All files / src/server/repositories pg-conflict.ts

100% Statements 10/10
87.5% Branches 7/8
100% Functions 1/1
100% Lines 7/7

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26                              38x 48x 48x 15x 5x   33x   23x    
// Is this error Postgres rejecting a specific unique index?
//
// MUST WALK `.cause`. drizzle 0.45 WRAPS the driver error: what it throws is a
// plain Error whose message is "Failed query: insert into ..." and whose `.cause`
// is the real PostgresError carrying `code` and `constraint_name`. Under 0.30 the
// PostgresError was thrown bare, so reading `error.code` worked — and every caller
// here did exactly that. The upgrade turned all five of them into `false`, which
// silently downgraded a gentle 409 ("you already have a sort in progress") into a
// 500, and turned two MAX+1 allocation retries into hard failures.
//
// So: match on `constraint_name` (exact, from the PostgresError) and fall back to
// the message, because the WRAPPER's message does not contain the constraint name
// — only the cause's does. src/lib/db-error-log.ts already reads `.cause.code` for
// the same reason; this is that lesson, applied where it changes behavior.
export function isUniqueViolation(error: unknown, constraint: string): boolean {
  for (let e: unknown = error, depth = 0; e && depth < 4; depth++) {
    const pg = e as { code?: string; constraint_name?: string; message?: string; cause?: unknown };
    if (pg.code === "23505") {
      if (pg.constraint_name) return pg.constraint_name === constraint;
      return (pg.message ?? "").includes(constraint);
    }
    e = pg.cause;
  }
  return false;
}