-
Notifications
You must be signed in to change notification settings - Fork 0
Automated Test: insights-performance-optimization #378
Automated Test: insights-performance-optimization #378
Conversation
…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: eunjae@cal.com <hey@eunjae.dev> * 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: eunjae@cal.com <hey@eunjae.dev> * 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: eunjae@cal.com <hey@eunjae.dev> * 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: eunjae@cal.com <hey@eunjae.dev> * 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>
📝 WalkthroughWalkthroughThis PR refactors InsightsBookingService to use Prisma.Sql fragments for constructing authorization and filter conditions instead of nested object literals. The service API exposes a new public options type, and corresponding test assertions are updated to validate against raw SQL expressions. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/lib/server/service/insightsBooking.ts`:
- Around line 164-174: The generated SQL uses PostgreSQL ANY() without type
casts which breaks at runtime; update the two Prisma.sql clauses that reference
teamIds and uniqueUserIds (the initial element in the conditions array and the
pushed element for uniqueUserIds) to use IN with Prisma.join instead of ANY
(e.g., replace ("teamId" = ANY(${teamIds})) and ("userId" =
ANY(${uniqueUserIds})) with ("teamId" IN (${Prisma.join(teamIds)})) and
("userId" IN (${Prisma.join(uniqueUserIds)}))). Keep the surrounding logic that
builds the conditions array and the reduce() combining logic intact.
🧹 Nitpick comments (4)
packages/lib/server/service/insightsBooking.ts (3)
29-34:InsightsBookingServicePublicOptionsis looser than the Zod schema.The public type makes
teamIdoptional for all scopes, but the Zod schema requires it for"team"scope. WhilesafeParsehandles validation at runtime, callers using this type won't get compile-time enforcement thatteamIdmust be provided whenscope === "team". Consider using a discriminated union type matching the schema, or at least adding a doc comment noting the Zod validation requirement.♻️ Suggested type that mirrors the schema
-export type InsightsBookingServicePublicOptions = { - scope: "user" | "org" | "team"; - userId: number; - orgId: number; - teamId?: number; -}; +export type InsightsBookingServicePublicOptions = + | { scope: "user"; userId: number; orgId: number } + | { scope: "org"; userId: number; orgId: number } + | { scope: "team"; userId: number; orgId: number; teamId: number };
68-81: Dead code:authConditionsis always truthy, making two branches unreachable.
getAuthorizationConditions()always returns aPrisma.Sqlobject (either real conditions orNOTHING_CONDITION). APrisma.Sqlinstance is always truthy, so theelse if (filterConditions)branch (line 76) and theelsebranch (line 78-80) are unreachable.♻️ Simplified logic
async getBaseConditions(): Promise<Prisma.Sql> { const authConditions = await this.getAuthorizationConditions(); const filterConditions = await this.getFilterConditions(); - if (authConditions && filterConditions) { + if (filterConditions) { return Prisma.sql`(${authConditions}) AND (${filterConditions})`; - } else if (authConditions) { + } else { return authConditions; - } else if (filterConditions) { - return filterConditions; - } else { - return NOTHING_CONDITION; } }
104-112: Falsy checks on filter IDs will silently skip0values.
if (this.filters.eventTypeId)andif (this.filters.memberUserId)use truthiness, so an ID of0would be ignored. While auto-increment IDs are typically positive, using explicit!== undefined(or!= null) would be more defensive and express intent more clearly.♻️ Proposed fix
- if (this.filters.eventTypeId) { + if (this.filters.eventTypeId != null) { conditions.push( Prisma.sql`("eventTypeId" = ${this.filters.eventTypeId}) OR ("eventParentId" = ${this.filters.eventTypeId})` ); } - if (this.filters.memberUserId) { + if (this.filters.memberUserId != null) { conditions.push(Prisma.sql`"userId" = ${this.filters.memberUserId}`); }packages/lib/server/service/__tests__/insightsBooking.integration-test.ts (1)
332-343: Org scope assertion depends on query result ordering, which may be non-deterministic.The
toEqualcheck on the user IDs array ([testData.user.id, user2.id, user3.id]) assumesMembershipRepository.findAllByTeamIdsreturns users in a specific order. If the repository doesn't guarantee ordering, this test could be flaky. Since auto-increment IDs are assigned in creation order and the DB likely returns them sorted, this works in practice, but it's inherently fragile.Consider sorting the IDs in the service's
buildOrgAuthorizationConditionbefore constructing the SQL, which would make both the query and the test deterministic.
| const conditions: Prisma.Sql[] = [Prisma.sql`("teamId" = ANY(${teamIds})) AND ("isTeamBooking" = true)`]; | ||
|
|
||
| if (userIdsFromOrg.length > 0) { | ||
| const uniqueUserIds = Array.from(new Set(userIdsFromOrg)); | ||
| conditions.push(Prisma.sql`("userId" = ANY(${uniqueUserIds})) AND ("isTeamBooking" = false)`); | ||
| } | ||
|
|
||
| return conditions.reduce((acc, condition, index) => { | ||
| if (index === 0) return condition; | ||
| return Prisma.sql`(${acc}) OR (${condition})`; | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
Prisma.sql ANY operator PostgreSQL array parameter binding
💡 Result:
For PostgreSQL, bind the whole JS array as a single parameter and use ANY($1) (often with an explicit cast):
Prisma TypedSQL (recommended)
SQL (.sql file):
SELECT id, name
FROM "User"
WHERE id = ANY($1);TS:
const userIds = [1, 2, 3]
const users = await prisma.$queryRawTyped(getUsersByIds(userIds))TypedSQL explicitly supports passing PostgreSQL array arguments this way. [1]
Prisma $queryRaw / Prisma.sql
const userIds = [1, 2, 3]
const rows = await prisma.$queryRaw`
SELECT id, name
FROM "User"
WHERE id = ANY(${userIds}::int[]);
`If your array is UUIDs:
WHERE id = ANY(${userIds}::uuid[]);Why not IN ($1)?
IN ($1) treats $1 as a single scalar value, not an array; for “array parameter” semantics you typically want = ANY($1::type[]). [3]
Notes
- Prisma raw queries support parameter binding via tagged templates and also via
$queryRawUnsafe("... $1 ...", value)-style parameterization. [2]
Sources: [1] Prisma TypedSQL docs (array args + ANY($1)), [2] Prisma raw queries docs (parameterized raw queries / tagged templates), [3] Stack Overflow discussion noting IN doesn’t work with array parameters and recommending = ANY($2::text[]).
🏁 Script executed:
# Find and examine the actual code file
cat -n packages/lib/server/service/insightsBooking.ts | sed -n '160,180p'Repository: admin-coderabbit/coderabbit-cal_dot_com-mirror
Length of output: 978
🏁 Script executed:
# Search for test cases or usage patterns with ANY in the codebase
rg "Prisma\.sql.*ANY" -A 3 -B 3Repository: admin-coderabbit/coderabbit-cal_dot_com-mirror
Length of output: 3112
🏁 Script executed:
# Check if Prisma.join is used elsewhere in the codebase
rg "Prisma\.join" -B 2 -A 2Repository: admin-coderabbit/coderabbit-cal_dot_com-mirror
Length of output: 1546
🏁 Script executed:
# Check the types of teamIds and uniqueUserIds
cat -n packages/lib/server/service/insightsBooking.ts | sed -n '140,175p'Repository: admin-coderabbit/coderabbit-cal_dot_com-mirror
Length of output: 1578
🏁 Script executed:
# Look at the full method signature and variable definitions
cat -n packages/lib/server/service/insightsBooking.ts | sed -n '130,180p'Repository: admin-coderabbit/coderabbit-cal_dot_com-mirror
Length of output: 2313
🏁 Script executed:
# Check Prisma version
rg '"prisma"' package.jsonRepository: admin-coderabbit/coderabbit-cal_dot_com-mirror
Length of output: 157
🏁 Script executed:
# Examine the test to see what types are being used
cat -n packages/lib/server/service/__tests__/insightsBooking.integration-test.ts | sed -n '1,50p'Repository: admin-coderabbit/coderabbit-cal_dot_com-mirror
Length of output: 1991
Add explicit type casts to ANY() operators, or use Prisma.join() with IN for safety.
The Prisma.sql("teamId" = ANY(${teamIds}))pattern is missing required PostgreSQL type casts. When usingANY()with array parameters in Prisma, you must explicitly cast the array type (e.g.,ANY(${teamIds}::uuid[])orANY(${teamIds}::text[])`). Without the cast, the query will fail at runtime.
A more robust alternative, already used elsewhere in the codebase, is IN with Prisma.join():
Prisma.sql`("teamId" IN (${Prisma.join(teamIds)}))`Apply the same fix to line 168 for uniqueUserIds.
🤖 Prompt for AI Agents
In `@packages/lib/server/service/insightsBooking.ts` around lines 164 - 174, The
generated SQL uses PostgreSQL ANY() without type casts which breaks at runtime;
update the two Prisma.sql clauses that reference teamIds and uniqueUserIds (the
initial element in the conditions array and the pushed element for
uniqueUserIds) to use IN with Prisma.join instead of ANY (e.g., replace
("teamId" = ANY(${teamIds})) and ("userId" = ANY(${uniqueUserIds})) with
("teamId" IN (${Prisma.join(teamIds)})) and ("userId" IN
(${Prisma.join(uniqueUserIds)}))). Keep the surrounding logic that builds the
conditions array and the reduce() combining logic intact.
This pull request was automatically created by
@coderabbitai/e2e-reviewer.Batch created pull request.
Summary by CodeRabbit
Refactor
Tests