Skip to content

Commit 1e673f1

Browse files
perf: handleChildrenEventTypes createManyAndReturn (calcom#25652)
* perf: handleChildrenEventTypes createManyAndReturn * fix: update test mocks for createManyAndReturn Co-Authored-By: morgan@cal.com <morgan@cal.com> * fix: use full EventType shape in createManyAndReturn mock return values Co-Authored-By: morgan@cal.com <morgan@cal.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent b91f27d commit 1e673f1

2 files changed

Lines changed: 65 additions & 101 deletions

File tree

apps/web/test/lib/handleChildrenEventTypes.test.ts

Lines changed: 64 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,23 @@ describe("handleChildrenEventTypes", () => {
148148
// Setup transaction mock to execute the callback
149149
setupTransactionMock();
150150

151-
// Mock findMany to return empty array (no workflows to link)
152-
prismaMock.eventType.findMany.mockResolvedValue([]);
151+
// Mock createManyAndReturn to return the created event type (full EventType shape required for type safety)
152+
const createdEventType = {
153+
...evType,
154+
id: 123,
155+
userId: 4,
156+
schedulingType,
157+
teamId,
158+
timeZone,
159+
requiresBookerEmailVerification,
160+
lockTimeZoneToggleOnBookingPage,
161+
useEventTypeDestinationCalendarEmail,
162+
secondaryEmailId,
163+
autoTranslateDescriptionEnabled,
164+
includeNoShowInRRCalculation,
165+
instantMeetingScheduleId,
166+
};
167+
prismaMock.eventType.createManyAndReturn.mockResolvedValue([createdEventType]);
153168

154169
const result = await updateChildrenEventTypes({
155170
eventTypeId: 1,
@@ -162,7 +177,7 @@ describe("handleChildrenEventTypes", () => {
162177
updatedValues: {},
163178
});
164179
const { createdAt, updatedAt, ...expectedEvType } = evType;
165-
expect(prismaMock.eventType.createMany).toHaveBeenCalledWith({
180+
expect(prismaMock.eventType.createManyAndReturn).toHaveBeenCalledWith({
166181
data: [
167182
{
168183
...expectedEvType,
@@ -183,6 +198,7 @@ describe("handleChildrenEventTypes", () => {
183198
},
184199
],
185200
skipDuplicates: true,
201+
select: { id: true, userId: true },
186202
});
187203
expect(result.newUserIds).toEqual([4]);
188204
expect(result.oldUserIds).toEqual([]);
@@ -329,8 +345,24 @@ describe("handleChildrenEventTypes", () => {
329345
// Setup transaction mock to execute the callback
330346
setupTransactionMock();
331347

332-
// Mock findMany to return empty array (no workflows to link)
333-
prismaMock.eventType.findMany.mockResolvedValue([]);
348+
// Mock createManyAndReturn to return the created event type (full EventType shape required for type safety)
349+
const createdEventType = {
350+
...evType,
351+
id: 123,
352+
userId: 4,
353+
schedulingType,
354+
teamId,
355+
timeZone,
356+
requiresBookerEmailVerification,
357+
lockTimeZoneToggleOnBookingPage,
358+
useEventTypeDestinationCalendarEmail,
359+
secondaryEmailId,
360+
autoTranslateDescriptionEnabled,
361+
includeNoShowInRRCalculation,
362+
instantMeetingScheduleId,
363+
assignRRMembersUsingSegment,
364+
};
365+
prismaMock.eventType.createManyAndReturn.mockResolvedValue([createdEventType]);
334366

335367
prismaMock.eventType.deleteMany.mockResolvedValue([123] as unknown as Prisma.BatchPayload);
336368
const result = await updateChildrenEventTypes({
@@ -344,7 +376,7 @@ describe("handleChildrenEventTypes", () => {
344376
updatedValues: {},
345377
});
346378
const { createdAt, updatedAt, ...expectedEvType } = evType;
347-
expect(prismaMock.eventType.createMany).toHaveBeenCalledWith({
379+
expect(prismaMock.eventType.createManyAndReturn).toHaveBeenCalledWith({
348380
data: [
349381
{
350382
...expectedEvType,
@@ -366,6 +398,7 @@ describe("handleChildrenEventTypes", () => {
366398
},
367399
],
368400
skipDuplicates: true,
401+
select: { id: true, userId: true },
369402
});
370403
expect(result.newUserIds).toEqual([4]);
371404
expect(result.oldUserIds).toEqual([]);
@@ -471,92 +504,27 @@ describe("handleChildrenEventTypes", () => {
471504
// Setup transaction mock to execute the callback
472505
setupTransactionMock();
473506

474-
// Mock findMany to return the newly created event type for workflow linking
475-
// This simulates the event type created for user 5
476-
prismaMock.eventType.findMany.mockResolvedValue([
477-
{
478-
id: 3,
479-
title: "test",
480-
slug: "test",
481-
description: null,
482-
position: 0,
483-
locations: [],
484-
length: 30,
485-
offsetStart: 0,
486-
hidden: false,
487-
userId: 5,
488-
profileId: null,
489-
teamId: null,
490-
eventName: null,
491-
parentId: 1,
492-
bookingFields: null,
493-
timeZone: null,
494-
periodType: "UNLIMITED",
495-
periodStartDate: null,
496-
periodEndDate: null,
497-
periodDays: null,
498-
periodCountCalendarDays: null,
499-
lockTimeZoneToggleOnBookingPage: false,
500-
lockedTimeZone: null,
501-
requiresConfirmation: false,
502-
requiresConfirmationWillBlockSlot: false,
503-
requiresConfirmationForFreeEmail: false,
504-
requiresBookerEmailVerification: false,
505-
canSendCalVideoTranscriptionEmails: true,
506-
autoTranslateDescriptionEnabled: false,
507-
recurringEvent: null,
508-
disableGuests: false,
509-
hideCalendarNotes: false,
510-
hideCalendarEventDetails: false,
511-
minimumBookingNotice: 120,
512-
beforeEventBuffer: 0,
513-
afterEventBuffer: 0,
514-
seatsPerTimeSlot: null,
515-
onlyShowFirstAvailableSlot: false,
516-
showOptimizedSlots: false,
517-
disableCancelling: false,
518-
disableRescheduling: false,
519-
seatsShowAttendees: false,
520-
seatsShowAvailabilityCount: true,
521-
schedulingType: null,
522-
scheduleId: null,
523-
price: 0,
524-
currency: "usd",
525-
slotInterval: null,
526-
metadata: {},
527-
successRedirectUrl: null,
528-
forwardParamsSuccessRedirect: true,
529-
bookingLimits: null,
530-
durationLimits: null,
531-
isInstantEvent: false,
532-
instantMeetingExpiryTimeOffsetInSeconds: 90,
533-
instantMeetingScheduleId: null,
534-
assignAllTeamMembers: false,
535-
useEventTypeDestinationCalendarEmail: false,
536-
secondaryEmailId: null,
537-
eventTypeColor: null,
538-
rescheduleWithSameRoundRobinHost: false,
539-
rrSegmentQueryValue: null,
540-
assignRRMembersUsingSegment: false,
541-
useEventLevelSelectedCalendars: false,
542-
restrictionScheduleId: null,
543-
useBookerTimezone: false,
544-
allowReschedulingCancelledBookings: false,
545-
includeNoShowInRRCalculation: false,
546-
interfaceLanguage: null,
547-
customReplyToEmail: null,
548-
createdAt: new Date(),
549-
updatedAt: new Date(),
550-
instantMeetingParameters: [],
551-
isRRWeightsEnabled: false,
552-
maxLeadThreshold: null,
553-
allowReschedulingPastBookings: false,
554-
hideOrganizerEmail: false,
555-
maxActiveBookingsPerBooker: null,
556-
maxActiveBookingPerBookerOfferReschedule: false,
557-
bookingRequiresAuthentication: false,
558-
},
559-
]);
507+
// Mock createManyAndReturn to return the newly created event type for workflow linking
508+
// This simulates the event type created for user 5 (full EventType shape required for type safety)
509+
const createdEventType = {
510+
...evType,
511+
id: 3,
512+
userId: 5,
513+
schedulingType: _schedulingType,
514+
teamId: _teamId,
515+
locations: _locations,
516+
timeZone: _timeZone,
517+
parentId: _parentId,
518+
requiresBookerEmailVerification,
519+
lockTimeZoneToggleOnBookingPage,
520+
useEventTypeDestinationCalendarEmail,
521+
secondaryEmailId,
522+
autoTranslateDescriptionEnabled,
523+
includeNoShowInRRCalculation,
524+
instantMeetingScheduleId,
525+
assignRRMembersUsingSegment,
526+
};
527+
prismaMock.eventType.createManyAndReturn.mockResolvedValue([createdEventType]);
560528

561529
// Mock the event type that will be returned for existing users
562530
const mockUpdatedEventType = {
@@ -601,9 +569,9 @@ describe("handleChildrenEventTypes", () => {
601569

602570
const { createdAt, updatedAt, ...expectedEvType } = evType;
603571
if ("workflows" in expectedEvType) delete expectedEvType.workflows;
604-
// Verify createMany was called for new users (user 5)
605-
// Note: createMany doesn't support nested relations like workflows, so they're handled separately
606-
expect(prismaMock.eventType.createMany).toHaveBeenCalledWith({
572+
// Verify createManyAndReturn was called for new users (user 5)
573+
// Note: createManyAndReturn doesn't support nested relations like workflows, so they're handled separately
574+
expect(prismaMock.eventType.createManyAndReturn).toHaveBeenCalledWith({
607575
data: [
608576
{
609577
...expectedEvType,
@@ -627,6 +595,7 @@ describe("handleChildrenEventTypes", () => {
627595
},
628596
],
629597
skipDuplicates: true,
598+
select: { id: true, userId: true },
630599
});
631600

632601
// Verify workflowsOnEventTypes.createMany was called for new users' workflows

packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,14 +241,9 @@ export default async function handleChildrenEventTypes({
241241
});
242242

243243
await prisma.$transaction(async (tx) => {
244-
await tx.eventType.createMany({
244+
const createdEvents = await tx.eventType.createManyAndReturn({
245245
data: eventTypesToCreateData,
246246
skipDuplicates: true,
247-
});
248-
249-
// Fetch the newly created event types to connect users and workflows
250-
const createdEvents = await tx.eventType.findMany({
251-
where: { parentId: parentId, userId: { in: newUserIds } },
252247
select: { id: true, userId: true },
253248
});
254249

0 commit comments

Comments
 (0)