diff --git a/apps/api/v2/package.json b/apps/api/v2/package.json index e96aeca30e..8e6fd564f8 100644 --- a/apps/api/v2/package.json +++ b/apps/api/v2/package.json @@ -38,7 +38,7 @@ "@axiomhq/winston": "^1.2.0", "@calcom/platform-constants": "*", "@calcom/platform-enums": "*", - "@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.253", + "@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.255", "@calcom/platform-types": "*", "@calcom/platform-utils": "*", "@calcom/prisma": "*", diff --git a/packages/lib/server/repository/selectedSlots.ts b/packages/lib/server/repository/selectedSlots.ts index c99d85a890..f86873f48d 100644 --- a/packages/lib/server/repository/selectedSlots.ts +++ b/packages/lib/server/repository/selectedSlots.ts @@ -1,6 +1,6 @@ import type { Prisma } from "@prisma/client"; -import { prisma } from "@calcom/prisma"; +import type { PrismaClient } from "@calcom/prisma"; type WhereCondition = { slotUtcStartDate?: Date | string; @@ -23,17 +23,19 @@ export type TimeSlot = { }; export class SelectedSlotsRepository { - static async findMany({ where, select }: FindManyArgs) { - return await prisma.selectedSlots.findMany({ where, select }); + constructor(private prismaClient: PrismaClient) {} + + async findMany({ where, select }: FindManyArgs) { + return await this.prismaClient.selectedSlots.findMany({ where, select }); } - static async findFirst({ where }: { where: Prisma.SelectedSlotsWhereInput }) { - return await prisma.selectedSlots.findFirst({ + async findFirst({ where }: { where: Prisma.SelectedSlotsWhereInput }) { + return await this.prismaClient.selectedSlots.findFirst({ where, }); } - static async findReservedByOthers({ + async findReservedByOthers({ slot, eventTypeId, uid, @@ -53,7 +55,7 @@ export class SelectedSlotsRepository { }); } - static async findManyReservedByOthers(slots: TimeSlot[], eventTypeId: number, uid: string) { + async findManyReservedByOthers(slots: TimeSlot[], eventTypeId: number, uid: string) { return await this.findMany({ where: { OR: slots.map((slot) => ({ @@ -71,14 +73,14 @@ export class SelectedSlotsRepository { }); } - static async findManyUnexpiredSlots({ + async findManyUnexpiredSlots({ userIds, currentTimeInUtc, }: { userIds: number[]; currentTimeInUtc: string; }) { - return prisma.selectedSlots.findMany({ + return this.prismaClient.selectedSlots.findMany({ where: { userId: { in: userIds }, releaseAt: { gt: currentTimeInUtc }, @@ -95,14 +97,14 @@ export class SelectedSlotsRepository { }); } - static async deleteManyExpiredSlots({ + async deleteManyExpiredSlots({ eventTypeId, currentTimeInUtc, }: { eventTypeId: number; currentTimeInUtc: string; }) { - return prisma.selectedSlots.deleteMany({ + return this.prismaClient.selectedSlots.deleteMany({ where: { eventTypeId: { equals: eventTypeId }, releaseAt: { lt: currentTimeInUtc }, diff --git a/packages/trpc/server/routers/viewer/slots/isAvailable.handler.ts b/packages/trpc/server/routers/viewer/slots/isAvailable.handler.ts index 130f5c4989..1884af8390 100644 --- a/packages/trpc/server/routers/viewer/slots/isAvailable.handler.ts +++ b/packages/trpc/server/routers/viewer/slots/isAvailable.handler.ts @@ -40,9 +40,8 @@ export const isAvailableHandler = async ({ // Check each slot's availability // Without uid, we must not check for reserved slots because if uuid isn't set in cookie yet, but it is going to be through reserveSlot request soon, we could consider the slot as reserved accidentally. - const reservedSlots = uid - ? await SelectedSlotsRepository.findManyReservedByOthers(slots, eventTypeId, uid) - : []; + const slotsRepo = new SelectedSlotsRepository(ctx.prisma); + const reservedSlots = uid ? await slotsRepo.findManyReservedByOthers(slots, eventTypeId, uid) : []; // Map all slots to their availability status const slotsWithStatus: TIsAvailableOutputSchema["slots"] = slots.map((slot) => { diff --git a/packages/trpc/server/routers/viewer/slots/reserveSlot.handler.test.ts b/packages/trpc/server/routers/viewer/slots/reserveSlot.handler.test.ts index 01df877a0c..b2a006f97a 100644 --- a/packages/trpc/server/routers/viewer/slots/reserveSlot.handler.test.ts +++ b/packages/trpc/server/routers/viewer/slots/reserveSlot.handler.test.ts @@ -10,12 +10,12 @@ import { vi, describe, it, expect, afterEach } from "vitest"; // We alias the module path once we know WEBAPP_URL has been configured. const dynamicImportHandler = async () => await import("./reserveSlot.handler"); -// The repository static method is used to check for an existing reservation by someone else. +// The repository instance method is used to check for an existing reservation by someone else. // To keep this unit test isolated from the database layer, we stub this to always resolve falsey. vi.mock("@calcom/lib/server/repository/selectedSlots", () => ({ - SelectedSlotsRepository: { + SelectedSlotsRepository: vi.fn().mockImplementation(() => ({ findReservedByOthers: vi.fn().mockResolvedValue(null), - }, + })), })); // A tiny helper to build a canned handler context with stubbed Prisma methods. diff --git a/packages/trpc/server/routers/viewer/slots/reserveSlot.handler.ts b/packages/trpc/server/routers/viewer/slots/reserveSlot.handler.ts index 22f27f1392..7b9c4d8d4e 100644 --- a/packages/trpc/server/routers/viewer/slots/reserveSlot.handler.ts +++ b/packages/trpc/server/routers/viewer/slots/reserveSlot.handler.ts @@ -64,7 +64,8 @@ export const reserveSlotHandler = async ({ ctx, input }: ReserveSlotOptions) => } // Check for existing reservations for the same slot - const reservedBySomeoneElse = await SelectedSlotsRepository.findReservedByOthers({ + const slotsRepo = new SelectedSlotsRepository(prisma); + const reservedBySomeoneElse = await slotsRepo.findReservedByOthers({ slot: { utcStartIso: slotUtcStartDate, utcEndIso: slotUtcEndDate, diff --git a/packages/trpc/server/routers/viewer/slots/util.ts b/packages/trpc/server/routers/viewer/slots/util.ts index 4c58e327a9..492891a482 100644 --- a/packages/trpc/server/routers/viewer/slots/util.ts +++ b/packages/trpc/server/routers/viewer/slots/util.ts @@ -107,9 +107,10 @@ export class AvailableSlotsService { eventTypeId: number; }) { const currentTimeInUtc = dayjs.utc().format(); + const slotsRepo = new SelectedSlotsRepository(prisma); const unexpiredSelectedSlots = - (await SelectedSlotsRepository.findManyUnexpiredSlots({ + (await slotsRepo.findManyUnexpiredSlots({ userIds: usersWithCredentials.map((user) => user.id), currentTimeInUtc, })) || []; @@ -123,7 +124,7 @@ export class AvailableSlotsService { return reservedSlots; async function _cleanupExpiredSlots({ eventTypeId }: { eventTypeId: number }) { - await SelectedSlotsRepository.deleteManyExpiredSlots({ eventTypeId, currentTimeInUtc }); + await slotsRepo.deleteManyExpiredSlots({ eventTypeId, currentTimeInUtc }); } } diff --git a/yarn.lock b/yarn.lock index 5c6a40b307..191cf46544 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2519,7 +2519,7 @@ __metadata: "@axiomhq/winston": ^1.2.0 "@calcom/platform-constants": "*" "@calcom/platform-enums": "*" - "@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.253" + "@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.255" "@calcom/platform-types": "*" "@calcom/platform-utils": "*" "@calcom/prisma": "*" @@ -3565,13 +3565,13 @@ __metadata: languageName: unknown linkType: soft -"@calcom/platform-libraries@npm:@calcom/platform-libraries@0.0.253": - version: 0.0.253 - resolution: "@calcom/platform-libraries@npm:0.0.253" +"@calcom/platform-libraries@npm:@calcom/platform-libraries@0.0.255": + version: 0.0.255 + resolution: "@calcom/platform-libraries@npm:0.0.255" dependencies: "@calcom/features": "*" "@calcom/lib": "*" - checksum: 797435f9a72750dc7f8bc6d3b52b1b1fa93701451907f4ae29028403619365649bdc7c5632ac1db326bd6ed1b90e27544d14ae108e042fe18eaeac4ca11e8606 + checksum: 50ec08f31a1a30fde270335f93065554ff93d74ab96d059262cec44f9efcae2036c2a7c26177cb3a1a2f708dabea4736b26110629ab08691e97a62f9d3464cd9 languageName: node linkType: hard