Skip to content

feat(events): add mutations for managing event RSVPs with optimistic concurrency (#1363) - #1797

Merged
krushit1307 merged 1 commit into
krushit1307:mainfrom
nayanraj864-cmyk:feat/rsvp-concurrency-mutation-1363
Jul 29, 2026
Merged

feat(events): add mutations for managing event RSVPs with optimistic concurrency (#1363)#1797
krushit1307 merged 1 commit into
krushit1307:mainfrom
nayanraj864-cmyk:feat/rsvp-concurrency-mutation-1363

Conversation

@nayanraj864-cmyk

@nayanraj864-cmyk nayanraj864-cmyk commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Pull Request

Description

Implements concurrent-safe RSVP management with pessimistic row-level locking (SELECT ... FOR UPDATE) and optimistic concurrency version tracking for CampusConnect (#1363).

When high-demand campus events open for registration, simultaneous user submissions are processed safely without overbooking or race conditions. The event's max_attendees capacity is strictly enforced, ensuring the available_spots counter never drops below zero.

  • Added version (INTEGER DEFAULT 1) and available_spots columns to the events table.
  • Implemented public.manage_event_rsvp(p_event_id, p_user_id, p_action) RPC function with transaction-level SELECT ... FOR UPDATE row locking.
  • Prevented duplicate RSVPs (ALREADY_RSVPED) and enforced capacity limits (EVENT_FULL).
  • Added GraphQL rsvpToEvent(eventId: ID!, userId: ID, action: String): RsvpPayload! mutation and RsvpPayload type definition in graphql/resolvers/index.ts.
  • Exposed maxAttendees, availableSpots, and version fields on the GraphQL Event type.
  • Created pgTAP unit test suite in supabase/tests/rsvp_concurrency.test.sql to verify capacity enforcement, locking behavior, duplicate handling, and spot release on cancellation.
  • Added GraphQL integration unit tests in src/graphql/server.test.ts (13/13 passing).

Type of Change

  • New Feature
  • Bug Fix
  • Documentation Update
  • Refactor
  • Performance Improvement
  • Security Improvement
  • Other

Related Issue

Closes #1363

Testing

Describe the testing performed.

  • Tested locally

  • Existing functionality verified

  • No new warnings or errors

  • pgTAP Test Suite (supabase/tests/rsvp_concurrency.test.sql):

    • public.manage_event_rsvp signature & execution.
    • Event capacity limit (2/2 filled -> 3rd user attempt returns EVENT_FULL, available_spots remains 0).
    • Total RSVP count in table is capped strictly at max_attendees.
    • Cancellation frees a spot (CANCEL_SUCCESS, spot count restored, 3rd user can then successfully register).
  • GraphQL Integration Tests (src/graphql/server.test.ts):

    • rsvpToEvent mutation execution and RsvpPayload schema fields (success, code, message, availableSpots, status, version).
    • 13/13 Vitest tests passing.
    • npx tsc --noEmit passed with 0 type errors.
    • npx eslint --max-warnings=0 passed with 0 warnings/errors.

Screenshots

N/A

Checklist

  • Code follows project conventions
  • Documentation updated where required
  • No unnecessary files included
  • Changes have been tested
  • Ready for review

Summary by CodeRabbit

  • New Features

    • Added GraphQL support for RSVPing to and cancelling attendance at events.
    • Event details now include maximum capacity, available spots, and a version indicator.
    • RSVP responses report success status, messages, capacity, and updated event version.
    • Added capacity enforcement and concurrency-safe RSVP processing.
  • Bug Fixes

    • Prevented duplicate RSVPs and blocked registrations when events are full.
    • Cancelling an RSVP now correctly frees an available spot.
  • Tests

    • Added coverage for successful, duplicate, full-capacity, cancellation, and subsequent RSVP scenarios.

…concurrency (krushit1307#1363)

- Add version and available_spots tracking columns to events table.
- Create public.manage_event_rsvp RPC function using pessimistic row-level locking
  (SELECT ... FOR UPDATE) and version increment logic to prevent race conditions and overbooking.
- Ensure event capacity (max_attendees) is strictly enforced and available_spots counter never drops below 0.
- Expose rsvpToEvent GraphQL mutation and RsvpPayload type in GraphQL Yoga resolvers/schema.
- Add pgTAP test suite (supabase/tests/rsvp_concurrency.test.sql) verifying capacity limits,
  duplicate RSVP prevention, spot release on cancellation, and locking.
- Add GraphQL integration tests in src/graphql/server.test.ts (13/13 passing).

Closes krushit1307#1363
@github-actions github-actions Bot added backend ECSoC26 Elite Coders Summer Of Code'26 - Open Source Program optimization labels Jul 29, 2026
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Event RSVP concurrency

Layer / File(s) Summary
Database RSVP state and concurrency
supabase/migrations/..., supabase/schema.sql, supabase/tests/*
Events gain available_spots and version; manage_event_rsvp serializes RSVP changes, enforces capacity, updates counters, and is covered by pgTAP tests.
GraphQL RSVP API and coverage
graphql/resolvers/index.ts, src/graphql/server.test.ts
GraphQL exposes RSVP and capacity fields, maps RPC responses into RsvpPayload, and tests successful and full-event mutations.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant GraphQL
  participant SupabaseRPC
  participant PostgreSQL
  Client->>GraphQL: rsvpToEvent(eventId, userId, action)
  GraphQL->>SupabaseRPC: manage_event_rsvp parameters
  SupabaseRPC->>PostgreSQL: lock event and update RSVP state
  PostgreSQL-->>SupabaseRPC: status, available_spots, version
  SupabaseRPC-->>GraphQL: JSONB response
  GraphQL-->>Client: RsvpPayload
Loading

Possibly related PRs

Suggested labels: advanced, enhancement, good-backend, good-pr, quality

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning supabase/schema.sql includes unrelated merge-conflict changes for saved_events, realtime publication, RLS policies, and profile backfill logic. Remove or split out the unrelated schema conflict resolutions so the PR only contains RSVP concurrency changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: event RSVP mutations with optimistic concurrency.
Linked Issues check ✅ Passed The RSVP RPC, GraphQL mutation, locking/version logic, and capacity tests satisfy #1363's concurrency and nonnegative spots requirements.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (4)
supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql (1)

139-147: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

CANCEL hard-deletes and always reports success, contradicting the CANCELLED status model used elsewhere.

Every other branch treats status = 'CANCELLED' as the cancellation representation, but here the row is removed, so cancellations leave no trace and a cancel for a user who never RSVPed still returns CANCEL_SUCCESS. Consider an UPDATE ... SET status = 'CANCELLED' and returning NOT_RSVPED when no row was affected.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql` around
lines 139 - 147, Update the CANCEL/REMOVE/UNRSVP branch to mark the matching
event_rsvps row with status 'CANCELLED' instead of deleting it. Track the
affected-row count and return NOT_RSVPED when no row exists for the effective
user; only report cancellation success after an update, while preserving the
existing RSVP recount behavior.
supabase/schema.sql (1)

102-103: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add a CHECK (available_spots >= 0) constraint.

Issue #1363 requires available_spots never becomes negative; today that invariant only lives in the RPC's GREATEST(0, ...). A column constraint enforces it for any other writer.

🛡️ Proposed constraint
-  available_spots INTEGER,
+  available_spots INTEGER CHECK (available_spots IS NULL OR available_spots >= 0),
   version INTEGER NOT NULL DEFAULT 1,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@supabase/schema.sql` around lines 102 - 103, Add a database CHECK constraint
to the available_spots column definition requiring values to be greater than or
equal to zero, while preserving its nullable behavior and the existing version
definition. Ensure this constraint applies independently of the RPC logic to
protect all writers.
graphql/resolvers/index.ts (1)

213-217: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate snake_case + camelCase fields double the Event API surface.

max_attendees/maxAttendees and available_spots/availableSpots are aliases for the same data. If camelCase is the direction, mark the snake_case variants @deprecated rather than maintaining both indefinitely.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@graphql/resolvers/index.ts` around lines 213 - 217, Deprecate the snake_case
Event fields max_attendees and available_spots in the GraphQL schema while
retaining maxAttendees and availableSpots as the preferred fields. Add
appropriate `@deprecated` metadata to the snake_case variants without changing
their existing data behavior.
src/graphql/server.test.ts (1)

78-109: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mock never exercises the resolver's error/fallback paths.

error is always null and data is never null, so the throw new Error(error.message) branch and the ?? "ERROR" / ?? null defaults in rsvpToEvent are untested. Adding an evt-error and an evt-null-data case would cover both cheaply. p_action is also ignored, so a CANCEL case can't be distinguished.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/graphql/server.test.ts` around lines 78 - 109, Update the rpc mock in the
GraphQL test to add evt-error and evt-null-data responses, exercising the
resolver’s error throw and fallback defaults in rsvpToEvent. Use a non-null
error with a message for evt-error and null data for evt-null-data, while
preserving existing RSVP behavior. Also branch on args.p_action so CANCEL
requests receive distinguishable mock behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql`:
- Around line 23-31: Bind RSVP mutations to the authenticated actor at both
layers: in supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql,
update manage_event_rsvp to reject mismatched p_user_id unless the caller is
service_role; in graphql/resolvers/index.ts lines 438-458, make rsvpToEvent
derive the user ID from request context, and remove or admin-gate the
client-supplied userId schema argument.
- Around line 11-19: The migration references missing event_rsvps.status and
events.requires_approval columns. At
supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql lines 11-19,
add event_rsvps.status with the specified default before the backfill and mirror
it in supabase/schema.sql; at lines 58-62, add events.requires_approval with its
specified default in both locations, or remove the corresponding references
while preserving confirmed RSVP behavior.
- Around line 176-177: Update the grants for public.manage_event_rsvp(UUID,
UUID, TEXT) to explicitly revoke EXECUTE from PUBLIC before granting it to
authenticated and service_role, ensuring anonymous callers cannot invoke this
SECURITY DEFINER function.

In `@supabase/tests/rsvp_concurrency.test.sql`:
- Line 17: Remove the blanket GRANT ALL statement from the RSVP concurrency test
setup. Keep the test focused on its assertions and do not replace it with
broader schema-wide privileges.
- Around line 52-99: Replace the sequential RSVP assertions in the concurrency
test with a multi-session concurrency harness using pg_isolation_tester, dblink,
or parallel RPC calls, so multiple users attempt RSVPs simultaneously. Validate
that exactly max_attendees (including the 50-capacity/51-attempt case) succeed,
the remaining attempt returns EVENT_FULL, and the final event_rsvps count never
exceeds capacity; retain cancellation and freed-spot coverage where applicable.
- Line 61: Correct the malformed event UUID argument in the manage_event_rsvp
call within the concurrency test, reducing the final group to a valid
12-hex-digit UUID while preserving the intended event identifier and all other
test inputs.

---

Nitpick comments:
In `@graphql/resolvers/index.ts`:
- Around line 213-217: Deprecate the snake_case Event fields max_attendees and
available_spots in the GraphQL schema while retaining maxAttendees and
availableSpots as the preferred fields. Add appropriate `@deprecated` metadata to
the snake_case variants without changing their existing data behavior.

In `@src/graphql/server.test.ts`:
- Around line 78-109: Update the rpc mock in the GraphQL test to add evt-error
and evt-null-data responses, exercising the resolver’s error throw and fallback
defaults in rsvpToEvent. Use a non-null error with a message for evt-error and
null data for evt-null-data, while preserving existing RSVP behavior. Also
branch on args.p_action so CANCEL requests receive distinguishable mock
behavior.

In `@supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql`:
- Around line 139-147: Update the CANCEL/REMOVE/UNRSVP branch to mark the
matching event_rsvps row with status 'CANCELLED' instead of deleting it. Track
the affected-row count and return NOT_RSVPED when no row exists for the
effective user; only report cancellation success after an update, while
preserving the existing RSVP recount behavior.

In `@supabase/schema.sql`:
- Around line 102-103: Add a database CHECK constraint to the available_spots
column definition requiring values to be greater than or equal to zero, while
preserving its nullable behavior and the existing version definition. Ensure
this constraint applies independently of the RPC logic to protect all writers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 23cda6da-a426-4cb4-a1ef-3d9be46c8e65

📥 Commits

Reviewing files that changed from the base of the PR and between d5485d7 and db29cfe.

📒 Files selected for processing (5)
  • graphql/resolvers/index.ts
  • src/graphql/server.test.ts
  • supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql
  • supabase/schema.sql
  • supabase/tests/rsvp_concurrency.test.sql

Comment on lines +11 to +19
UPDATE public.events e
SET available_spots = CASE
WHEN e.max_attendees IS NULL THEN NULL
ELSE GREATEST(0, e.max_attendees - (
SELECT COUNT(*) FROM public.event_rsvps r
WHERE r.event_id = e.id AND (r.status IS NULL OR r.status NOT IN ('CANCELLED', 'REJECTED'))
))
END
WHERE e.available_spots IS NULL AND e.max_attendees IS NOT NULL;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔴 Critical | 🏗️ Heavy lift

The new RPC references two columns that don't exist in supabase/schema.sql. event_rsvps.status and events.requires_approval are absent from the table definitions (lines 141-148 and 88-109), so the migration's backfill fails immediately and the function body fails on every call. Root cause: neither column is created by this PR.

  • supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql#L11-L19: add ALTER TABLE public.event_rsvps ADD COLUMN IF NOT EXISTS status TEXT NOT NULL DEFAULT 'CONFIRMED'; before the backfill, and mirror it in supabase/schema.sql, or remove the status filters entirely.
  • supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql#L58-L62: add requires_approval BOOLEAN NOT NULL DEFAULT FALSE to events in both this migration and supabase/schema.sql, or drop requires_approval from the SELECT ... INTO and hardcode 'CONFIRMED'.
📍 Affects 1 file
  • supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql#L11-L19 (this comment)
  • supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql#L58-L62
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql` around
lines 11 - 19, The migration references missing event_rsvps.status and
events.requires_approval columns. At
supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql lines 11-19,
add event_rsvps.status with the specified default before the backfill and mirror
it in supabase/schema.sql; at lines 58-62, add events.requires_approval with its
specified default in both locations, or remove the corresponding references
while preserving confirmed RSVP behavior.

Comment on lines +23 to +31
CREATE OR REPLACE FUNCTION public.manage_event_rsvp(
p_event_id UUID,
p_user_id UUID DEFAULT auth.uid(),
p_action TEXT DEFAULT 'RSVP'
)
RETURNS JSONB
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Any caller can RSVP or cancel on behalf of an arbitrary user. The actor is never bound to the authenticated session at either layer: the RPC runs SECURITY DEFINER (bypassing RLS) and trusts p_user_id, and the resolver forwards a client-supplied userId verbatim.

  • supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql#L23-L31: reject the call when p_user_id differs from auth.uid() unless the caller is service_role.
  • graphql/resolvers/index.ts#L438-L458: derive the user id from the GraphQL request context instead of the userId argument, and remove or admin-gate that argument in the rsvpToEvent schema field.
📍 Affects 2 files
  • supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql#L23-L31 (this comment)
  • graphql/resolvers/index.ts#L438-L458
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql` around
lines 23 - 31, Bind RSVP mutations to the authenticated actor at both layers: in
supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql, update
manage_event_rsvp to reject mismatched p_user_id unless the caller is
service_role; in graphql/resolvers/index.ts lines 438-458, make rsvpToEvent
derive the user ID from request context, and remove or admin-gate the
client-supplied userId schema argument.

Comment on lines +176 to +177
GRANT EXECUTE ON FUNCTION public.manage_event_rsvp(UUID, UUID, TEXT) TO authenticated;
GRANT EXECUTE ON FUNCTION public.manage_event_rsvp(UUID, UUID, TEXT) TO service_role;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Revoke default PUBLIC EXECUTE on this SECURITY DEFINER function.

Postgres grants EXECUTE to PUBLIC by default, so anon can invoke it regardless of these explicit grants.

🔒 Tighten grants
+REVOKE ALL ON FUNCTION public.manage_event_rsvp(UUID, UUID, TEXT) FROM PUBLIC;
 GRANT EXECUTE ON FUNCTION public.manage_event_rsvp(UUID, UUID, TEXT) TO authenticated;
 GRANT EXECUTE ON FUNCTION public.manage_event_rsvp(UUID, UUID, TEXT) TO service_role;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
GRANT EXECUTE ON FUNCTION public.manage_event_rsvp(UUID, UUID, TEXT) TO authenticated;
GRANT EXECUTE ON FUNCTION public.manage_event_rsvp(UUID, UUID, TEXT) TO service_role;
REVOKE ALL ON FUNCTION public.manage_event_rsvp(UUID, UUID, TEXT) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.manage_event_rsvp(UUID, UUID, TEXT) TO authenticated;
GRANT EXECUTE ON FUNCTION public.manage_event_rsvp(UUID, UUID, TEXT) TO service_role;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@supabase/migrations/20260729120000_concurrency_rsvp_mutation.sql` around
lines 176 - 177, Update the grants for public.manage_event_rsvp(UUID, UUID,
TEXT) to explicitly revoke EXECUTE from PUBLIC before granting it to
authenticated and service_role, ensuring anonymous callers cannot invoke this
SECURITY DEFINER function.

SELECT plan(8);

-- Grant schema privileges
GRANT ALL ON ALL TABLES IN SCHEMA public TO authenticated, anon;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Drop this blanket GRANT ALL.

Granting all privileges on every public table to authenticated and anon is unrelated to the assertions and, if this file is ever run outside a rolled-back transaction, materially weakens the schema's posture.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@supabase/tests/rsvp_concurrency.test.sql` at line 17, Remove the blanket
GRANT ALL statement from the RSVP concurrency test setup. Keep the test focused
on its assertions and do not replace it with broader schema-wide privileges.

Comment on lines +52 to +99
-- Test 2: User 1 RSVPs successfully
SELECT is(
(public.manage_event_rsvp('e1000000-0000-0000-0000-000000000200', 'e1000000-0000-0000-0000-000000000001', 'RSVP')->>'code'),
'RSVP_SUCCESS',
'User 1 should successfully RSVP for available spot 1 of 2'
);

-- Test 3: User 1 tries duplicate RSVP -> ALREADY_RSVPED
SELECT is(
(public.manage_event_rsvp('e1000000-0000-0000-0000-0000000000200', 'e1000000-0000-0000-0000-000000000001', 'RSVP')->>'code'),
'ALREADY_RSVPED',
'Duplicate RSVP from User 1 should return ALREADY_RSVPED'
);

-- Test 4: User 2 RSVPs successfully (2nd spot filled, max_attendees = 2)
SELECT is(
(public.manage_event_rsvp('e1000000-0000-0000-0000-000000000200', 'e1000000-0000-0000-0000-000000000002', 'RSVP')->>'code'),
'RSVP_SUCCESS',
'User 2 should successfully RSVP for spot 2 of 2'
);

-- Test 5: User 3 tries to RSVP when event is at capacity (2/2 filled) -> EVENT_FULL
SELECT is(
(public.manage_event_rsvp('e1000000-0000-0000-0000-000000000200', 'e1000000-0000-0000-0000-000000000003', 'RSVP')->>'code'),
'EVENT_FULL',
'User 3 RSVP attempt when 2/2 spots filled should return EVENT_FULL'
);

-- Test 6: Verify total count of RSVPs in table remains strictly 2 (51st/3rd RSVP blocked)
SELECT results_eq(
'SELECT COUNT(*)::integer FROM public.event_rsvps WHERE event_id = ''e1000000-0000-0000-0000-000000000200''',
ARRAY[2],
'Total RSVP count in table must equal max_attendees capacity (2)'
);

-- Test 7: User 1 cancels RSVP -> spot is freed
SELECT is(
(public.manage_event_rsvp('e1000000-0000-0000-0000-000000000200', 'e1000000-0000-0000-0000-000000000001', 'CANCEL')->>'code'),
'CANCEL_SUCCESS',
'User 1 RSVP cancellation should succeed and free a spot'
);

-- Test 8: User 3 can now RSVP into the newly freed spot
SELECT is(
(public.manage_event_rsvp('e1000000-0000-0000-0000-000000000200', 'e1000000-0000-0000-0000-000000000003', 'RSVP')->>'code'),
'RSVP_SUCCESS',
'User 3 should successfully RSVP into the freed spot'
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

These tests are sequential, not concurrent — the acceptance criteria are not covered.

All eight assertions run in a single session/transaction, so SELECT ... FOR UPDATE never contends and the "50 spots cannot receive 51 RSVPs" criterion from #1363 is untested. pgTAP alone cannot do this; a multi-session harness (e.g. pg_isolation_tester/dblink, or a Node script firing N parallel RPC calls) is needed. Want me to open an issue for the concurrency harness?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@supabase/tests/rsvp_concurrency.test.sql` around lines 52 - 99, Replace the
sequential RSVP assertions in the concurrency test with a multi-session
concurrency harness using pg_isolation_tester, dblink, or parallel RPC calls, so
multiple users attempt RSVPs simultaneously. Validate that exactly max_attendees
(including the 50-capacity/51-attempt case) succeed, the remaining attempt
returns EVENT_FULL, and the final event_rsvps count never exceeds capacity;
retain cancellation and freed-spot coverage where applicable.


-- Test 3: User 1 tries duplicate RSVP -> ALREADY_RSVPED
SELECT is(
(public.manage_event_rsvp('e1000000-0000-0000-0000-0000000000200', 'e1000000-0000-0000-0000-000000000001', 'RSVP')->>'code'),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Malformed UUID — the whole test file aborts here.

'e1000000-0000-0000-0000-0000000000200' has 13 hex digits in the last group; Postgres raises invalid input syntax for type uuid.

🐛 Fix the event id
-  (public.manage_event_rsvp('e1000000-0000-0000-0000-0000000000200', 'e1000000-0000-0000-0000-000000000001', 'RSVP')->>'code'),
+  (public.manage_event_rsvp('e1000000-0000-0000-0000-000000000200', 'e1000000-0000-0000-0000-000000000001', 'RSVP')->>'code'),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
(public.manage_event_rsvp('e1000000-0000-0000-0000-0000000000200', 'e1000000-0000-0000-0000-000000000001', 'RSVP')->>'code'),
(public.manage_event_rsvp('e1000000-0000-0000-0000-000000000200', 'e1000000-0000-0000-0000-000000000001', 'RSVP')->>'code'),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@supabase/tests/rsvp_concurrency.test.sql` at line 61, Correct the malformed
event UUID argument in the manage_event_rsvp call within the concurrency test,
reducing the final group to a valid 12-hex-digit UUID while preserving the
intended event identifier and all other test inputs.

@krushit1307 krushit1307 added good-pr Blue All CI checks are passing on this PR labels Jul 29, 2026
@krushit1307
krushit1307 merged commit 9bd83af into krushit1307:main Jul 29, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Blue All CI checks are passing on this PR ECSoC26-L3 ECSoC26 Elite Coders Summer Of Code'26 - Open Source Program good-pr optimization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Mutations for Managing Event RSVPs with Optimistic Concurrency

2 participants