Skip to content

Conversation

@emrysal
Copy link
Contributor

@emrysal emrysal commented Jan 27, 2026

What does this PR do?

Optimizes the team booking limits query in _getBusyTimesFromTeamLimitsForUsers by replacing an expensive attendee.email IN (64+ emails) SQL pattern with indexed eventType.teamId filtering and in-application user filtering.

Problem: The original query generated an expensive EXISTS subquery scanning attendees for each booking with 64+ email parameters, which is slow for large teams.

Solution:

  • Query all team bookings by eventType.teamId (indexed column)
  • Filter in application code using Sets for O(1) lookups to find bookings where users are organizers or attendees

Changes:

  • Add findByTeamIdAndDateRangeIncludeAttendees to BookingRepository
  • Refactor _getBusyTimesFromTeamLimitsForUsers to use the new method with in-app filtering

Trade-off: Returns slightly more data from DB (all team bookings vs only user-relevant), but the query is significantly faster due to using indexed columns instead of expensive EXISTS subqueries.

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A - internal optimization only.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  1. Test team booking limits functionality with a team that has multiple members
  2. Verify availability slots are correctly calculated when team booking limits are configured
  3. Compare query performance before/after for teams with 50+ members

Key verification points:

  • Bookings where user is the organizer (userId) should be counted toward limits
  • Bookings where user is an attendee (email match) should be counted toward limits
  • Managed event bookings should be included when includeManagedEvents is true

Checklist

  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • I have checked if my changes generate no new warnings

Human Review Checklist

  • Verify the in-app filtering logic correctly replicates the original query behavior (organizer OR attendee matching)
  • Consider if existing tests adequately cover this code path
  • Evaluate the trade-off for teams with many bookings but few relevant users

Link to Devin run: https://app.devin.ai/sessions/65b1815aa6b74057959160047de5e8f3
Requested by: @emrysal

Replace expensive attendee email IN clause query with eventType.teamId
filtering and in-application user filtering.

Changes:
- Add findByTeamIdAndDateRangeIncludeAttendees to BookingRepository
- Refactor _getBusyTimesFromTeamLimitsForUsers to use new method
- Filter bookings in application code using Set for O(1) lookups

This improves query performance for large teams by:
1. Using indexed eventType.teamId column instead of attendee email IN
2. Reducing from 2-3 queries to 1-2 queries
3. Avoiding expensive EXISTS subquery with 64+ email parameters

Co-Authored-By: alex@cal.com <me@alexvanandel.com>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@emrysal emrysal marked this pull request as ready for review January 27, 2026 17:08
@emrysal emrysal requested a review from a team as a code owner January 27, 2026 17:08
@graphite-app graphite-app bot added foundation core area: core, team members only labels Jan 27, 2026
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/trpc/server/routers/viewer/slots/util.ts">

<violation number="1" location="packages/trpc/server/routers/viewer/slots/util.ts:659">
P2: The new attendee-email filter applies to all bookings (including managed events), but the previous query only counted managed bookings when the organizer userId matched. This changes booking-limit behavior for managed events and can over-count limits. Consider distinguishing managed bookings and only applying attendee matching to non-managed bookings to preserve prior behavior.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

return true;
}
// Check if any user is an attendee
return booking.attendees.some((attendee) => userEmailSet.has(attendee.email));
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The new attendee-email filter applies to all bookings (including managed events), but the previous query only counted managed bookings when the organizer userId matched. This changes booking-limit behavior for managed events and can over-count limits. Consider distinguishing managed bookings and only applying attendee matching to non-managed bookings to preserve prior behavior.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/trpc/server/routers/viewer/slots/util.ts, line 659:

<comment>The new attendee-email filter applies to all bookings (including managed events), but the previous query only counted managed bookings when the organizer userId matched. This changes booking-limit behavior for managed events and can over-count limits. Consider distinguishing managed bookings and only applying attendee matching to non-managed bookings to preserve prior behavior.</comment>

<file context>
@@ -634,16 +634,32 @@ export class AvailableSlotsService {
+        return true;
+      }
+      // Check if any user is an attendee
+      return booking.attendees.some((attendee) => userEmailSet.has(attendee.email));
+    });
+
</file context>
Fix with Cubic

@github-actions
Copy link
Contributor

Devin AI is addressing Cubic AI's review feedback

A Devin session has been created to address the issues identified by Cubic AI.

View Devin Session

@devin-ai-integration
Copy link
Contributor

I reviewed the Cubic AI feedback on this PR. The issue identified (violation #1 regarding the attendee-email filter applying to managed events) has a confidence score of 7/10, which is below the 9/10 threshold required for automated fixes.

Issue skipped due to low confidence score:

Since no issues meet the 9/10 confidence threshold, no changes were made to this PR. A human reviewer should evaluate whether this concern is valid and warrants a fix.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants