From 51d210e9e11d5a25fceebad7a293c2c46ba29d70 Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Fri, 30 Aug 2024 19:10:44 +0900 Subject: [PATCH] perf: Improve loading existing bookings via API (#16410) --- packages/core/getBusyTimes.ts | 124 ++++++++++-------- .../trpc/server/routers/viewer/slots/util.ts | 16 +-- 2 files changed, 75 insertions(+), 65 deletions(-) diff --git a/packages/core/getBusyTimes.ts b/packages/core/getBusyTimes.ts index a4a68149fbf5dd..263ff90252d0f6 100644 --- a/packages/core/getBusyTimes.ts +++ b/packages/core/getBusyTimes.ts @@ -1,4 +1,5 @@ import type { Booking, EventType } from "@prisma/client"; +import { Prisma } from "@prisma/client"; import { getBusyCalendarTimes } from "@calcom/core/CalendarManager"; import dayjs from "@calcom/dayjs"; @@ -8,7 +9,7 @@ import logger from "@calcom/lib/logger"; import { getPiiFreeBooking } from "@calcom/lib/piiFreeData"; import { performance } from "@calcom/lib/server/perfObserver"; import prisma from "@calcom/prisma"; -import type { Prisma, SelectedCalendar } from "@calcom/prisma/client"; +import type { SelectedCalendar } from "@calcom/prisma/client"; import { BookingStatus } from "@calcom/prisma/enums"; import { stringToDayjs } from "@calcom/prisma/zod-utils"; import type { EventBusyDetails, IntervalLimit } from "@calcom/types/Calendar"; @@ -106,63 +107,78 @@ export async function getBusyTimes(params: { // Will keep support for retrieving a user's bookings if the caller does not already supply them. // This function is called from multiple places but we aren't refactoring all of them at this moment // to avoid potential side effects. - const bookings = params.currentBookings - ? params.currentBookings - : await prisma.booking.findMany({ - where: { - OR: [ - // User is primary host (individual events, or primary organizer) - { - ...sharedQuery, - userId, - }, - // The current user has a different booking at this time he/she attends - { - ...sharedQuery, - attendees: { - some: { - email: userEmail, - }, - }, - }, - { - startTime: { lte: endTimeDate }, - endTime: { gte: startTimeDate }, - eventType: { - id: eventTypeId, - requiresConfirmation: true, - requiresConfirmationWillBlockSlot: true, - }, - status: { - in: [BookingStatus.PENDING], - }, - }, - ], - }, + let bookings = params.currentBookings; + + if (!bookings) { + const bookingsSelect = Prisma.validator()({ + id: true, + uid: true, + userId: true, + startTime: true, + endTime: true, + title: true, + eventType: { select: { id: true, - uid: true, - userId: true, - startTime: true, - endTime: true, - title: true, - eventType: { - select: { - id: true, - afterEventBuffer: true, - beforeEventBuffer: true, - seatsPerTimeSlot: true, - }, + afterEventBuffer: true, + beforeEventBuffer: true, + seatsPerTimeSlot: true, + }, + }, + ...(seatedEvent && { + _count: { + select: { + seatsReferences: true, }, - ...(seatedEvent && { - _count: { - select: { - seatsReferences: true, - }, - }, - }), }, - }); + }), + }); + + const currentBookingsAllUsersQueryOne = prisma.booking.findMany({ + where: { + // User is primary host (individual events, or primary organizer) + ...sharedQuery, + userId, + }, + select: bookingsSelect, + }); + + const currentBookingsAllUsersQueryTwo = prisma.booking.findMany({ + where: { + ...sharedQuery, + attendees: { + some: { + email: userEmail, + }, + }, + }, + select: bookingsSelect, + }); + + const currentBookingsAllUsersQueryThree = prisma.booking.findMany({ + where: { + startTime: { lte: endTimeDate }, + endTime: { gte: startTimeDate }, + eventType: { + id: eventTypeId, + requiresConfirmation: true, + requiresConfirmationWillBlockSlot: true, + }, + status: { + in: [BookingStatus.PENDING], + }, + }, + select: bookingsSelect, + }); + + const [resultOne, resultTwo, resultThree] = await Promise.all([ + currentBookingsAllUsersQueryOne, + currentBookingsAllUsersQueryTwo, + currentBookingsAllUsersQueryThree, + ]); + + bookings = [...resultOne, ...resultTwo, ...resultThree]; + } const bookingSeatCountMap: { [x: string]: number } = {}; const busyTimes = bookings.reduce( diff --git a/packages/trpc/server/routers/viewer/slots/util.ts b/packages/trpc/server/routers/viewer/slots/util.ts index 12dd41c21f3c45..73c3732d21ede9 100644 --- a/packages/trpc/server/routers/viewer/slots/util.ts +++ b/packages/trpc/server/routers/viewer/slots/util.ts @@ -442,7 +442,7 @@ export async function getAvailableSlots({ input, ctx }: GetScheduleOptions): Pro }; const allUserIds = usersWithCredentials.map((user) => user.id); - const bookingsSelect = { + const bookingsSelect = Prisma.validator()({ id: true, uid: true, userId: true, @@ -468,7 +468,7 @@ export async function getAvailableSlots({ input, ctx }: GetScheduleOptions): Pro }, }, }), - }; + }); const currentBookingsAllUsersQueryOne = prisma.booking.findMany({ where: { @@ -477,9 +477,7 @@ export async function getAvailableSlots({ input, ctx }: GetScheduleOptions): Pro in: allUserIds, }, }, - select: { - ...bookingsSelect, - }, + select: bookingsSelect, }); const currentBookingsAllUsersQueryTwo = prisma.booking.findMany({ @@ -493,9 +491,7 @@ export async function getAvailableSlots({ input, ctx }: GetScheduleOptions): Pro }, }, }, - select: { - ...bookingsSelect, - }, + select: bookingsSelect, }); const currentBookingsAllUsersQueryThree = prisma.booking.findMany({ @@ -511,9 +507,7 @@ export async function getAvailableSlots({ input, ctx }: GetScheduleOptions): Pro in: [BookingStatus.PENDING], }, }, - select: { - ...bookingsSelect, - }, + select: bookingsSelect, }); const [resultOne, resultTwo, resultThree] = await Promise.all([