#prisma
#middleware
#updatemany
#deletemany
Tue Aug 02 2022
This is not a story about a bug but rather a feature!
Have you ever used table.updateMany
or table.deleteMany
in your code? we have and it was something like this:
const deleteChildrenOfThatParent = await prisma.children.deleteMany({ where: { parentEmail: { equal: parent.email, }, }, })
It was working great for a long time and you know what, we had TS checking the types too but somehow someday we lost all of our children data in the table. We checked the database (Postgres) and we found out that at a certain time, all of the data has been wiped out! We blamed DevOps, hackers, AWS, ... but it was us not anyone else.
Finally, we figured out that we might have a situation where parent.email
was undefined
. But still, we couldn't believe that deleteMany
with a condition executed that. After some testing, we were shocked but that was true and actually, it made sense... our "where" clause made the code in a way that we deleted all the children only because of that undefined
. we basically ran:
const deleteChildrenOfThatParent = await prisma.children.deleteMany({ where: {}, }, })
What could have saved us though?
So we had a retro around it and there were some angry stakeholders there! We promised them that this would never happen again! first thing first we just found every updateMany
and deleteMany
function and we bookmarked them. We could just put a condition before each one to check for undefined but this wasn't a permanent solution or scalable one.
After some investigation, we found a great solution, yeah Prisma itself came to help :p
So what we needed to implement was something in the lower layer on the Prisma which could check all the mutations to make sure we're not removing data that we don't want to delete. Prisma Middleware is that thing YES!
we just implemented the middleware in a way that we check every query (mutations) and filter out the updateMany
and deleteMany
ones and make sure that there is a condition on them!
async function main() { prisma.$use(async (params, next) => { // Check incoming query type if (params.model === 'Post') { if (params.action === 'deleteMany' || params.action === 'updateMany') { //Check the Where clause in params.arg.where, if it's empty just return } } return next(params) })
© Copyright 2022 Farmin Farzin