Exercise 2: Handling Duplicate Slugs — Possible Solution ========================================================== // src/posts.ts import { Prisma, type PrismaClient } from "../generated/prisma/client"; export async function createPost( db: PrismaClient, input: { title: string; content: string; authorId: number }, ) { if (input.title.trim().length < 3) throw new Error("Title too short"); const base = slugify(input.title); for (let n = 1; n <= 20; n++) { const slug = n === 1 ? base : `${base}-${n}`; try { return await db.post.create({ data: { ...input, slug, published: false } }); } catch (e) { const duplicate = e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2002"; if (!duplicate) throw e; // any other error is a real problem } } throw new Error("Could not find a free slug"); } // test/posts.int.test.ts it("gives a repeated title a numbered slug", async () => { const author = await prisma.user.create({ data: { email: "a@test.local", name: "A" } }); const input = { title: "Hello World", content: "...", authorId: author.id }; const first = await createPost(prisma, input); const second = await createPost(prisma, input); const third = await createPost(prisma, input); expect([first.slug, second.slug, third.slug]) .toEqual(["hello-world", "hello-world-2", "hello-world-3"]); }); Why the mocked test still passes on the unfixed version: The chapter's mock test configures db.post.create to always succeed, and only checks that it was called with slug "hello-world". The mock has no unique index and no memory of earlier calls, so calling it twice with the same slug succeeds both times. The bug only exists because of the real @unique constraint, which only a real database enforces. WHY THIS WORKS AS AN ANSWER ------------------------------ It relies on the database's own constraint instead of checking with findUnique first. A "check, then create" approach has a race: two requests could both see the slug as free and both try to create it. Trying the insert and catching P2002 is safe under concurrency. The loop is capped so a bug can never spin forever, and non-duplicate errors are re-thrown rather than swallowed.