I’m using PlanetScale to host my database and Fastify with Prisma to build a simple API.
I read the documentation about the things to consider, most notably the missing support of foreign keys.
I followed the guide to create indexes on foreign keys and also the guide to create explicit many-to-many relations but then I can’t use anymore all the cool features of Prisma.
I currently have the following schema:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DB_URL")
relationMode = "prisma"
}
model Owner {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(255)
pets Pet[]
createdBy String @db.VarChar(255)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Pet {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(255)
owners Owner[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
After the explicit many-to-many relation is introduced, here is the schema:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DB_URL")
relationMode = "prisma"
}
model Owner {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(255)
pets OwnersOfPets[]
createdBy String @db.VarChar(255)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Pet {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(255)
owners OwnersOfPets[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model OwnersOfPets {
pet Pet @relation(fields: [petId], references: [id])
petId Int
owner Owner @relation(fields: [ownerId], references: [id])
ownerId Int
@@id([petId, ownerId])
@@index([petId])
@@index([ownerId])
}
For reference, here is the generated OwnersOfPetsWhereUniqueInput
type:
export type OwnersOfPetsWhereUniqueInput = Prisma.AtLeast<{
ownerId_petId?: OwnersOfPetsOwnerIdPetIdCompoundUniqueInput
AND?: OwnersOfPetsWhereInput | OwnersOfPetsWhereInput[]
OR?: OwnersOfPetsWhereInput[]
NOT?: OwnersOfPetsWhereInput | OwnersOfPetsWhereInput[]
ownerId?: IntFilter<"OwnersOfPets"> | number
petId?: IntFilter<"OwnersOfPets"> | number
owner?: XOR<OwnerRelationFilter, OwnerWhereInput>
pet?: XOR<PetRelationFilter, PetWhereInput>
}, "ownerId_petId">
The issue is that I have some pretty simple existing code to connect owners to pets which is now broken as I need to transform several things to a new much more complicated syntax:
const pet = await request.server.prisma.pet.findUnique({
where: { id },
// Before schema change
// include: { owners: true },
// After schema change
include: { owners: { include: { owner: true } } },
})
// Some more code
await request.server.prisma.pet.update({
where: { id },
data: {
// Some new data
...omit(request.body, 'owners'),
owners: {
// Before schema change
// connect: [{ name: 'Henry' }, { name: 'James' }],
// After schema change
connect: [
{ petId_ownerId: { petId: id, ownerId: 1 } },
{ petId_ownerId: { petId: id, ownerId: 2 } },
],
},
},
})
As you can see, the code is much more complicated with a very simple use case… Plus, I can’t use the unique name
field of Owners to connect to the Pet.
Also, the connectOrCreate
feature is inherently broken with the introduction of the explicit many-to-many relation table, because it requires to provide both a petId
and ownerId
, which I obviously don’t have yet in the create
case.
Am I doing something wrong ? Is it expected that I don’t get the same DX as with implicit many-to-many relations ?
This question has been answered in a Github discussion: