Skip to content

Conversation

@hussam789
Copy link

@hussam789 hussam789 commented Oct 30, 2025

User description

PR #4


PR Type

Enhancement


Description

  • Convert InsightsBookingService from Prisma object notation to raw SQL queries

    • Replace Prisma.BookingTimeStatusDenormalizedWhereInput with Prisma.sql template literals
    • Update authorization and filter condition builders to use SQL syntax
  • Refactor condition building logic for improved performance

    • Combine authorization and filter conditions using getBaseConditions method
    • Simplify condition composition with reduce pattern for AND/OR operations
  • Update integration tests to validate Prisma.sql format

    • Replace object notation expectations with SQL template literal comparisons
    • Add NOTHING_CONDITION constant for consistency
    • Refactor findMany test to use $queryRaw for database validation
  • Fix type checking in isOrgOwnerOrAdmin method

    • Replace array includes check with direct equality comparison

Diagram Walkthrough

flowchart LR
  A["Prisma Object Notation"] -->|Convert| B["Prisma.sql Template Literals"]
  B -->|Authorization Conditions| C["getAuthorizationConditions"]
  B -->|Filter Conditions| D["getFilterConditions"]
  C -->|Combine| E["getBaseConditions"]
  D -->|Combine| E
  E -->|Raw SQL Query| F["Database"]
Loading

File Walkthrough

Relevant files
Enhancement
insightsBooking.ts
Convert to Prisma.sql raw query format                                     

packages/lib/server/service/insightsBooking.ts

  • Convert return types from
    Prisma.BookingTimeStatusDenormalizedWhereInput to Prisma.Sql
  • Replace NOTHING constant with NOTHING_CONDITION using Prisma.sql1=0
  • Refactor buildAuthorizationConditions to return Prisma.sql directly
    instead of wrapped in AND object
  • Update buildOrgAuthorizationCondition and
    buildTeamAuthorizationCondition to use SQL template literals with ANY
    operator for array conditions
  • Simplify buildFilterConditions to compose conditions with reduce
    pattern for AND operations
  • Replace findMany method with getBaseConditions method that combines
    auth and filter conditions
  • Fix isOrgOwnerOrAdmin type checking to use direct equality instead of
    array includes
  • Add InsightsBookingServicePublicOptions type for constructor parameter
+73/-82 
Tests
insightsBooking.integration-test.ts
Update tests for Prisma.sql format validation                       

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

  • Add NOTHING_CONDITION constant using Prisma.sql1=0 for consistency
  • Update all authorization condition test expectations from object
    notation to Prisma.sql template literals
  • Update all filter condition test expectations to use SQL syntax with
    proper column quoting
  • Replace findMany test with getBaseConditions test using $queryRaw for
    actual database validation
  • Remove caching tests that validated object notation behavior
  • Simplify test assertions to compare SQL template literals directly
+41/-149

…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>
@qodo-code-review
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Raw SQL usage

Description: Raw SQL fragments built with Prisma.sql are interpolated into $queryRaw (see tests)
without explicit whitelisting of identifiers, posing a possible SQL injection risk if any
interpolated values are not strictly parameterized or if identifiers/arrays are
constructed unsafely.
insightsBooking.ts [68-85]

Referred Code
async getBaseConditions(): Promise<Prisma.Sql> {
  const authConditions = await this.getAuthorizationConditions();
  const filterConditions = await this.getFilterConditions();

  if (authConditions && filterConditions) {
    return Prisma.sql`(${authConditions}) AND (${filterConditions})`;
  } else if (authConditions) {
    return authConditions;
  } else if (filterConditions) {
    return filterConditions;
  } else {
    return NOTHING_CONDITION;
  }
}

async getAuthorizationConditions(): Promise<Prisma.Sql> {
  if (this.cachedAuthConditions === undefined) {
    this.cachedAuthConditions = await this.buildAuthorizationConditions();
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing auditing: The new raw SQL condition building and query execution paths do not include any explicit
audit logging of sensitive authorization/filter application or access events.

Referred Code
async getBaseConditions(): Promise<Prisma.Sql> {
  const authConditions = await this.getAuthorizationConditions();
  const filterConditions = await this.getFilterConditions();

  if (authConditions && filterConditions) {
    return Prisma.sql`(${authConditions}) AND (${filterConditions})`;
  } else if (authConditions) {
    return authConditions;
  } else if (filterConditions) {
    return filterConditions;
  } else {
    return NOTHING_CONDITION;
  }
}

async getAuthorizationConditions(): Promise<Prisma.Sql> {
  if (this.cachedAuthConditions === undefined) {
    this.cachedAuthConditions = await this.buildAuthorizationConditions();
  }
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Error handling gaps: Methods constructing and executing raw SQL (e.g., getBaseConditions and use in tests) lack
explicit try/catch or handling of empty/null edge cases beyond basic checks, leaving
unclear how failures are surfaced or logged.

Referred Code
async getBaseConditions(): Promise<Prisma.Sql> {
  const authConditions = await this.getAuthorizationConditions();
  const filterConditions = await this.getFilterConditions();

  if (authConditions && filterConditions) {
    return Prisma.sql`(${authConditions}) AND (${filterConditions})`;
  } else if (authConditions) {
    return authConditions;
  } else if (filterConditions) {
    return filterConditions;
  } else {
    return NOTHING_CONDITION;
  }
}

async getAuthorizationConditions(): Promise<Prisma.Sql> {
  if (this.cachedAuthConditions === undefined) {
    this.cachedAuthConditions = await this.buildAuthorizationConditions();
  }
  return this.cachedAuthConditions;
}


 ... (clipped 35 lines)
Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Raw SQL errors: Transition to Prisma.sql raw conditions may surface database error messages if thrown
upstream without sanitization, and the diff does not show safe user-facing error mapping.

Referred Code
async getBaseConditions(): Promise<Prisma.Sql> {
  const authConditions = await this.getAuthorizationConditions();
  const filterConditions = await this.getFilterConditions();

  if (authConditions && filterConditions) {
    return Prisma.sql`(${authConditions}) AND (${filterConditions})`;
  } else if (authConditions) {
    return authConditions;
  } else if (filterConditions) {
    return filterConditions;
  } else {
    return NOTHING_CONDITION;
  }
}

async getAuthorizationConditions(): Promise<Prisma.Sql> {
  if (this.cachedAuthConditions === undefined) {
    this.cachedAuthConditions = await this.buildAuthorizationConditions();
  }
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Re-evaluate the necessity of this refactor

The suggestion questions the refactor from Prisma's type-safe object notation to
raw SQL, citing unproven performance claims and increased complexity. It
recommends providing benchmarks to justify this change or reverting it.

Examples:

packages/lib/server/service/insightsBooking.ts [68-81]
  async getBaseConditions(): Promise<Prisma.Sql> {
    const authConditions = await this.getAuthorizationConditions();
    const filterConditions = await this.getFilterConditions();

    if (authConditions && filterConditions) {
      return Prisma.sql`(${authConditions}) AND (${filterConditions})`;
    } else if (authConditions) {
      return authConditions;
    } else if (filterConditions) {
      return filterConditions;

 ... (clipped 4 lines)
packages/lib/server/service/__tests__/insightsBooking.integration-test.ts [480-484]
      const baseConditions = await service.getBaseConditions();
      const results = await prisma.$queryRaw<{ id: number }[]>`
        SELECT id FROM "BookingTimeStatusDenormalized"
        WHERE ${baseConditions}
      `;

Solution Walkthrough:

Before:

class InsightsBookingService {
  async findMany(findManyArgs) {
    const authConditions = await this.getAuthorizationConditions(); // Returns Prisma object
    const filterConditions = await this.getFilterConditions(); // Returns Prisma object

    return this.prisma.bookingTimeStatusDenormalized.findMany({
      ...findManyArgs,
      where: {
        AND: [authConditions, filterConditions],
      },
    });
  }
}

// Consumer code
const service = new InsightsBookingService(...);
const results = await service.findMany({ select: { id: true } });

After:

class InsightsBookingService {
  async getBaseConditions(): Promise<Prisma.Sql> {
    const authConditions = await this.getAuthorizationConditions(); // Returns Prisma.Sql
    const filterConditions = await this.getFilterConditions(); // Returns Prisma.Sql

    if (authConditions && filterConditions) {
      return Prisma.sql`(${authConditions}) AND (${filterConditions})`;
    }
    // ...
    return authConditions;
  }
}

// Consumer code
const service = new InsightsBookingService(...);
const conditions = await service.getBaseConditions();
const results = await prisma.$queryRaw`SELECT id FROM "BookingTimeStatusDenormalized" WHERE ${conditions}`;
Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a critical architectural shift from a type-safe ORM pattern to raw SQL, questioning the unproven performance claims and highlighting the significant trade-offs in maintainability and API design.

High
General
Use Prisma.join for cleaner SQL composition

Refactor the SQL condition joining logic by replacing the reduce method with the
more idiomatic and readable Prisma.join.

packages/lib/server/service/insightsBooking.ts [164-174]

-const conditions: Prisma.Sql[] = [Prisma.sql`("teamId" = ANY(${teamIds})) AND ("isTeamBooking" = true)`];
+const conditions: Prisma.Sql[] = [];
+
+if (teamIds.length > 0) {
+  conditions.push(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})`;
-});
+if (conditions.length === 0) {
+  return NOTHING_CONDITION;
+}
 
+return Prisma.join(conditions, " OR ");
+
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly proposes using Prisma.join which is a more idiomatic, readable, and maintainable way to combine Prisma.Sql fragments than the current reduce implementation.

Low
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants