From 783f2606fac08473cf04b134c7e7f02887dfd657 Mon Sep 17 00:00:00 2001 From: hbjORbj Date: Wed, 13 Aug 2025 18:42:16 +0900 Subject: [PATCH 1/6] fix: unique constraint violation --- .../viewer/eventTypes/duplicate.handler.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts index f9f63577b284f2..3cf973ba3dd145 100644 --- a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts +++ b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts @@ -1,4 +1,5 @@ import { Prisma } from "@prisma/client"; +import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library"; import { generateHashedLink } from "@calcom/lib/generateHashedLink"; import { CalVideoSettingsRepository } from "@calcom/lib/server/repository/calVideoSettings"; @@ -165,7 +166,19 @@ export const duplicateHandler = async ({ ctx, input }: DuplicateOptions) => { } const eventTypeRepo = new EventTypeRepository(prisma); - const newEventType = await eventTypeRepo.create(data); + let newEventType; + try { + newEventType = await eventTypeRepo.create(data); + } catch (error: unknown) { + if (error instanceof PrismaClientKnownRequestError && error.code === "P2002") { + // unique constraint violation + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Unique constraint violation while creating a duplicate event.", + }); + } + throw error; + } // Create custom inputs if (customInputs) { From 1a4a80243c2a4a1d153df13109a1bdb9b47bbfd7 Mon Sep 17 00:00:00 2001 From: hbjORbj Date: Wed, 13 Aug 2025 18:56:35 +0900 Subject: [PATCH 2/6] refactor --- .../viewer/eventTypes/duplicate.handler.ts | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts index 3cf973ba3dd145..08169aae8e3965 100644 --- a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts +++ b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts @@ -166,19 +166,8 @@ export const duplicateHandler = async ({ ctx, input }: DuplicateOptions) => { } const eventTypeRepo = new EventTypeRepository(prisma); - let newEventType; - try { - newEventType = await eventTypeRepo.create(data); - } catch (error: unknown) { - if (error instanceof PrismaClientKnownRequestError && error.code === "P2002") { - // unique constraint violation - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Unique constraint violation while creating a duplicate event.", - }); - } - throw error; - } + + const newEventType = await eventTypeRepo.create(data); // Create custom inputs if (customInputs) { @@ -239,6 +228,13 @@ export const duplicateHandler = async ({ ctx, input }: DuplicateOptions) => { eventType: newEventType, }; } catch (error) { + if (error instanceof PrismaClientKnownRequestError && error.code === "P2002") { + // unique constraint violation + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Unique constraint violation while creating a duplicate event.", + }); + } throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: `Error duplicating event type ${error}` }); } }; From 0d402de39f676ac04b9a115892fd9331a60d449d Mon Sep 17 00:00:00 2001 From: hbjORbj Date: Wed, 13 Aug 2025 18:57:54 +0900 Subject: [PATCH 3/6] add test --- .../eventTypes/duplicate.handler.test.ts | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.test.ts diff --git a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.test.ts b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.test.ts new file mode 100644 index 00000000000000..7624fd37a71fca --- /dev/null +++ b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.test.ts @@ -0,0 +1,48 @@ +import prismaMock from "../../../../../../tests/libs/__mocks__/prismaMock"; + +import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library"; +import { describe, it, expect, vi, beforeEach } from "vitest"; + +import { TRPCError } from "@trpc/server"; + +import { duplicateHandler } from "./duplicate.handler"; + +vi.mock("@calcom/prisma", () => ({ + default: prismaMock, +})); +vi.mock("@calcom/lib/server/repository/eventTypeRepository"); +vi.mock("@calcom/lib/server/repository/calVideoSettings"); +vi.mock("../../viewer/calendars/setDestinationCalendar.handler"); + +describe("duplicateHandler", () => { + const ctx = { user: { id: 1, profile: { id: 1 } } } as any; + const input = { id: 123, slug: "test-event", title: "Test", description: "Test", length: 30, teamId: null }; + const eventType = { id: 123, userId: 1, teamId: null, users: [{ id: 1 }] }; + + beforeEach(() => { + vi.resetAllMocks(); + prismaMock.eventType.findUnique.mockResolvedValue(eventType); + }); + + it("should throw BAD_REQUEST in case of unique constraint violation", async () => { + const { EventTypeRepository } = await import("@calcom/lib/server/repository/eventTypeRepository"); + vi.mocked(EventTypeRepository).mockImplementation( + () => + ({ + create: vi.fn().mockRejectedValue( + new PrismaClientKnownRequestError("Unique constraint failed", { + code: "P2002", + clientVersion: "mockedVersion", + }) + ), + } as any) + ); + + await expect(duplicateHandler({ ctx, input })).rejects.toThrow( + new TRPCError({ + code: "BAD_REQUEST", + message: "Unique constraint violation while creating a duplicate event.", + }) + ); + }); +}); From 12ced11271ed0e97201e3bd2771d22e4f38002ad Mon Sep 17 00:00:00 2001 From: hbjORbj Date: Wed, 13 Aug 2025 18:58:52 +0900 Subject: [PATCH 4/6] fix space --- .../trpc/server/routers/viewer/eventTypes/duplicate.handler.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts index 08169aae8e3965..964f8d86fb08a9 100644 --- a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts +++ b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts @@ -166,7 +166,6 @@ export const duplicateHandler = async ({ ctx, input }: DuplicateOptions) => { } const eventTypeRepo = new EventTypeRepository(prisma); - const newEventType = await eventTypeRepo.create(data); // Create custom inputs From a9fc74220f04854a5ddce4602ae754ff3083ccf9 Mon Sep 17 00:00:00 2001 From: hbjORbj Date: Wed, 13 Aug 2025 19:00:09 +0900 Subject: [PATCH 5/6] clean up --- .../server/routers/viewer/eventTypes/duplicate.handler.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.test.ts b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.test.ts index 7624fd37a71fca..6e1d812549ec73 100644 --- a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.test.ts +++ b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.test.ts @@ -11,8 +11,6 @@ vi.mock("@calcom/prisma", () => ({ default: prismaMock, })); vi.mock("@calcom/lib/server/repository/eventTypeRepository"); -vi.mock("@calcom/lib/server/repository/calVideoSettings"); -vi.mock("../../viewer/calendars/setDestinationCalendar.handler"); describe("duplicateHandler", () => { const ctx = { user: { id: 1, profile: { id: 1 } } } as any; From fb08bd9550b5ea5b893b3f7775cfc359dbf350e0 Mon Sep 17 00:00:00 2001 From: hbjORbj Date: Thu, 14 Aug 2025 19:33:48 +0900 Subject: [PATCH 6/6] address comment --- .../trpc/server/routers/viewer/eventTypes/duplicate.handler.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts index 964f8d86fb08a9..5fd92d3cda07fc 100644 --- a/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts +++ b/packages/trpc/server/routers/viewer/eventTypes/duplicate.handler.ts @@ -1,5 +1,4 @@ import { Prisma } from "@prisma/client"; -import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library"; import { generateHashedLink } from "@calcom/lib/generateHashedLink"; import { CalVideoSettingsRepository } from "@calcom/lib/server/repository/calVideoSettings"; @@ -227,7 +226,7 @@ export const duplicateHandler = async ({ ctx, input }: DuplicateOptions) => { eventType: newEventType, }; } catch (error) { - if (error instanceof PrismaClientKnownRequestError && error.code === "P2002") { + if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2002") { // unique constraint violation throw new TRPCError({ code: "BAD_REQUEST",