Reuse same model for two fields in Prisma - prisma

My goal is for this:
I have a table of professions. A person can have two professions - a primary and secondary profession.
model Person {
id String #id #default(cuid())
PrimaryProfessionId String?
Secondary String?
PrimaryProfession Profession #relation(fields: [PrimaryProfessionId], references: [id])
SecondaryProfession Profession #relation(fields: [SecondaryProfessionId], references: [id], name: "secondaryProfession")
}
model Profession {
id String #id #default(cuid())
name String
Primary Person?
Secondary Person? #relation("secondaryProfession")
}
Trying to copy this: Prisma - How to point two fields to same model? but it doesnt work.
With current code I am getting error: Error parsing attribute "#relation": A one-to-one relation must use unique fields on the defining side.
What should I fix to make this work?

Related

Prisma model typing issue - expected non-nullable type "String", found incompatible value of "null"

Problem
I am using Prisma as an ORM for a psql database. When I try to delete a row from a table (Plant) that my current table (Pod) references I get the error:
Error converting field "plantId" of expected non-nullable type "String", found incompatible value of "null".
My intention is, when the underlying Plant row is deleted, the reference or foreign_key on the Pod rows that reference it, are set to null. However, I can't seem to set it up correctly. I thought by typing it with plantId: String? it would be able to handle that since the ? set's the row to either <type>|null.
I could really use some help, I'm not sure where I'm going wrong.
// Plant
model Plant {
id Int #id #default(autoincrement())
plantId String #unique #default(uuid())
name String #unique
pods Pod[]
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
// Pod
model Pod {
id Int #id #default(autoincrement())
podId String #unique #default(uuid())
name String #db.VarChar(200)
hasAlert Boolean
plant Plant? #relation(fields: [plantId], references: [plantId], onDelete: SetNull)
plantId String?
batch Batch #relation(fields: [batchId], references: [batchId], onDelete: Cascade)
batchId String
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
Prisma Studio walk through:
Pod has a foreign key pointing to Plant (named broccoli)
In Plant table, I delete the referenced Plant (broccoli) that we saw in Pod
Upon returning to the Pod table, we get the following error:

enum in prisma instead of table

I have two tables in my Prisma db. One is for admins and the other is for users, and since they differ a lot from each other I decided not to create an isAdmin field. They have both in common the establishment that is described as a table (one-to-many relation), but it has only one field (name). I'd like to know whether it is a good idea to create an Enum to represent this field. My only doubt is that, since the values of the enums can change (adding more fields dynamically), it is not as good as creating a table
model Admin {
id String #id #default(uuid())
pin Int
establishment Establishment #relation(fields: [establishmentId], references: [id])
establishmentId Int
}
model User {
id String #id #default(uuid())
name String
balance Float #default(0)
establishment Establishment #relation(fields: [establishmentId], references: [id])
establishmentId Int
}
model Establishment {
id Int #id #default(autoincrement())
name String
}
This is how I've imagined the new data source to be like
model Admin {
id String #id #default(uuid())
pin Int
establishment Establishment
}
model User {
id String #id #default(uuid())
name String
balance Float #default(0)
establishment Establishment
}
enum Establishment {
ESTABLISHMENT1
ESTABLISHMENT2
}
If you are sure that you won't need to store any more fields for Establishment then the enums approach is good. But in case in future you are envisioning that there could be other common fields, then you would need to duplicate them in Users and Admins Table and Enums approach won't be a fit.
Another approach could be to use the check constraint on database level to only allow two valid values i.e. ESTABLISHMENT1 and ESTABLISHMENT2, this way you won't even need to define enums.

Relation two to many with Prisma

I'm trying to create a prisma schema with this kind of relation - I have two models: Player and Game. Every game is "played" by two players and I'm trying to connect them with something like this:
model Player {
id String #id #default(cuid())
name String
games Game[]
}
model Game {
id Int #id #default(autoincrement())
player_1 Player
player_2 Player
winnerId String
}
In this case I get an error which says Ambiguous relation detected. The fields player_1 and player_2 in model Game both refer to Player. Please provide different relation names for them by adding #relation(<name>).
And if I add relation with names which looks like this:
player_1 Player #relation(name: "GamePlayer1")
player_2 Player #relation(name: "GamePlayer2")
I get an error The relation field player_1/player_2 on Model Game is missing an opposite relation field on the model Player. I don't think that adding additional fields to Player model is necessary and also don't think that adding many to many relation which would look like this players: Player[] is smart.
What would be the right way to connect those two models based on my example?
You need to provide both player's id on Game and separate relation name on Player and Game. Here the right way to fix it:
model Player {
id String #id #default(cuid())
name String
games_player_1 Game[] #relation(name: "GamePlayer1")
games_player_2 Game[] #relation(name: "GamePlayer2")
}
model Game {
id Int #id #default(autoincrement())
player_1_id String
player_2_id String
player_1 Player #relation(name: "GamePlayer1", fields: [player_1_id], references: [id], onDelete: Cascade)
player_2 Player #relation(name: "GamePlayer2", fields: [player_2_id], references: [id], onDelete: Cascade)
winnerId String
}

How can I filter by a value inside a pivot table (using Prisma)?

I'm building a bike rental app where users can reserve bikes for a certain number of days. Bikes and users have a many-to-many relationship, there's a bike_user pivot table that contains the information about reservation start and end dates. See the diagram:
My schema looks kinda like this:
model User {
id String #id #default(cuid())
username String #unique
email String #unique
rented_bikes BikeUser[]
}
model Bike {
id String #id #default(cuid())
model String
color String
rented_by_users BikeUser[]
}
model BikeUser {
user User #relation(fields: [userId], references: [id])
userId String
bike Bike #relation(fields: [bikeId], references: [id])
bikeId String
reservation_start_date DateTime
reservation_end_date String
##id([userId, bikeId])
}
My goal is to take a range of dates, and filter the bikes, showing only the ones that haven't been reserved between these two dates.
Can you please help me figure out how to do this?

What is the best way to model a one-to-many relationship that also has a "selected" object in Prisma?

In our app, a user can be a member of many organizations. While viewing the site, they are generally viewing it through one of those organizations. This is the selected organization.
Is the following model the best way to model that? Is there a way to model it so you don't have to have the selectedBy and selectedById on the Membership and just have the selectedMembershipId on the User with a foreign key to the Membership?
model User {
id Int #id #default(autoincrement())
memberships Membership[] #relation("Memberships")
selectedMembership Membership? #relation("Selection")
}
model Membership {
id Int #id #default(autoincrement())
user User #relation("Memberships", fields: [userId], references: [id])
userId Int
selectedBy User? #relation("Selection", fields: [selectedById], references: [id])
selectedById Int? #unique
organization Organization #relation(fields: [orgId], references: [id])
orgId Int
role MemberRole
##unique([userId, orgId])
}
It's not possible to do precisely what you're hoping to. The syntax for relations in prisma calls for having a relation field (To the best of my understanding, that's what you would prefer not to have in your schema).
Since it's a one-to-one relation, if you prefer, you could do it the other way around, and have a selectedMembershipId foreign key on the User side and only have the selectedBy relation field on the Membership side like this:
model User {
id Int #id #default(autoincrement())
memberships Membership[] #relation("Memberships")
selectedMembership Membership? #relation("Selection", fields: [selectedMembershipId], references: [id])
selectedMembershipId Int? #unique
}
model Membership {
id Int #id #default(autoincrement())
user User #relation("Memberships", fields: [userId], references: [id])
userId Int
selectedBy User? #relation("Selection")
...
}
However, this is really a matter of preference regarding which side to keep the foreign key. In my opinion, the way you're handling your schema is the most reasonable way to model the relationship in Prisma.