Skip to content

fix(actions): use upsert/deleteMany in toggleStarMarked to prevent constraint errors - #520

Open
Xenon010101 wants to merge 1 commit into
piyushdotcomm:mainfrom
Xenon010101:fix/star-toggle-race-condition
Open

fix(actions): use upsert/deleteMany in toggleStarMarked to prevent constraint errors#520
Xenon010101 wants to merge 1 commit into
piyushdotcomm:mainfrom
Xenon010101:fix/star-toggle-race-condition

Conversation

@Xenon010101

Copy link
Copy Markdown

What changed

Replaced db.starMark.create/delete with db.starMark.upsert/deleteMany in toggleStarMarked across both the playground and dashboard action modules.

Closes #518

Why

db.starMark.create throws a P2002 unique constraint violation when a user clicks the star button twice in rapid succession, because the first click already inserted the row with the same @@unique([userId, playgroundId]) key. The error is caught and returned as { success: false }, but the user gets no meaningful feedback — the toggle just silently fails.

The inverse path has the same problem: db.starMark.delete throws P2025 (record not found) when unstarring a playground that was already unstarred.

Fix

  • Star: createupsert with update: { isMarked: true } — second click is a no-op, no constraint error.
  • Unstar: deletedeleteMany — no-op when no matching row exists, no P2025 error.

Applied to both modules/playground/actions/index.ts and modules/dashboard/actions/index.ts which had identical copies of the bug.

Verification

  • npm run lint — 0 errors
  • npm test — 112/112 tests pass
  • npm run build — builds successfully

…nstraint errors

db.starMark.create throws a P2002 unique constraint violation when
the user clicks star twice rapidly, because the first click already
inserted the row. db.starMark.delete throws P2025 when the record
does not exist (unstar when already unstarred).

Replace create with upsert (idempotent on repeated star clicks) and
delete with deleteMany (no-op when no matching row exists). Applied
to both the playground and dashboard action modules.

Closes piyushdotcomm#518
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@Xenon010101, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2f1f90f9-5047-4275-a0b3-cb6b99ce6b23

📥 Commits

Reviewing files that changed from the base of the PR and between 4ffe26f and 14e9dfe.

📒 Files selected for processing (2)
  • modules/dashboard/actions/index.ts
  • modules/playground/actions/index.ts
✨ 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.

@github-actions

Copy link
Copy Markdown

👋 Thanks for opening a PR, @Xenon010101!

Your PR has entered the 🚦 PR Review Pipeline.

Standard PR detected — your PR will follow the standard review pipeline.


What happens next

Stage Reviewer Checks
Stage 1 — Automated Validation 🤖 Bot DCO · Format · AI/Slop · Duplicate
Stage 2 — Human Review 👥 Maintainer Code + Quality Review
Stage 3 — PA / Maintainer Review 🔑 Project Admin Final Merge Decision

A pipeline status comment will appear below and update automatically as your PR progresses.


While you wait

  • Sign all commits (git commit -s)
  • Link your issue (Closes #123)
  • Use a feature branch (not main)
  • Avoid unrelated changes

This comment is posted only once.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Fix star toggle race: use upsert/deleteMany to avoid Prisma constraint errors

🐞 Bug fix 🕐 10-20 Minutes

Grey Divider

AI Description

• Make starring idempotent by switching star creation to Prisma upsert.
• Make unstarring safe by switching delete to deleteMany (no-op if already unstarred).
• Apply the same fix to both dashboard and playground action modules.
Diagram

graph TD
  UI["Star toggle UI"] --> DASH["Dashboard action"] --> PRISMA["Prisma client"] --> DB[("starMark table")]
  UI --> PLAY["Playground action"] --> PRISMA
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Catch-and-ignore Prisma P2002/P2025 errors
  • ➕ Minimal code churn; preserves existing create/delete calls
  • ➕ Allows custom handling (e.g., user-facing messaging)
  • ➖ Still relies on exceptions for control flow under normal user behavior
  • ➖ Harder to keep consistent across modules; easy to miss similar call sites
2. UI-side debouncing / disable button during in-flight request
  • ➕ Reduces duplicate requests and improves perceived UX
  • ➖ Doesn’t fully eliminate server-side races (multi-tab, retries, latency)
  • ➖ Still needs server-side idempotency to be correct

Recommendation: Keep the current approach. Using upsert for starring and deleteMany for unstarring makes the mutation idempotent at the persistence layer, directly addressing the unique constraint (P2002) and record-not-found (P2025) failure modes without relying on exception handling or client timing.

Files changed (2) +12 / -28

Bug fix (2) +12 / -28
index.tsMake toggleStarMarked idempotent with upsert/deleteMany +6/-14

Make toggleStarMarked idempotent with upsert/deleteMany

• Replaces starMark.create with starMark.upsert to avoid unique constraint violations when starring repeatedly. Replaces starMark.delete with starMark.deleteMany to avoid record-not-found errors when unstarring an already-unstarred playground.

modules/dashboard/actions/index.ts

index.tsAlign toggleStarMarked with safe upsert/deleteMany semantics +6/-14

Align toggleStarMarked with safe upsert/deleteMany semantics

• Mirrors the dashboard fix by using upsert for starring and deleteMany for unstarring. Prevents constraint and not-found errors during rapid or repeated toggles.

modules/playground/actions/index.ts

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Qodo Logo

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.

fix(actions): toggleStarMarked uses create/delete instead of upsert — unique constraint error on rapid clicks

1 participant