Support afterCreate/afterUpdate database triggers
CDDelta opened this issue · comments
Problem
The Prisma client offers a way to modify inbound queries and updates to the database through middleware but offers no way to trigger actions based on the full result of a create/update operation.
For example, say I want to create a Post
model with a default id that's generated by the database and a corresponding PostRevsion
model for the creation and every update to the Post
. There's no way for one to use middleware to create a PostRevision
and reference back to the Post
because the middleware has no access to the final database generated data. It is a similar case with updates which might only partially update the contents of Post
meaning the middleware has no access to the complete Post
to create a revision of.
Suggested solution
Copied from #653:
Prisma Client should have a way to define functions before and after crud operations. Here is an example that I thought of which would be pretty common. The Sequelize link I posted above also has plenty of examples and concepts, basically an instruction guide on what to include.
prisma = new PrismaClient();
prisma.setTriggers(prisma => ({
beforeOrderCreate: async (args: OrderCreateArgs): Promise<OrderCreateArgs> => {
const grandTotal = calcGrandTotal(args.data.lineItems.create);
// Error can be thrown here
await processPayment(grandTotal, args.data.user.connect.id);
return {
...args,
{
data: {
...args.data,
grandTotal
}
}
})
afterOrderCreate: async (order: Order): Promise<void> => {
const user = await prisma.order.findOne({ where: { id: order.id } }).user();
if (user.acceptsEmail) {
await sendEmailToCustomer(order.id, order.grandTotal, user.name);
}
},
afterOrderUpdate: async (newOrder: Order, oldOrder: Order): Promise<void> => {
if (newOrder.grandTotal !== oldOrder.grandTotal) {
await prisma.creditNote.create({
data: {
amount: newOrder.grandTotal - oldOrder.grandTotal,
order: { connect: { id: newOrder.id }
}
}
}
}
}))
From me:
This feature would be even more powerful if coupled with long-running transactions but it's perhaps already too complex.
Alternatives
Alternatively, providing a way to define these triggers within schema.prisma
would be sufficient for my use case while also providing the transactional guarantees required.
Additional context
Ok, I've had a look at Prisma Migrate and the migration workflow and generated SQL it provides seems to work for the alternative I outlined. I'll close this issue once I've explored it further. :)
I've managed to workaround this issue by creating database triggers using SQL. Closing.