Skip to content

Comments

fix: prisma serialisation errors#24452

Merged
keithwillcode merged 3 commits intomainfrom
fix/pbac-serilization
Oct 14, 2025
Merged

fix: prisma serialisation errors#24452
keithwillcode merged 3 commits intomainfrom
fix/pbac-serilization

Conversation

@sean-brydon
Copy link
Member

What does this PR do?

Fixes an issue found by @supalarry during PBAC api v2 implementation

@graphite-app graphite-app bot requested a review from a team October 14, 2025 12:45
@keithwillcode keithwillcode added consumer core area: core, team members only labels Oct 14, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 14, 2025

Walkthrough

The PermissionRepository permission-check query was rewritten to use a JSONB-based approach: permission pairs are serialized (JSON.stringify) and expanded via jsonb_array_elements, then validated against RolePermission rows using EXISTS per required permission. The previous multi-CASE, WITH, and UNION ALL SQL logic and intermediate arrays were removed. External behavior is unchanged: returns true only if all requested permissions are satisfied; empty-permissions validation remains. An integration test suite was added covering exact matches, wildcards, universal wildcard, empty inputs, non-existent roles, and complex multi-rule scenarios. No exported/public API signatures changed.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (2 inconclusive)
Check name Status Explanation Resolution
Title Check ❓ Inconclusive The title refers to a valid aspect of the changeset by mentioning Prisma serialization errors but is overly broad and omits the PBAC permission checking context and core SQL rewrite, making it unclear to someone scanning the history what exactly was fixed. Please revise the title to clearly reference the affected feature and change, for example “fix: PBAC PermissionRepository Prisma serialization errors,” so that the context and primary change are immediately evident.
Description Check ❓ Inconclusive The description notes that it fixes an issue found during PBAC API v2 implementation, which is related to the changeset, but it remains very terse and does not convey what was changed or why. Consider expanding the description to summarize the main changes, such as the JSONB rewrite in PermissionRepository, the added serialization step, and the new integration tests, to provide meaningful context.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/pbac-serilization

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 and usage tips.

@dosubot dosubot bot added the 🐛 bug Something isn't working label Oct 14, 2025
SELECT 1 as match FROM "RolePermission"
WHERE "roleId" = ${roleId} AND ("resource", "action") = ANY(${resourceActions})
// Check if each requested permission is satisfied by at least one role permission
const matchingPermissions = await this.client.$queryRaw<[{ count: bigint }]>`
Copy link
Member Author

Choose a reason for hiding this comment

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

packages/features/pbac/infrastructure/repositories/PermissionRepository.ts L247

We also do this here

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
packages/features/pbac/infrastructure/repositories/PermissionRepository.ts (2)

24-33: Use select instead of include in Prisma queries.

Per project guidelines, avoid include; select only required fields from related models.

-    const memberships = await this.client.membership.findMany({
-      where: { userId },
-      include: {
-        customRole: {
-          include: {
-            permissions: true,
-          },
-        },
-      },
-    });
+    const memberships = await this.client.membership.findMany({
+      where: { userId },
+      select: {
+        teamId: true,
+        customRole: {
+          select: {
+            id: true,
+            permissions: true,
+          },
+        },
+      },
+    });

As per coding guidelines


140-156: Alias JSONB element column for clarity: use AS required_perm(perm) and update references to perm->>'resource' and perm->>'action'; the existing @@unique([roleId,resource,action]) already provides the needed composite index.

packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration.test.ts (2)

18-45: Use a single unique suffix per test run to reduce collision risk.

Date.now() called multiple times can repeat within the same ms. Generate one suffix and reuse it for email/username/slug.

-    // Create test user
-    const testUser = await prisma.user.create({
+    const suffix = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
+    // Create test user
+    const testUser = await prisma.user.create({
       data: {
-        email: `test-${Date.now()}@example.com`,
-        username: `testuser-${Date.now()}`,
+        email: `test-${suffix}@example.com`,
+        username: `testuser-${suffix}`,
       },
     });
@@
-    const testTeam = await prisma.team.create({
+    const testTeam = await prisma.team.create({
       data: {
-        name: `Test Team ${Date.now()}`,
-        slug: `test-team-${Date.now()}`,
+        name: `Test Team ${suffix}`,
+        slug: `test-team-${suffix}`,
       },
     });

66-68: Double‑check global Prisma client lifecycle in tests.

Disconnecting prisma in afterAll can interfere with other test suites sharing the same client. Prefer centralized teardown or a locally instantiated client per suite.

Would you like me to generate a Vitest globalSetup/globalTeardown example to manage Prisma once?

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 947b05b and bb5d2fb.

📒 Files selected for processing (2)
  • packages/features/pbac/infrastructure/repositories/PermissionRepository.ts (1 hunks)
  • packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration.test.ts
  • packages/features/pbac/infrastructure/repositories/PermissionRepository.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration.test.ts
  • packages/features/pbac/infrastructure/repositories/PermissionRepository.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration.test.ts
  • packages/features/pbac/infrastructure/repositories/PermissionRepository.ts
**/*Repository.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Repository files must include Repository suffix, prefix with technology if applicable (e.g., PrismaAppRepository.ts), and use PascalCase matching the exported class

Files:

  • packages/features/pbac/infrastructure/repositories/PermissionRepository.ts
🧬 Code graph analysis (1)
packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration.test.ts (2)
packages/features/pbac/infrastructure/repositories/PermissionRepository.ts (1)
  • PermissionRepository (15-286)
packages/features/pbac/domain/types/permission-registry.ts (1)
  • PermissionString (67-67)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Install dependencies / Yarn install & cache
🔇 Additional comments (2)
packages/features/pbac/infrastructure/repositories/PermissionRepository.ts (1)

136-138: Good move: serialize permission pairs to JSONB.

Passing a JSON string as a bound parameter and casting to jsonb avoids serialization errors and keeps the raw SQL parameterized (no injection risk).

packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration.test.ts (1)

70-174: Solid integration coverage for the JSONB‑based permission checks.

Scenarios comprehensively cover exact matches, wildcards, universal wildcard, partial matches, empty input, and bug reproduction. LGTM.

Also applies to: 175-206, 208-219, 221-237, 239-255, 257-273, 275-303

Copy link
Member Author

Choose a reason for hiding this comment

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

Added an intergration test to ensure we correctly test the checkPermission logic sql is working as expected. It s a bit complex and mocking it as a unit missed a serialisation error.

@vercel
Copy link

vercel bot commented Oct 14, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
cal Ignored Ignored Oct 14, 2025 1:39pm
cal-eu Ignored Ignored Oct 14, 2025 1:39pm

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

🧹 Nitpick comments (3)
packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration-test.ts (3)

18-45: Use a unique suffix and select only the needed fields on create

Reduce collision risk and align with “select only what you need” for Prisma responses. Return only ids.

As per coding guidelines

   beforeEach(async () => {
-    // Create test user
-    const testUser = await prisma.user.create({
-      data: {
-        email: `test-${Date.now()}@example.com`,
-        username: `testuser-${Date.now()}`,
-      },
-    });
+    const unique = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
+    // Create test user
+    const testUser = await prisma.user.create({
+      data: {
+        email: `test-${unique}@example.com`,
+        username: `testuser-${unique}`,
+      },
+      select: { id: true },
+    });
     testUserId = testUser.id;
 
     // Create test team
     const testTeam = await prisma.team.create({
       data: {
-        name: `Test Team ${Date.now()}`,
-        slug: `test-team-${Date.now()}`,
+        name: `Test Team ${unique}`,
+        slug: `test-team-${unique}`,
       },
-    });
+      select: { id: true },
+    });
     testTeamId = testTeam.id;
 
     // Create test role
     const testRole = await prisma.role.create({
       data: {
-        name: `Test Role ${Date.now()}`,
+        name: `Test Role ${unique}`,
         teamId: testTeamId,
       },
-    });
+      select: { id: true },
+    });
     testRoleId = testRole.id;
   });

47-64: Wrap cleanup in a single transaction for speed and atomicity

Consolidates multiple round-trips and ensures consistent teardown.

   afterEach(async () => {
-    // Clean up test data
-    await prisma.rolePermission.deleteMany({
-      where: { roleId: testRoleId },
-    });
-    await prisma.membership.deleteMany({
-      where: { userId: testUserId },
-    });
-    await prisma.role.deleteMany({
-      where: { id: testRoleId },
-    });
-    await prisma.team.deleteMany({
-      where: { id: testTeamId },
-    });
-    await prisma.user.deleteMany({
-      where: { id: testUserId },
-    });
+    // Clean up test data
+    await prisma.$transaction([
+      prisma.rolePermission.deleteMany({ where: { roleId: testRoleId } }),
+      prisma.membership.deleteMany({ where: { userId: testUserId } }),
+      prisma.role.deleteMany({ where: { id: testRoleId } }),
+      prisma.team.deleteMany({ where: { id: testTeamId } }),
+      prisma.user.deleteMany({ where: { id: testUserId } }),
+    ]);
   });

71-86: Deduplicate overlapping tests to reduce runtime

These two tests validate the same single-permission path. Consider keeping only the bug reproduction case and removing/merging the earlier one.

Also applies to: 287-303

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bb5d2fb and a311bc9.

📒 Files selected for processing (1)
  • packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration-test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration-test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration-test.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration-test.ts
🧬 Code graph analysis (1)
packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration-test.ts (2)
packages/features/pbac/infrastructure/repositories/PermissionRepository.ts (1)
  • PermissionRepository (15-286)
packages/features/pbac/domain/types/permission-registry.ts (1)
  • PermissionString (67-67)
🔇 Additional comments (1)
packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration-test.ts (1)

70-174: Strong coverage across exact, wildcard, universal, negative, and single-permission paths

The suite exercises the core matching logic well and guards against the prior serialization issue. LGTM.

Also applies to: 175-286, 306-326

…ermissionRepository.integration-test.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a311bc9 and 863608e.

📒 Files selected for processing (1)
  • packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration-test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration-test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration-test.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration-test.ts
🧬 Code graph analysis (1)
packages/features/pbac/infrastructure/repositories/__tests__/PermissionRepository.integration-test.ts (2)
packages/features/pbac/infrastructure/repositories/PermissionRepository.ts (1)
  • PermissionRepository (15-286)
packages/features/pbac/domain/types/permission-registry.ts (1)
  • PermissionString (67-67)

@sean-brydon sean-brydon requested a review from a team October 14, 2025 13:54
@github-actions
Copy link
Contributor

github-actions bot commented Oct 14, 2025

E2E results are ready!

@keithwillcode keithwillcode merged commit e26a57b into main Oct 14, 2025
63 of 65 checks passed
@keithwillcode keithwillcode deleted the fix/pbac-serilization branch October 14, 2025 18:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛 bug Something isn't working consumer core area: core, team members only ready-for-e2e size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants