diff --git a/packages/prisma/extensions/disallow-undefined-delete-update-many.test.ts b/packages/prisma/extensions/disallow-undefined-delete-update-many.test.ts new file mode 100644 index 0000000000..a7b07968f7 --- /dev/null +++ b/packages/prisma/extensions/disallow-undefined-delete-update-many.test.ts @@ -0,0 +1,38 @@ +import { describe, it, expect } from "vitest"; + +import { checkUndefinedInValue } from "./disallow-undefined-delete-update-many"; + +describe("Disallow undefined delete/update many", () => { + it("checkUndefinedInValue should throw exception when the 'in' field of where object is undefined", async () => { + const where = { + id: { + in: undefined, + }, + }; + + expect(() => checkUndefinedInValue(where)).toThrowError( + 'The "in" value for the field "id" cannot be undefined.' + ); + }); + + it("checkUndefinedInValue should throw exception when a field of where object is undefined", async () => { + const where = { + from: undefined, + }; + + expect(() => checkUndefinedInValue(where)).toThrowError( + 'The value for the field "from" cannot be undefined.' + ); + }); + + it("checkUndefinedInValue should not throw exception when the where object does not contain undefined values", async () => { + const where = { + id: { + in: [1, 2, 3], + }, + name: "test name", + }; + + checkUndefinedInValue(where); + }); +}); diff --git a/packages/prisma/extensions/disallow-undefined-delete-update-many.ts b/packages/prisma/extensions/disallow-undefined-delete-update-many.ts new file mode 100644 index 0000000000..441de4901d --- /dev/null +++ b/packages/prisma/extensions/disallow-undefined-delete-update-many.ts @@ -0,0 +1,38 @@ +import { Prisma } from "@prisma/client"; + +export const checkUndefinedInValue = (where: any) => { + if (where) { + for (const key in where) { + // INFO: Since this is for $allModels, we don't have a way to get the correct + // where type + const whereInput = where[key as any] as any; + let message; + if (whereInput === undefined) { + message = `The value for the field "${key}" cannot be undefined.`; + throw new Error(message); + } + + if (whereInput.hasOwnProperty("in") && typeof whereInput.in === "undefined") { + message = `The "in" value for the field "${key}" cannot be undefined.`; + throw new Error(message); + } + } + } +}; + +export function disallowUndefinedDeleteUpdateManyExtension() { + return Prisma.defineExtension({ + query: { + $allModels: { + async deleteMany({ args, query }) { + checkUndefinedInValue(args.where); + return query(args); + }, + async updateMany({ args, query }) { + checkUndefinedInValue(args.where); + return query(args); + }, + }, + }, + }); +} diff --git a/packages/prisma/index.ts b/packages/prisma/index.ts index d4dd9c8b19..35214516b4 100644 --- a/packages/prisma/index.ts +++ b/packages/prisma/index.ts @@ -3,6 +3,7 @@ import { PrismaClient as PrismaClientWithoutExtension } from "@prisma/client"; import { withAccelerate } from "@prisma/extension-accelerate"; import { bookingIdempotencyKeyExtension } from "./extensions/booking-idempotency-key"; +import { disallowUndefinedDeleteUpdateManyExtension } from "./extensions/disallow-undefined-delete-update-many"; import { excludePendingPaymentsExtension } from "./extensions/exclude-pending-payment-teams"; import { usageTrackingExtention } from "./extensions/usage-tracking"; import { bookingReferenceMiddleware } from "./middleware"; @@ -25,6 +26,7 @@ export const customPrisma = (options?: Prisma.PrismaClientOptions) => .$extends(usageTrackingExtention()) .$extends(excludePendingPaymentsExtension()) .$extends(bookingIdempotencyKeyExtension()) + .$extends(disallowUndefinedDeleteUpdateManyExtension()) .$extends(withAccelerate()); // If any changed on middleware server restart is required @@ -37,6 +39,7 @@ const prismaWithClientExtensions = prismaWithoutClientExtensions .$extends(usageTrackingExtention()) .$extends(excludePendingPaymentsExtension()) .$extends(bookingIdempotencyKeyExtension()) + .$extends(disallowUndefinedDeleteUpdateManyExtension()) .$extends(withAccelerate()); export const prisma = globalForPrisma.prismaWithClientExtensions || prismaWithClientExtensions;