Deal with foreign keys - scala

I found a way of defining a primary key in Play:
case class User(id: Pk[Long], name: String)
But I didn't find any way to deal with foreign keys. Is there any one or do I have to use it as a normal field?

You can treat it as a normal field.
By the way you can check sample Play! framework applications. You can find them within the Play! distribution in folder "samples". For example, check computer-database project. There are foreign keys in database, but in the code they are treated like a normal fields.
Evolution:
create table company (
id bigint not null,
name varchar(255) not null,
constraint pk_company primary key (id))
;
create table computer (
id bigint not null,
name varchar(255) not null,
introduced timestamp,
discontinued timestamp,
company_id bigint,
constraint pk_computer primary key (id))
;
alter table computer add constraint fk_computer_company_1 foreign key (company_id) references company (id) on delete restrict on update restrict;
Code:
case class Computer(id: Pk[Long] = NotAssigned, name: String, introduced: Option[Date], discontinued: Option[Date], companyId: Option[Long])

Related

Diesel migration force String instead of Uuid in schema.rs

I have a problem with the diesel migration. I need to implement Uuid as primary key for a model. I got a lot of issues with the Uuid integration (feature uuidv07, uuid crate,..) but when I specify the type uuid in the migration, diesel generate a "Varchar" field in the migration, so I can't use Uuid as a type of field in my model.
users.sql
CREATE TABLE users (
id UUID PRIMARY KEY,
email VARCHAR NOT NULL,
name VARCHAR NOT NULL,
password VARCHAR NOT NULL,
id_role INT,
CONSTRAINT fk_role
FOREIGN KEY(id_role)
REFERENCES roles(id)
)
schema.rs
table! {
users (id) {
id -> Varchar,
email -> Varchar,
name -> Varchar,
password -> Varchar,
id_role -> Nullable<Int4>,
}
}
Is this normal to use Varchar and not Uuid ?
uuid = { version = "0.8.2", features = ["serde", "v4"] }
diesel = { version = "1.4.5", features = ["postgres", "r2d2", "uuidv07"] }
Thanks.
Diesel does not force anything onto you. It just reads the types from your database system. So if it outputs a Varchar as type for a specific column that means your database system recorded Varchar (for whatever reason) as type for this column. Or to word it differently: The problem here is not diesel, but likely an interaction between your migration, your existing database schema and your database. As neither information about your pre-existing database schema nor about your database system is provided as part of your question there is not much I can add here to point you into the right direction.

MIGRATION FAILED ENUM TYPE ALREADY EXISTS ERROR

I'm building a microservices app using Spring Boot + Postgres + Flyway,
within flight-archive microservice, I created a script sql that contains the following code:
CREATE TYPE Payment_method AS ENUM ('CASH', 'PAYPAL', 'CREDIT CARD');
CREATE TABLE IF NOT EXISTS flight_booking_archive (
booking_Id INT NOT NULL PRIMARY KEY,
flight_Id INT NOT NULL,
passenger_Id INT NOT NULL,
adults INT NOT NULL,
babies INT NOT NULL,
amount_paid MONEY,
payment_method Payment_method,
booked DATE DEFAULT CURRENT_DATE,
CONSTRAINT fk_flight_id FOREIGN KEY (flight_Id) references flight(flight_ID),
CONSTRAINT fk_passenger_id FOREIGN KEY (passenger_Id) references passenger(passenger_ID)
)
then, when I run flight-archive microservice using maven, I got the following error
SQL State : 42710
Error Code : 0
Message : ERROR: type "payment_method" already exists
Location : db/migration/V1__flight_archive_table.sql (C:\Users\OMAYMA\flight-app-
demo\server\flight-booking-
archive\target\classes\db\migration\V1__flight_archive_table.sql)
Line : 1
Statement : CREATE TYPE Payment_method AS ENUM ('CASH', 'PAYPAL', 'CREDIT CARD')
In Postgres if you want to use uppercase you have to use quotation marks, otherwise, the words will always be in lowercase.
Try making this change:
CREATE TYPE "Payment_method" AS ENUM ('CASH', 'PAYPAL', 'CREDIT CARD');
CREATE TABLE IF NOT EXISTS flight_booking_archive (
booking_Id INT NOT NULL PRIMARY KEY,
flight_Id INT NOT NULL,
passenger_Id INT NOT NULL,
adults INT NOT NULL,
babies INT NOT NULL,
amount_paid MONEY,
payment_method "Payment_method",
booked DATE DEFAULT CURRENT_DATE,
CONSTRAINT fk_flight_id FOREIGN KEY (flight_Id) references flight(flight_ID),
CONSTRAINT fk_passenger_id FOREIGN KEY (passenger_Id) references passenger(passenger_ID)

Foreign Key could not be found with SqlAlchemy and PostgreSQL

I just started a Flask - SqlAlchemy project and am having some trouble with Foreign Keys.
I have the tables User and Portfolio. Portfolio has a foreign key to user, using username. I set up my model like this.
class User(db.Model):
__tablename__ = 'portfolio_users'
__table_args__ = {"schema":"keldan"}
username = Column(String(), primary_key=True)
date_added = Column(DateTime())
class Portfolio(db.Model):
__tablename__ = 'portfolios'
__table_args__ = {"schema":"keldan"}
id = Column('pid', Integer(), Sequence('portfolios_pid_seq'), primary_key=True)
date_added = Column(DateTime())
name = Column(String())
username = Column(String(), ForeignKey('portfolio_users.username'))
user = relationship('User', backref=backref('portfolios', cascade='save-update, merge, delete, delete-orphan'))
The error I get when I try to run a simple select all query is:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'portfolios.username' could not find table 'portfolio_users' with which to generate a foreign key to target column 'username'
The tables are created like this:
CREATE TABLE keldan.portfolio_users
(
username text NOT NULL,
date_added date NOT NULL,
CONSTRAINT users_pk PRIMARY KEY (username)
)
WITH (
OIDS=FALSE
);
CREATE TABLE keldan.portfolios
(
pid serial NOT NULL,
username text NOT NULL,
date_added date NOT NULL,
name text NOT NULL,
CONSTRAINT portfolios_pk PRIMARY KEY (pid),
CONSTRAINT portfolios_fk FOREIGN KEY (username)
REFERENCES keldan.portfolio_users (username) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
OIDS=FALSE
);
I have spent the better part of a day trying to figure this out or making workarounds using primaryjoin but nothing seems to work.
I finally found the answer I was looking for here
If you are not using the default schema (public) then it's not enough to specify the schema for each class, but I need to specify it in the foreign key as well.
username = Column(String(), ForeignKey('keldan.portfolio_users.username'))

Using Automapper with F# Entity Type Provider

I am looking at Automapper for the first time using F# and the Entity Type Provider. I want to map between the EF Type Provider types and the F# record types that I have created.
The EF Type Provider is based on the following database schema:
CREATE TABLE [dbo].[Address](
[Id] [int] IDENTITY(1,1) NOT NULL,
[FamilyId] [int] NOT NULL,
[State] [varchar](50) NOT NULL,
[County] [varchar](50) NOT NULL,
[City] [varchar](50) NOT NULL,
CONSTRAINT [PK_Address] PRIMARY KEY CLUSTERED ([Id] ASC)
CREATE TABLE [dbo].[Child](
[Id] [int] IDENTITY(1,1) NOT NULL,
[FamilyId] [int] NOT NULL,
[FirstName] [varchar](50) NOT NULL,
[Gender] [varchar](50) NOT NULL,
[Grade] [int] NOT NULL,
CONSTRAINT [PK_Child] PRIMARY KEY CLUSTERED ([Id] ASC)
CREATE TABLE [dbo].[Family](
[Id] [int] IDENTITY(1,1) NOT NULL,
[LastName] [varchar](50) NOT NULL,
[IsRegistered] [bit] NOT NULL,
CONSTRAINT [PK_Family] PRIMARY KEY CLUSTERED ([Id] ASC)
CREATE TABLE [dbo].[Parent](
[Id] [int] IDENTITY(1,1) NOT NULL,
[FamilyId] [int] NOT NULL,
[FirstName] [varchar](50) NOT NULL,
CONSTRAINT [PK_Parent] PRIMARY KEY CLUSTERED ([Id] ASC)
CREATE TABLE [dbo].[Pet](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ChildId] [int] NOT NULL,
[GivenName] [varchar](50) NOT NULL,
CONSTRAINT [PK_Pet] PRIMARY KEY CLUSTERED ([Id] ASC)
ALTER TABLE [dbo].[Address] WITH CHECK ADD CONSTRAINT [FK_Address_Family] FOREIGN KEY([FamilyId])
REFERENCES [dbo].[Family] ([Id])
ALTER TABLE [dbo].[Address] CHECK CONSTRAINT [FK_Address_Family]
ALTER TABLE [dbo].[Child] WITH CHECK ADD CONSTRAINT [FK_Child_Family] FOREIGN KEY([FamilyId])
REFERENCES [dbo].[Family] ([Id])
ALTER TABLE [dbo].[Child] CHECK CONSTRAINT [FK_Child_Family]
ALTER TABLE [dbo].[Parent] WITH CHECK ADD CONSTRAINT [FK_Parent_Family] FOREIGN KEY([FamilyId])
REFERENCES [dbo].[Family] ([Id])
ALTER TABLE [dbo].[Parent] CHECK CONSTRAINT [FK_Parent_Family]
ALTER TABLE [dbo].[Pet] WITH CHECK ADD CONSTRAINT [FK_Pet_Child] FOREIGN KEY([ChildId])
REFERENCES [dbo].[Child] ([Id])
ALTER TABLE [dbo].[Pet] CHECK CONSTRAINT [FK_Pet_Child]
I then created a comparable set of types in F#:
type Pet = {Id:int; GivenName:string}
type Child = {Id:int; FirstName:string; Gender:string; Grade:int; Pets: Pet list}
type Address = {Id:int; State:string; County:string; City:string}
type Parent = {Id:int; FirstName:string}
type Family = {Id:int; Parents:Parent list; Children: Child list; Address:Address}
The only real difference is that the foreign key is not explicit in the record types.
When I use Automapper on the Address type, it works as expected:
Mapper.CreateMap<EntityConnection.ServiceTypes.Address, Address>()
let context = EntityConnection.GetDataContext()
let addressQuery = query {for address in context.Addresses do select address}
let address = Seq.head addressQuery
let address' = Mapper.Map<Address>(address)
val address' : Address = {Id = 1;
State = "WA";
County = "King";
City = "Seattle";}
But when I try and do the same with the entire graph,
Mapper.CreateMap<EntityConnection.ServiceTypes.Pet, Pet>()
Mapper.CreateMap<EntityConnection.ServiceTypes.Child, Child>()
Mapper.CreateMap<EntityConnection.ServiceTypes.Address, Address>()
Mapper.CreateMap<EntityConnection.ServiceTypes.Parent, Parent>()
Mapper.CreateMap<EntityConnection.ServiceTypes.Family, Family>()
let context = EntityConnection.GetDataContext()
let familyQuery = query {for family in context.Families do select family}
let family = Seq.head familyQuery
let family' = Mapper.Map<Family>(family)
I get this exception:
System.ArgumentException: Type needs to have a constructor with 0 args or only optional args
Parameter name: type
I am wondering if it is b/c EF is lazy loading so the remaining types are not being evaluated? has anyone seen this before?
The error is pretty straight forward. None of your classes have a constructor that takes 0 arguments.
F# creates default constructors for you so the default constructor on your class has multiple arguments in it. For example:
type Pet = {Id:int; GivenName:string}
as a c# class would have this as it's definition.
public class Pet
{
public int Id { get; private set; }
public string GivenName { get; private set; }
public Pet(int id, string givenName)
{
Id = id;
GivenName = givenName;
}
}
Note the lack of a parameterless constructor. That's where your error is coming from.
You can fix it by flagging your type as CLIMutable
[<CLIMutable>]
type Pet = {Id:int; GivenName:string}

"Can't adapt type" error on a Foreign key attribute with SQLAlchemy/PostGreSQL

I got a problem with PostGreSQL 8.4 and tables reflection. My metadata object seems to be ok (it has foreign keys, primary keys, every columns and tables). But when I try to associate an object to an another one through a Foreign key, I get : "sqlalchemy.exc.ProgrammingError: (ProgrammingError) can't adapt type 'EventParameters' 'INSERT INTO event (".
I'm using SQLAlchemy 0.6.3 (psycopg2 2.2.1) and PostGreSQL 8.4.5
Here, my code :
#! /usr/bin/env python
from sqlalchemy import MetaData, create_engine
from sqlalchemy.orm import mapper, sessionmaker
class EventParameters(object):
pass
class Event(object):
pass
engine = create_engine('postgresql://postgres:toto#127.0.0.1:5432/renass')
metadata = MetaData()
metadata.reflect(bind=engine)
Session = sessionmaker(bind=engine)
session = Session()
mapper(EventParameters, metadata.tables['eventparameters'])
mapper(Event, metadata.tables['event'])
ep = EventParameters()
ep.publicid = 'test'
e = Event()
e.publicid = 'test'
e.eventparametersid=ep
session.add(e)
session.commit()
and my database :
CREATE TABLE EventParameters (
id SERIAL PRIMARY KEY,
publicID varchar(255) UNIQUE NOT NULL,
description varchar(255),
creationInfo_agencyID varchar(64),
creationInfo_agencyURI varchar(255),
creationInfo_author varchar(128),
creationInfo_authorURI varchar(255),
creationInfo_creationTime time,
creationInfo_version varchar(64)
);
CREATE TABLE Event (
id SERIAL PRIMARY KEY,
eventParametersID integer NOT NULL REFERENCES EventParameters(id),
publicID varchar(255) UNIQUE NOT NULL,
preferredOriginID integer,
preferredMagnitudeID integer,
preferredFocalMechanismID integer,
type EventType,
typeCertainty EventTypeCertainty,
creationInfo_agencyID varchar(64),
creationInfo_agencyURI varchar(255),
creationInfo_author varchar(128),
creationInfo_authorURI varchar(255),
creationInfo_creationTime time,
creationInfo_version varchar(64)
);
It seems that SQLAlchemy don't recognize the attribute "eventparametersid" as a relationship ...
Thank you in advance
Fabien
To make your code working you should change the mapper invocation for the Event class to include the mapping between the two classes
mapper(Event, metadata.tables['event'], properties={
'eventparameters': relation(EventParameters)
})
then use that column to assign the EventParameters instance
ep = EventParameters()
ep.publicid = 'test'
e = Event()
e.publicid = 'test'
e.eventparameters = ep