Skip to content

Conversation

@fogelito
Copy link
Contributor

@fogelito fogelito commented Aug 3, 2025

Summary by CodeRabbit

  • Bug Fixes

    • Ensured that newly created documents always include an empty permissions attribute when permissions are not specified.
    • Improved batch update logic to prevent unnecessary permissions updates when permissions remain unchanged.
  • Tests

    • Added and enhanced tests to verify correct handling of empty and updated permissions attributes during document creation and updates.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 3, 2025

Walkthrough

This change refines how document permissions are handled during creation and batch updates. It ensures that all new documents explicitly have a $permissions attribute, adjusts encoding/decoding to skip permissions transformation, and introduces logic to selectively skip permissions updates in batch operations based on document state. Tests are updated and expanded to validate these behaviors.

Changes

Cohort / File(s) Change Summary
SQL Adapter Permissions Update Logic
src/Database/Adapter/SQL.php
Updated updateDocuments to check for permissions updates using offsetExists('$permissions') and to skip updating permissions for documents with $skipPermissionsUpdate set to true.
Database Permissions Initialization and Batch Update Logic
src/Database/Database.php
Ensured new documents always have a $permissions attribute; changed batch update logic to use indexed iteration and a $skipPermissionsUpdate flag; adjusted encode, decode, and casting methods to skip permissions processing.
Document Attribute Removal
src/Database/Document.php
Simplified removeAttribute to directly unset the attribute without checking for existence.
E2E Document Permissions Test
tests/e2e/Adapter/Scopes/DocumentTests.php
Enhanced testSkipPermissions to assert that all created/updated documents have an explicit empty $permissions attribute.
E2E Permissions Update and Unset Test
tests/e2e/Adapter/Scopes/PermissionTests.php
Added testUnsetPermissions to verify correct behavior when updating and unsetting permissions, including checks for the $skipPermissionsUpdate flag and document visibility under permissions.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Database
    participant SQLAdapter

    Client->>Database: createDocument / createDocuments
    Database->>Database: Ensure $permissions is set (empty if missing)
    Database->>SQLAdapter: Insert document(s) with $permissions

    Client->>Database: updateDocuments (with/without permissions)
    Database->>Database: For each document, compare permissions
    Database->>Database: Set $skipPermissionsUpdate if unchanged
    Database->>SQLAdapter: updateDocuments(batch)
    SQLAdapter->>SQLAdapter: For each doc, skip permissions update if $skipPermissionsUpdate
    SQLAdapter->>Database: Return updated docs
    Database->>Database: Remove $skipPermissionsUpdate from docs
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~18 minutes

Possibly related PRs

Suggested reviewers

  • abnegate

Poem

Hopping through code with a whisk of my tail,
Permissions set right so no tests will fail.
Skipping and setting, with flags in the breeze,
Documents updated with elegant ease.
A carrot for each test that passes tonight—
This bunny reviews with delight! 🥕

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11b0d98 and 3d8c85b.

📒 Files selected for processing (4)
  • src/Database/Adapter/SQL.php (2 hunks)
  • src/Database/Database.php (8 hunks)
  • tests/e2e/Adapter/Scopes/DocumentTests.php (1 hunks)
  • tests/e2e/Adapter/Scopes/PermissionTests.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/Database/Adapter/SQL.php
  • tests/e2e/Adapter/Scopes/DocumentTests.php
  • src/Database/Database.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Adapter Tests (Mirror)
  • GitHub Check: Adapter Tests (Pool)
  • GitHub Check: Adapter Tests (SharedTables/MySQL)
  • GitHub Check: Adapter Tests (SharedTables/Postgres)
  • GitHub Check: Adapter Tests (SharedTables/SQLite)
  • GitHub Check: Adapter Tests (SharedTables/MariaDB)
  • GitHub Check: Adapter Tests (MariaDB)
  • GitHub Check: Adapter Tests (Postgres)
  • GitHub Check: Adapter Tests (SQLite)
  • GitHub Check: Adapter Tests (MySQL)
  • GitHub Check: Unit Test
🔇 Additional comments (4)
tests/e2e/Adapter/Scopes/PermissionTests.php (4)

17-57: LGTM! Comprehensive test setup for document creation with permissions.

The initial test setup correctly creates documents with full permissions and validates both the document attributes and permissions are properly stored. The use of batch operations with createDocuments and the callback pattern for result collection is well-implemented.


59-89: LGTM! Proper validation of permission preservation during updates.

This section correctly tests that when no permissions are specified in an update operation, the existing permissions are preserved. The test validates both the callback results and the persisted documents, ensuring comprehensive coverage.


91-129: LGTM! Effective testing of permission modifications during updates.

This section properly tests permission updates by removing the delete permission and verifies:

  • The permission change is applied correctly
  • Document attributes are updated as expected
  • The $skipPermissionsUpdate flag is not present (confirming permissions were actually updated)

The test logic aligns well with the PR's objective of handling permission updates selectively.


131-168: LGTM! Thorough validation of permission unsetting behavior.

This section excellently tests the complete removal of permissions by:

  • Setting permissions to an empty array
  • Verifying documents become inaccessible with authorization enabled (count = 0)
  • Confirming documents still exist when authorization is disabled (count = 3)
  • Validating the absence of the $skipPermissionsUpdate flag

This comprehensive approach ensures the permission system works correctly at both the storage and access control levels.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-update-documents

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 2

🔭 Outside diff range comments (1)
src/Database/Database.php (1)

6348-6350: Skipping JSON filter for $permissions may break persistence

$permissions is still declared as type=string with the json filter (Line 219).
By short-circuiting the encode path here we now try to persist a PHP array into a string column, bypassing json_encode. Drivers such as PDO/MySQL will error with “Array to string conversion”.

Either:

-            if ($key === '$permissions') {
-                continue;
-            }
+            // Keep applying json filter so DB still receives a string
+            // but skip the automatic []-when-empty logic.
+            if ($key === '$permissions' && !in_array('json', $filters, true)) {
+                continue;
+            }

or change the column type and adapter logic to accept native JSON.

♻️ Duplicate comments (1)
src/Database/Database.php (1)

3715-3718: Duplicate logic – consider extracting helper

The same if-empty-then-[] block now exists in both createDocument() and createDocuments(). Factor it out (e.g. applyDefaultPermissions(Document $d)) to avoid divergence later.

🧹 Nitpick comments (1)
src/Database/Adapter/SQL.php (1)

434-442: Remove or implement the commented optimization code.

The commented-out permission comparison optimization should either be:

  1. Removed if not needed
  2. Properly implemented and tested if the optimization is valuable

Dead code should not remain in the codebase.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 065b481 and 11b0d98.

📒 Files selected for processing (7)
  • phpunit.xml (1 hunks)
  • src/Database/Adapter/SQL.php (3 hunks)
  • src/Database/Database.php (7 hunks)
  • src/Database/Document.php (1 hunks)
  • tests/e2e/Adapter/Base.php (1 hunks)
  • tests/e2e/Adapter/Scopes/DocumentTests.php (1 hunks)
  • tests/e2e/Adapter/Scopes/PermissionTests.php (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: in postgresql adapter methods like getupsertstatement, complexity for database-specific sql generati...
Learnt from: ArnabChatterjee20k
PR: utopia-php/database#613
File: src/Database/Adapter/Postgres.php:1254-1319
Timestamp: 2025-07-01T11:31:37.438Z
Learning: In PostgreSQL adapter methods like getUpsertStatement, complexity for database-specific SQL generation is acceptable when the main business logic is properly separated in the parent SQL adapter class, following the adapter pattern where each database adapter handles its own SQL syntax requirements.

Applied to files:

  • src/Database/Adapter/SQL.php
🔇 Additional comments (11)
phpunit.xml (1)

10-10: Verify if this configuration change should be permanent.

The stopOnFailure attribute has been changed to "true", which will halt test execution on the first failure. This is typically used during debugging but may not be desired in CI/CD pipelines where you want to see all test failures.

Is this change intentional for production, or should it be reverted before merging?

src/Database/Document.php (1)

279-285: LGTM! Good simplification.

Removing the conditional check before unset() is a good optimization. In PHP, unset() is safe to call on non-existent array keys and doesn't produce errors, making the existence check unnecessary.

tests/e2e/Adapter/Base.php (1)

20-23: Verify that disabling test suites is intentional and temporary.

Four major test trait suites have been commented out (CollectionTests, DocumentTests, AttributeTests, IndexTests), which significantly reduces test coverage. This appears to be for focusing on permission-related testing during development.

Please confirm:

  1. Is this change temporary for debugging/development purposes?
  2. Should these test suites be re-enabled before merging?
  3. Are there specific failures in these test suites that need to be addressed?

Consider using test filtering or separate test configurations instead of commenting out entire test suites to maintain coverage.

tests/e2e/Adapter/Scopes/DocumentTests.php (1)

453-456: LGTM! Proper test enhancement for permission initialization.

The added assertions correctly verify that documents returned by createOrUpdateDocuments have the $permissions key present and initialized as an empty array. This aligns well with the broader changes mentioned in the AI summary to ensure $permissions is always initialized in the database layer.

The test enhancement follows good practices:

  • Uses appropriate PHPUnit assertions (assertArrayHasKey and assertEquals)
  • Tests both the presence of the key and its expected value
  • Complements the existing test logic without disrupting the flow
src/Database/Adapter/SQL.php (2)

430-432: LGTM! Permission detection logic improved.

The change from !empty($updates->getPermissions()) to $updates->offsetExists('$permissions') correctly handles cases where permissions are explicitly set to an empty array, ensuring the attribute is properly encoded even when permissions are being cleared.


498-498: LGTM! Consistent permission handling logic.

The change maintains consistency with the earlier modification on line 430, ensuring that permission update logic is triggered whenever the $permissions key exists, supporting proper handling of permission removal scenarios.

tests/e2e/Adapter/Scopes/PermissionTests.php (1)

17-137: Excellent test coverage for permission handling.

This test method provides comprehensive coverage of the permission update functionality:

  • ✅ Creates documents with permissions
  • ✅ Validates permission preservation during updates without permission changes
  • ✅ Tests explicit permission removal via empty array
  • ✅ Verifies authorization behavior after permission removal
  • ✅ Uses Authorization::disable() to confirm documents still exist

The test logic is well-structured and thoroughly validates the core permission handling changes.

src/Database/Database.php (4)

4437-4459: 👍 Rewriting the loop removes the reference trap

Switching to foreach ($batch as $index => $document) and assigning back with $batch[$index] avoids the by-reference side-effects that previously corrupted $batch. Nice clean-up.


6429-6432: Decode still skips $permissions – verify symmetry

Once the encode side is fixed (see previous comment), keeping decode / casting skipped is fine because callers expect an array.
Just make sure the adapter returns the decoded array; otherwise the application will start receiving raw JSON strings.


6492-6494: Casting exclusion looks good

Since $permissions is an array of strings there’s nothing to cast; excluding it here avoids an unnecessary json_decode branch.


3612-3615: Empty permissions default may lock documents down
Automatically defaulting a missing $permissions value to an empty array will deny all access (read/update/delete) on the newly created documents—often even to their creator—unless you’ve layered on higher-level ACL rules. Please confirm that this “zero-access” behavior is intentional. Most schemas instead:

  • inherit the parent collection’s default roles, or
  • grant at least a read (and often write) right to the creating user.

Locations to review:

  • src/Database/Database.php Lines 3612–3615
  • src/Database/Database.php Lines 3715–3718

If you do intend tighter defaults, consider documenting this ACL change. Otherwise, adjust the fallback to include the creator’s role or your collection’s standard defaults.

@abnegate abnegate merged commit 400eb89 into main Aug 5, 2025
15 checks passed
@abnegate abnegate deleted the fix-update-documents branch August 5, 2025 05:05
@coderabbitai coderabbitai bot mentioned this pull request Sep 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants