|
1 | 1 | import {Prisma} from "@prisma/client" |
| 2 | +import {DriverAdapterError, isDriverAdapterError} from "@prisma/driver-adapter-utils" |
| 3 | + |
| 4 | +// Reference for error structure https://github.com/prisma/prisma/blob/7.2.0/packages/driver-adapter-utils/src/types.ts |
| 5 | +// |
| 6 | +// The cause of the DriverAdapterError is a discriminated union of types that can be narrowed down |
| 7 | +// to extract the specific error details. |
| 8 | + |
| 9 | +/** |
| 10 | + * Helper to safely extract driver-specific details from the adapter error. |
| 11 | + */ |
| 12 | +function getDriverAdapterError(error: Prisma.PrismaClientKnownRequestError): DriverAdapterError | undefined { |
| 13 | + const adapterError = error.meta?.driverAdapterError |
| 14 | + if (adapterError && isDriverAdapterError(adapterError)) return adapterError |
| 15 | + return undefined |
| 16 | +} |
2 | 17 |
|
3 | 18 | export function isPrismaUniqueConstraintError(error: unknown, fields: string[]): boolean { |
4 | | - const uniqueFields = new Set(fields) |
| 19 | + if (!(error instanceof Prisma.PrismaClientKnownRequestError) || error.code !== "P2002") return false |
| 20 | + |
| 21 | + const adapterError = getDriverAdapterError(error) |
| 22 | + if (!adapterError) return false |
5 | 23 |
|
6 | | - if (uniqueFields.size !== fields.length) throw new Error("Fields array contains duplicates") |
7 | | - if (!(error instanceof Prisma.PrismaClientKnownRequestError)) return false |
8 | | - if (error.code !== "P2002" || !Array.isArray(error.meta?.target)) return false |
| 24 | + const cause = adapterError.cause |
| 25 | + if (cause.kind !== "UniqueConstraintViolation") return false |
9 | 26 |
|
10 | | - const violatedFields = error.meta.target as string[] |
| 27 | + const violatedFields = cause.constraint && "fields" in cause.constraint ? cause.constraint.fields : [] |
11 | 28 | return fields.length === violatedFields.length && fields.every(field => violatedFields.includes(field)) |
12 | 29 | } |
13 | 30 |
|
14 | | -export function isPrismaForeignKeyConstraintError(error: unknown, constraint: string): boolean { |
15 | | - if (!(error instanceof Prisma.PrismaClientKnownRequestError)) return false |
16 | | - if (error.code !== "P2003" || !error.meta?.constraint) return false |
| 31 | +export function isPrismaForeignKeyConstraintError(error: unknown, constraintName: string): boolean { |
| 32 | + if (!(error instanceof Prisma.PrismaClientKnownRequestError) || error.code !== "P2003") return false |
17 | 33 |
|
18 | | - const violatedField = error.meta.constraint as string |
19 | | - return constraint === violatedField |
20 | | -} |
| 34 | + const adapterError = getDriverAdapterError(error) |
| 35 | + if (!adapterError) return false |
21 | 36 |
|
22 | | -export function isPrismaRecordNotFoundError(error: unknown, modelName: Prisma.ModelName): boolean { |
23 | | - if (!(error instanceof Prisma.PrismaClientKnownRequestError)) return false |
24 | | - if (error.code !== "P2025" || !error.meta?.modelName) return false |
| 37 | + const cause = adapterError.cause |
| 38 | + if (cause.kind !== "ForeignKeyConstraintViolation") return false |
25 | 39 |
|
26 | | - const violatedModel = error.meta.modelName as string |
27 | | - return modelName === violatedModel |
| 40 | + return cause.constraint !== undefined && "index" in cause.constraint && cause.constraint.index === constraintName |
28 | 41 | } |
29 | 42 |
|
30 | | -export function isPrismaCheckConstraintError(error: unknown, constraint: string): boolean { |
31 | | - if (!(error instanceof Prisma.PrismaClientKnownRequestError)) return false |
32 | | - if (error.code !== "P2004" || !error.meta?.constraint) return false |
| 43 | +export function isPrismaRecordNotFoundError(error: unknown, modelName: Prisma.ModelName): boolean { |
| 44 | + if (!(error instanceof Prisma.PrismaClientKnownRequestError) || error.code !== "P2025") return false |
| 45 | + |
| 46 | + /** |
| 47 | + * P2025 "Record not found" is slightly different. Usually, the DB doesn't throw |
| 48 | + * an error for a missing record (it just returns 0 rows), so Prisma's engine |
| 49 | + * generates this error. |
| 50 | + * |
| 51 | + * Based on your captured debug log, 'modelName' is at the root of 'meta'. |
| 52 | + */ |
| 53 | + const violatedModel = error.meta?.modelName as string | undefined |
33 | 54 |
|
34 | | - const violatedConstraint = error.meta.constraint as string |
35 | | - return constraint === violatedConstraint |
| 55 | + return modelName === violatedModel |
36 | 56 | } |
0 commit comments