Skip to content

perf: replace OR conditions with UNION in bookings query #21067

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
99120ee
perf: replace OR conditions with UNION in bookings query
devin-ai-integration[bot] May 1, 2025
23a4a7d
fix: add type safety to raw SQL query implementation
devin-ai-integration[bot] May 1, 2025
dc28eb7
fix: resolve type checking issues
devin-ai-integration[bot] May 2, 2025
d591f34
fix: update RecurringInfo type to match BookingListItem expectations
devin-ai-integration[bot] May 2, 2025
49995e7
Abstract WHERE and FROM clause
joeauyeung May 2, 2025
9022518
perf: fetch all booking data in a single SQL query
devin-ai-integration[bot] May 2, 2025
eb3e40c
perf: fetch all booking data in a single comprehensive SQL query
devin-ai-integration[bot] May 2, 2025
6e990d7
fix: add type annotation to attendee parameter
devin-ai-integration[bot] May 2, 2025
4314287
fix: resolve remaining type checking issues
devin-ai-integration[bot] May 2, 2025
af07eb8
fix: include noShow property in attendee data and ensure consistent s…
devin-ai-integration[bot] May 2, 2025
a03d732
fix: ensure proper sorting and noShow handling in SQL query
devin-ai-integration[bot] May 2, 2025
9dc37fc
fix: use UNION ALL to preserve duplicates and ensure proper sorting
devin-ai-integration[bot] May 2, 2025
2fb12a0
fix: add row numbering to ensure consistent sorting across UNION ALL …
devin-ai-integration[bot] May 2, 2025
d0c9c10
fix: resolve SQL parameter mismatch in PrismaClientType.sql() calls
devin-ai-integration[bot] May 2, 2025
e0a4d30
fix: replace addParam with addComprehensiveParam in comprehensiveQuery
devin-ai-integration[bot] May 2, 2025
12abaf9
fix: resolve parameter mismatch in SQL query
devin-ai-integration[bot] May 2, 2025
09fc61f
fix: separate parameter arrays for recurringInfo queries to resolve p…
devin-ai-integration[bot] May 2, 2025
395d724
fix: use consistent parameters for count query to fix parameter mismatch
devin-ai-integration[bot] May 2, 2025
1d9a5d0
fix: replace PrismaClientType.sql with Prisma.sql to fix parameter mi…
devin-ai-integration[bot] May 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 42 additions & 27 deletions apps/web/components/booking/BookingListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,14 @@ type ReroutableBooking = Ensure<TeamEventBooking, "routedFromRoutingFormReponse"

function buildParsedBooking(booking: BookingItemProps) {
// The way we fetch bookings there could be eventType object even without an eventType, but id confirms its existence
const bookingEventType = booking.eventType.id
? (booking.eventType as Ensure<
typeof booking.eventType,
// It would only ensure that the props are present, if they are optional in the original type. So, it is safe to assert here.
"id" | "length" | "title" | "slug" | "schedulingType" | "team"
>)
: null;
const bookingEventType =
booking.eventType && booking.eventType.id
? (booking.eventType as Ensure<
typeof booking.eventType,
// It would only ensure that the props are present, if they are optional in the original type. So, it is safe to assert here.
"id" | "length" | "title" | "slug" | "schedulingType" | "team"
>)
: null;

const bookingMetadata = bookingMetadataSchema.parse(booking.metadata ?? null);
return {
Expand Down Expand Up @@ -119,15 +120,17 @@ function BookingListItem(booking: BookingItemProps) {
const [isNoShowDialogOpen, setIsNoShowDialogOpen] = useState<boolean>(false);
const cardCharged = booking?.payment[0]?.success;

const attendeeList = booking.attendees.map((attendee) => {
return {
name: attendee.name,
email: attendee.email,
id: attendee.id,
noShow: attendee.noShow || false,
phoneNumber: attendee.phoneNumber,
};
});
const attendeeList = booking.attendees.map(
(attendee: { name: string; email: string; id: number; noShow?: boolean; phoneNumber?: string }) => {
return {
name: attendee.name,
email: attendee.email,
id: attendee.id,
noShow: attendee.noShow || false,
phoneNumber: attendee.phoneNumber,
};
}
);

const noShowMutation = trpc.viewer.markNoShow.useMutation({
onSuccess: async (data) => {
Expand Down Expand Up @@ -169,15 +172,17 @@ function BookingListItem(booking: BookingItemProps) {
const isTabUnconfirmed = booking.listingStatus === "unconfirmed";
const isBookingFromRoutingForm = isBookingReroutable(parsedBooking);

const paymentAppData = getPaymentAppData(booking.eventType);
const paymentAppData = booking.eventType
? getPaymentAppData(booking.eventType)
: { enabled: false, price: 0 };

const location = booking.location as ReturnType<typeof getEventLocationValue>;
const locationVideoCallUrl = parsedBooking.metadata?.videoCallUrl;

const { resolvedTheme, forcedTheme } = useGetTheme();
const hasDarkTheme = !forcedTheme && resolvedTheme === "dark";
const eventTypeColor =
booking.eventType.eventTypeColor &&
booking.eventType?.eventTypeColor &&
booking.eventType.eventTypeColor[hasDarkTheme ? "darkEventTypeColor" : "lightEventTypeColor"];

const locationToDisplay = getSuccessPageLocationMessage(
Expand Down Expand Up @@ -221,8 +226,8 @@ function BookingListItem(booking: BookingItemProps) {
disabled: mutation.isPending,
},
// For bookings with payment, only confirm if the booking is paid for
...((isPending && !paymentAppData.enabled) ||
(paymentAppData.enabled && !!paymentAppData.price && booking.paid)
...((isPending && !paymentAppData?.enabled) ||
(paymentAppData?.enabled && !!paymentAppData?.price && booking.paid)
? [
{
id: "confirm",
Expand All @@ -239,7 +244,7 @@ function BookingListItem(booking: BookingItemProps) {
];

const editBookingActions: ActionType[] = [
...(isBookingInPast && !booking.eventType.allowReschedulingPastBookings
...(isBookingInPast && booking.eventType && !booking.eventType.allowReschedulingPastBookings
? []
: [
{
Expand Down Expand Up @@ -294,7 +299,7 @@ function BookingListItem(booking: BookingItemProps) {
]),
];

if (booking.eventType.schedulingType === SchedulingType.ROUND_ROBIN) {
if (booking.eventType && booking.eventType.schedulingType === SchedulingType.ROUND_ROBIN) {
editBookingActions.push({
id: "reassign ",
label: t("reassign"),
Expand Down Expand Up @@ -358,8 +363,8 @@ function BookingListItem(booking: BookingItemProps) {
},
];

const isDisabledCancelling = booking.eventType.disableCancelling;
const isDisabledRescheduling = booking.eventType.disableRescheduling;
const isDisabledCancelling = booking.eventType?.disableCancelling || false;
const isDisabledRescheduling = booking.eventType?.disableRescheduling || false;

if (isTabRecurring && isRecurring) {
bookedActions = bookedActions.filter((action) => action.id !== "edit_booking");
Expand Down Expand Up @@ -475,7 +480,7 @@ function BookingListItem(booking: BookingItemProps) {
},
];

const showPendingPayment = paymentAppData.enabled && booking.payment.length && !booking.paid;
const showPendingPayment = paymentAppData?.enabled && booking.payment.length && !booking.paid;

return (
<>
Expand Down Expand Up @@ -739,11 +744,21 @@ function BookingListItem(booking: BookingItemProps) {
/>
</div>

{isBookingFromRoutingForm && (
{isBookingFromRoutingForm && parsedBooking.eventType && (
<RerouteDialog
isOpenDialog={rerouteDialogIsOpen}
setIsOpenDialog={setRerouteDialogIsOpen}
booking={{ ...parsedBooking, eventType: parsedBooking.eventType }}
booking={{
...parsedBooking,
eventType: {
id: parsedBooking.eventType.id,
title: parsedBooking.eventType.title,
slug: parsedBooking.eventType.slug,
length: parsedBooking.eventType.length,
schedulingType: parsedBooking.eventType.schedulingType,
team: parsedBooking.eventType.team,
},
}}
/>
)}
</>
Expand Down
10 changes: 5 additions & 5 deletions apps/web/modules/bookings/views/bookings-listing-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ type BookingListingStatus = (typeof validStatuses)[number];
type BookingOutput = RouterOutputs["viewer"]["bookings"]["get"]["bookings"][0];

type RecurringInfo = {
recurringEventId: string | null;
recurringEventId: string;
count: number;
firstDate: Date | null;
bookings: { [key: string]: Date[] };
firstDate: Date;
bookings: { CANCELLED: Date[]; ACCEPTED: Date[]; REJECTED: Date[]; PENDING: Date[]; AWAITING_HOST: Date[] };
};

const tabs: (VerticalTabItemProps | HorizontalTabItemProps)[] = [
Expand Down Expand Up @@ -139,7 +139,7 @@ function BookingsContent({ status }: BookingsProps) {
const columnHelper = createColumnHelper<RowData>();

return [
columnHelper.accessor((row) => row.type === "data" && row.booking.eventType.id, {
columnHelper.accessor((row) => row.type === "data" && row.booking.eventType?.id, {
id: "eventTypeId",
header: t("event_type"),
enableColumnFilter: true,
Expand All @@ -151,7 +151,7 @@ function BookingsContent({ status }: BookingsProps) {
},
},
}),
columnHelper.accessor((row) => row.type === "data" && row.booking.eventType.team?.id, {
columnHelper.accessor((row) => row.type === "data" && row.booking.eventType?.team?.id, {
id: "teamId",
header: t("team"),
enableColumnFilter: true,
Expand Down
2 changes: 1 addition & 1 deletion packages/features/ee/teams/components/TeamsListing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function TeamsListing({
errorMsgFromInvite,
}: TeamsListingProps) {
const searchParams = useSearchParams();
const token = searchParams.get("token");
const token = searchParams?.get("token") || null;
const { t } = useLocale();
const router = useRouter();

Expand Down
Loading
Loading