fix(prisma-adapter): route insensitive id increments through the lookup path

This commit is contained in:
Gustavo Valverde
2026-10-15 12:09:11 +01:00
parent 37ae122bce
commit 5bf2a71c9e
2 changed files with 43 additions and 1 deletions
@@ -607,6 +607,41 @@ describe("prisma-adapter", () => {
});
});
it("incrementOne resolves an insensitive id before the keyed update", async () => {
const update = vi.fn().mockResolvedValue({ id: "row-1", remaining: 4 });
const txClient = {
verification: {
findFirst: vi.fn().mockResolvedValue({ id: "row-1" }),
update,
},
};
const adapter = prismaAdapter(
{
$transaction: vi.fn(async (cb) => cb(txClient)),
verification: {},
} as never,
{ provider: "postgresql" },
)({
verification: {
additionalFields: { remaining: { type: "number" } },
},
} as BetterAuthOptions);
await adapter.incrementOne({
model: "verification",
where: [{ field: "id", value: "row-1", mode: "insensitive" }],
increment: { remaining: -1 },
});
expect(update).toHaveBeenCalledWith({
where: {
id: "row-1",
AND: [{ id: { equals: "row-1", mode: "insensitive" } }],
},
data: { remaining: { increment: -1 } },
});
});
it("update keeps an insensitive predicate next to a unique key", async () => {
const update = vi.fn().mockResolvedValue({ id: "user-id" });
const adapter = prismaAdapter(
@@ -746,7 +746,14 @@ export const prismaAdapter = (prisma: PrismaClient, config: PrismaConfig) => {
// transaction and update by id. Either way the original guard stays in
// the where, so a racer that invalidated it (e.g. remaining dropped to
// 0) yields P2025 and we report no mutation.
const hasIdField = where?.some((w) => w.field === "id");
// Only a case-sensitive AND eq on id can stay a flat key for update().
const hasIdField = where?.some(
(w) =>
w.field === "id" &&
(w.operator === "eq" || !w.operator) &&
w.connector !== "OR" &&
!isInsensitiveForPrisma(w),
);
if (hasIdField) {
const whereClause = convertWhereClause({
model: modelKey,