I have a problem in Prisma data modeling where I have to constrain that a user can submit only one review for a product. I have following design for the non-constrained situation.
Should
Customer
andProduct
be combined into a primary key inProductReview
model, or should this constraint be imposed at the application server level, and not at the database level?
Datamodel for now (non-constrained version):
type Product {
id: ID! @unique
title: String!
reviews: [ProductReview!]! @relation(name: "ProductReviews", onDelete: CASCADE)
}
type Customer {
id: ID! @unique
email: String @unique
}
type ProductReview {
id: ID! @unique
forProduct: Product! @relation(name: "ProductReviews", onDelete: SET_NULL)
byCustomer: Customer!
review: String!
ratinng: Float!
}
It looks like Prisma v2 introduced composite primary keys:
https://newreleases.io/project/github/prisma/prisma/release/2.0.0-preview023
An example from that link:
model User {
firstName String
lastName String
email String
@@id([firstName, lastName])
}
So in the given question example, it should be possible to add to ProductReview
:
@@id([id, forProduct])
I have to constrain that a user can submit only one review for a product. I have following design for the non-constrained situation.
Unfortunately, this is currently not possible with Prisma. There already is an open feature request asking for this functionality, please leave your 👍 on the issue!
To get that functionality in your application, you'll need to implement that constraint manually on the application layer (e.g. express, apollo-server or graphql-yoga).
You can take a look at this page of How to GraphQL where there's a similar situation with the User
, Link
and Vote
types. Here's how the resolver to create a Vote
and ensurs no votes from that user already exist is implemented with graphql-yoga:
async function vote(parent, args, context, info) {
// 1
const userId = getUserId(context)
// 2
const linkExists = await context.db.exists.Vote({
user: { id: userId },
link: { id: args.linkId },
})
if (linkExists) {
throw new Error(`Already voted for link: ${args.linkId}`)
}
// 3
return context.db.mutation.createVote(
{
data: {
user: { connect: { id: userId } },
link: { connect: { id: args.linkId } },
},
},
info,
)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With