Skip to content

Commit 56ff75f

Browse files
eunjae-leedevin-ai-integration[bot]
authored andcommitted
feat: convert InsightsBookingService to use Prisma.sql raw queries (#22345)
* fix: use raw query at InsightsBookingService * feat: convert InsightsBookingService to use Prisma.sql raw queries - Convert auth conditions from Prisma object notation to Prisma.sql - Convert filter conditions from Prisma object notation to Prisma.sql - Update return types from Prisma.BookingTimeStatusDenormalizedWhereInput to Prisma.Sql - Fix type error in isOrgOwnerOrAdmin method - Follow same pattern as InsightsRoutingService conversion Co-Authored-By: [email protected] <[email protected]> * feat: convert InsightsBookingService to use Prisma.sql raw queries - Convert auth conditions from Prisma object notation to Prisma.sql - Convert filter conditions from Prisma object notation to Prisma.sql - Update return types from Prisma.BookingTimeStatusDenormalizedWhereInput to Prisma.Sql - Fix type error in isOrgOwnerOrAdmin method - Follow same pattern as InsightsRoutingService conversion Co-Authored-By: [email protected] <[email protected]> * fix: update InsightsBookingService integration tests for Prisma.sql format - Replace Prisma object notation expectations with Prisma.sql template literals - Add NOTHING_CONDITION constant for consistency with InsightsRoutingService - Update all test cases to use direct Prisma.sql comparisons - Use $queryRaw for actual database integration testing - Follow same testing patterns as InsightsRoutingService Co-Authored-By: [email protected] <[email protected]> * fix: exclude intentionally skipped jobs from required CI check failure - Remove 'skipped' from failure condition in pr.yml and all-checks.yml - Allow E2E jobs to be skipped without failing the required check - Only actual failures and cancelled jobs will cause required check to fail Co-Authored-By: [email protected] <[email protected]> * fix tests * Revert "fix: exclude intentionally skipped jobs from required CI check failure" This reverts commit 6ff44fc9a8f14ad657f7bba7c2e454e192b66c8f. * clean up tests * address feedback --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 202d248 commit 56ff75f

File tree

2 files changed

+114
-231
lines changed

2 files changed

+114
-231
lines changed

packages/lib/server/service/__tests__/insightsBooking.integration-test.ts

Lines changed: 41 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import type { Team, User, Membership } from "@prisma/client";
2+
import { Prisma } from "@prisma/client";
23
import { describe, expect, it } from "vitest";
34

45
import prisma from "@calcom/prisma";
56
import { BookingStatus, MembershipRole } from "@calcom/prisma/enums";
67

78
import { InsightsBookingService } from "../../service/insightsBooking";
89

10+
const NOTHING_CONDITION = Prisma.sql`1=0`;
11+
912
// Helper function to create unique test data
1013
async function createTestData({
1114
teamRole = MembershipRole.MEMBER,
@@ -204,7 +207,7 @@ describe("InsightsBookingService Integration Tests", () => {
204207
});
205208

206209
const conditions = await service.getAuthorizationConditions();
207-
expect(conditions).toEqual({ id: -1 });
210+
expect(conditions).toEqual(NOTHING_CONDITION);
208211
});
209212

210213
it("should return NOTHING for non-owner/admin user", async () => {
@@ -239,7 +242,7 @@ describe("InsightsBookingService Integration Tests", () => {
239242
});
240243

241244
const conditions = await service.getAuthorizationConditions();
242-
expect(conditions).toEqual({ id: -1 });
245+
expect(conditions).toEqual(NOTHING_CONDITION);
243246

244247
// Clean up
245248
await prisma.membership.delete({
@@ -267,14 +270,7 @@ describe("InsightsBookingService Integration Tests", () => {
267270
});
268271

269272
const conditions = await service.getAuthorizationConditions();
270-
expect(conditions).toEqual({
271-
AND: [
272-
{
273-
userId: testData.user.id,
274-
teamId: null,
275-
},
276-
],
277-
});
273+
expect(conditions).toEqual(Prisma.sql`("userId" = ${testData.user.id}) AND ("teamId" IS NULL)`);
278274

279275
await testData.cleanup();
280276
});
@@ -296,24 +292,11 @@ describe("InsightsBookingService Integration Tests", () => {
296292
});
297293

298294
const conditions = await service.getAuthorizationConditions();
299-
expect(conditions).toEqual({
300-
AND: [
301-
{
302-
OR: [
303-
{
304-
teamId: testData.team.id,
305-
isTeamBooking: true,
306-
},
307-
{
308-
userId: {
309-
in: [testData.user.id],
310-
},
311-
isTeamBooking: false,
312-
},
313-
],
314-
},
315-
],
316-
});
295+
expect(conditions).toEqual(
296+
Prisma.sql`(("teamId" = ${testData.team.id}) AND ("isTeamBooking" = true)) OR (("userId" = ANY(${[
297+
testData.user.id,
298+
]})) AND ("isTeamBooking" = false))`
299+
);
317300

318301
// Clean up
319302
await testData.cleanup();
@@ -346,26 +329,18 @@ describe("InsightsBookingService Integration Tests", () => {
346329

347330
const conditions = await service.getAuthorizationConditions();
348331

349-
expect(conditions).toEqual({
350-
AND: [
351-
{
352-
OR: [
353-
{
354-
teamId: {
355-
in: [testData.org.id, testData.team.id, team2.id, team3.id],
356-
},
357-
isTeamBooking: true,
358-
},
359-
{
360-
userId: {
361-
in: [testData.user.id, user2.id, user3.id],
362-
},
363-
isTeamBooking: false,
364-
},
365-
],
366-
},
367-
],
368-
});
332+
expect(conditions).toEqual(
333+
Prisma.sql`(("teamId" = ANY(${[
334+
testData.org.id,
335+
testData.team.id,
336+
team2.id,
337+
team3.id,
338+
]})) AND ("isTeamBooking" = true)) OR (("userId" = ANY(${[
339+
testData.user.id,
340+
user2.id,
341+
user3.id,
342+
]})) AND ("isTeamBooking" = false))`
343+
);
369344

370345
await testData.cleanup();
371346
});
@@ -406,13 +381,9 @@ describe("InsightsBookingService Integration Tests", () => {
406381
});
407382

408383
const conditions = await service.getFilterConditions();
409-
expect(conditions).toEqual({
410-
AND: [
411-
{
412-
OR: [{ eventTypeId: testData.eventType.id }, { eventParentId: testData.eventType.id }],
413-
},
414-
],
415-
});
384+
expect(conditions).toEqual(
385+
Prisma.sql`("eventTypeId" = ${testData.eventType.id}) OR ("eventParentId" = ${testData.eventType.id})`
386+
);
416387

417388
await testData.cleanup();
418389
});
@@ -433,13 +404,7 @@ describe("InsightsBookingService Integration Tests", () => {
433404
});
434405

435406
const conditions = await service.getFilterConditions();
436-
expect(conditions).toEqual({
437-
AND: [
438-
{
439-
userId: testData.user.id,
440-
},
441-
],
442-
});
407+
expect(conditions).toEqual(Prisma.sql`"userId" = ${testData.user.id}`);
443408

444409
await testData.cleanup();
445410
});
@@ -461,90 +426,15 @@ describe("InsightsBookingService Integration Tests", () => {
461426
});
462427

463428
const conditions = await service.getFilterConditions();
464-
expect(conditions).toEqual({
465-
AND: [
466-
{
467-
OR: [{ eventTypeId: testData.eventType.id }, { eventParentId: testData.eventType.id }],
468-
},
469-
{
470-
userId: testData.user.id,
471-
},
472-
],
473-
});
474-
475-
await testData.cleanup();
476-
});
477-
});
478-
479-
describe("Caching", () => {
480-
it("should cache authorization conditions", async () => {
481-
const testData = await createTestData({
482-
teamRole: MembershipRole.OWNER,
483-
orgRole: MembershipRole.OWNER,
484-
});
485-
486-
const service = new InsightsBookingService({
487-
prisma,
488-
options: {
489-
scope: "user",
490-
userId: testData.user.id,
491-
orgId: testData.org.id,
492-
},
493-
});
494-
495-
// First call should build conditions
496-
const conditions1 = await service.getAuthorizationConditions();
497-
expect(conditions1).toEqual({
498-
AND: [
499-
{
500-
userId: testData.user.id,
501-
teamId: null,
502-
},
503-
],
504-
});
505-
506-
// Second call should use cached conditions
507-
const conditions2 = await service.getAuthorizationConditions();
508-
expect(conditions2).toEqual(conditions1);
509-
510-
// Clean up
511-
await testData.cleanup();
512-
});
513-
514-
it("should cache filter conditions", async () => {
515-
const testData = await createTestData();
516-
517-
const service = new InsightsBookingService({
518-
prisma,
519-
options: {
520-
scope: "user",
521-
userId: testData.user.id,
522-
orgId: testData.org.id,
523-
},
524-
filters: {
525-
eventTypeId: testData.eventType.id,
526-
},
527-
});
528-
529-
// First call should build conditions
530-
const conditions1 = await service.getFilterConditions();
531-
expect(conditions1).toEqual({
532-
AND: [
533-
{
534-
OR: [{ eventTypeId: testData.eventType.id }, { eventParentId: testData.eventType.id }],
535-
},
536-
],
537-
});
538-
539-
// Second call should use cached conditions
540-
const conditions2 = await service.getFilterConditions();
541-
expect(conditions2).toEqual(conditions1);
429+
expect(conditions).toEqual(
430+
Prisma.sql`(("eventTypeId" = ${testData.eventType.id}) OR ("eventParentId" = ${testData.eventType.id})) AND ("userId" = ${testData.user.id})`
431+
);
542432

543433
await testData.cleanup();
544434
});
545435
});
546436

547-
describe("findMany", () => {
437+
describe("getBaseConditions", () => {
548438
it("should combine authorization and filter conditions", async () => {
549439
const testData = await createTestData({
550440
teamRole: MembershipRole.OWNER,
@@ -587,16 +477,18 @@ describe("InsightsBookingService Integration Tests", () => {
587477
},
588478
});
589479

590-
const results = await service.findMany({
591-
select: {
592-
id: true,
593-
title: true,
594-
},
595-
});
480+
const baseConditions = await service.getBaseConditions();
481+
const results = await prisma.$queryRaw<{ id: number }[]>`
482+
SELECT id FROM "BookingTimeStatusDenormalized"
483+
WHERE ${baseConditions}
484+
`;
596485

597486
// Should return the user booking since it matches both conditions
598-
expect(results).toHaveLength(1);
599-
expect(results[0]?.id).toBe(userBooking.id);
487+
expect(results).toEqual([
488+
{
489+
id: userBooking.id,
490+
},
491+
]);
600492

601493
// Clean up
602494
await prisma.booking.delete({

0 commit comments

Comments
 (0)