Skip to content

UniqueException#10657

Open
fogelito wants to merge 8 commits into1.8.xfrom
unique-exception
Open

UniqueException#10657
fogelito wants to merge 8 commits into1.8.xfrom
unique-exception

Conversation

@fogelito
Copy link
Copy Markdown
Contributor

Added support for UniqueException to differentiate it from DuplicateException.
UniqueException extends DuplicateException for backwards compatibility. It will be thrown for all unique constraint violations except those caused by the _uid constraint.

What does this PR do?

(Provide a description of what this PR does and why it's needed.)

Test Plan

(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work. Screenshots may also be helpful.)

Related PRs and Issues

  • (Related PR or issue)

Checklist

  • Have you read the Contributing Guidelines on issues?
  • If the PR includes a change to an API's metadata (desc, label, params, etc.), does it also include updated API specs and example docs?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 16, 2025

📝 Walkthrough

Walkthrough

composer.json aliases utopia-php/database to "dev-unique-exception as 2.3.2". Two new exception constants were added: DOCUMENT_UNIQUE_VIOLATION and ROW_UNIQUE_VIOLATION. app/config/errors.php was updated to expose those exceptions as public errors with HTTP 409. Documents Action gained protected getUniqueException() to choose the appropriate constant. Documents Create now catches Utopia\Database\Exception\Unique and maps it via getUniqueException(). Tests added testUniqueUid twice (duplicate definitions) and updated assertions for duplicate-ID conflicts.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • abnegate
  • ItzNotABug

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "UniqueException" directly and accurately reflects the primary change in the pull request. The changeset adds comprehensive support for a new UniqueException type to differentiate unique constraint violations from duplicate key violations, which includes dependency updates, new error mappings, exception constants, error handling in the Create module, and test additions. The title is concise and specific enough that a teammate reviewing the commit history would clearly understand the PR introduces UniqueException functionality. While minimal in length, the title is not vague or generic—it uses a precise, descriptive term rather than placeholder language like "misc updates."
Description Check ✅ Passed The PR description is clearly related to the changeset. It explains that UniqueException support has been added to differentiate from DuplicateException, that UniqueException extends DuplicateException for backwards compatibility, and that it will be thrown for unique constraint violations except those from the _uid constraint. This description directly corresponds to the changes shown in the raw summary, including the new exception constants, error mappings, and exception handling logic. The description is neither vague nor generic—it provides specific, meaningful information about the purpose and behavior of the change.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ 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 unique-exception

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.

…que-exception

# Conflicts:
#	composer.lock
@github-actions
Copy link
Copy Markdown

github-actions bot commented Oct 16, 2025

Security Scan Results for PR

Docker Image Scan Results

Package Version Vulnerability Severity
binutils 2.44-r2 CVE-2025-5244 HIGH
binutils 2.44-r2 CVE-2025-5245 HIGH
libxml2 2.13.8-r0 CVE-2025-49794 CRITICAL
libxml2 2.13.8-r0 CVE-2025-49796 CRITICAL
libxml2 2.13.8-r0 CVE-2025-49795 HIGH
libxml2 2.13.8-r0 CVE-2025-6021 HIGH
golang.org/x/crypto v0.31.0 CVE-2025-22869 HIGH
golang.org/x/oauth2 v0.24.0 CVE-2025-22868 HIGH
stdlib 1.22.10 CVE-2025-47907 HIGH

Source Code Scan Results

🎉 No vulnerabilities found!

Copy link
Copy Markdown
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

📥 Commits

Reviewing files that changed from the base of the PR and between 2e10cd0 and 4d91f1a.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • composer.json (1 hunks)
⏰ 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). (18)
  • GitHub Check: E2E Service Test (Migrations)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Webhooks)
  • GitHub Check: E2E Service Test (Locale)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (Tokens)
  • GitHub Check: E2E Service Test (Functions)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (Projects)
  • GitHub Check: E2E Service Test (Databases/TablesDB)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: E2E Shared Mode Service Test (Dev Keys) (Shared V2)
  • GitHub Check: E2E Shared Mode Service Test (Site Screenshots) (Shared V1)
  • GitHub Check: Unit Test
  • GitHub Check: E2E General Test

@github-actions
Copy link
Copy Markdown

github-actions bot commented Oct 16, 2025

✨ Benchmark results

  • Requests per second: 1,141
  • Requests with 200 status code: 205,417
  • P99 latency: 0.172042563

⚡ Benchmark Comparison

Metric This PR Latest version
RPS 1,141 964
200 205,417 173,550
P99 0.172042563 0.219940092

Copy link
Copy Markdown
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: 4

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d91f1a and 0d95ba9.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • app/config/errors.php (2 hunks)
  • src/Appwrite/Extend/Exception.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (1 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php (3 hunks)
  • tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (3)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (1)
  • isCollectionsAPI (57-62)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Action.php (1)
  • isCollectionsAPI (48-51)
src/Appwrite/Extend/Exception.php (1)
  • Exception (7-466)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php (2)
src/Appwrite/Extend/Exception.php (1)
  • Exception (7-466)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (1)
  • getUniqueException (133-138)
app/config/errors.php (1)
src/Appwrite/Extend/Exception.php (1)
  • Exception (7-466)
tests/e2e/Services/Databases/Legacy/DatabasesBase.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Scopes/Scope.php (1)
  • getHeaders (145-145)
🪛 GitHub Actions: Linter
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php

[error] 1-1: PSR-12: ordered_imports failed. 1 style issue. (PHP CS/PHPCS lint: ordered_imports)

⏰ 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). (20)
  • GitHub Check: E2E Shared Mode Service Test (GraphQL, Shared V1)
  • GitHub Check: E2E Service Test (Storage)
  • GitHub Check: E2E Service Test (VCS)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Locale)
  • GitHub Check: E2E Service Test (Migrations)
  • GitHub Check: E2E Service Test (Webhooks)
  • GitHub Check: E2E Service Test (Teams)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (Realtime)
  • GitHub Check: E2E Service Test (Databases/TablesDB)
  • GitHub Check: E2E Shared Mode Service Test (Dev Keys) (Shared V2)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: Unit Test
  • GitHub Check: E2E General Test
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: scan
🔇 Additional comments (3)
src/Appwrite/Extend/Exception.php (1)

215-215: LGTM! New unique violation constants follow the existing pattern.

The new DOCUMENT_UNIQUE_VIOLATION and ROW_UNIQUE_VIOLATION constants are well-placed and follow the established naming convention for exception types.

Also applies to: 225-225

src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php (1)

445-446: Exception handling for unique violations is correctly implemented.

The catch block for UniqueException is properly positioned before the more general DuplicateException and correctly maps to the appropriate error code via getUniqueException().

app/config/errors.php (1)

765-769: LGTM! Clear error mappings for unique constraint violations.

The new error mappings for DOCUMENT_UNIQUE_VIOLATION and ROW_UNIQUE_VIOLATION are well-structured and appropriate:

  • HTTP 409 correctly represents conflict status for unique constraint violations
  • Descriptions are clear and actionable for API consumers
  • Structure is consistent with existing error definitions
  • Proper differentiation from DOCUMENT_ALREADY_EXISTS / ROW_ALREADY_EXISTS (which handle _uid violations specifically)

Also applies to: 807-811

Copy link
Copy Markdown
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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08ec06d and a46fc5e.

📒 Files selected for processing (1)
  • tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/e2e/Services/Databases/Legacy/DatabasesBase.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Scopes/Scope.php (1)
  • getHeaders (145-145)
⏰ 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). (20)
  • GitHub Check: E2E Shared Mode Service Test (Databases/TablesDB, Shared V2)
  • GitHub Check: E2E Shared Mode Service Test (Projects, Shared V2)
  • GitHub Check: E2E Shared Mode Service Test (Databases/Legacy, Shared V1)
  • GitHub Check: E2E Shared Mode Service Test (Locale, Shared V1)
  • GitHub Check: E2E Shared Mode Service Test (Account, Shared V1)
  • GitHub Check: E2E Shared Mode Service Test (Console, Shared V1)
  • GitHub Check: E2E Shared Mode Service Test (Avatars, Shared V1)
  • GitHub Check: E2E Service Test (Projects)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Shared Mode Service Test (Site Screenshots) (Shared V1)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: E2E Shared Mode Service Test (Dev Keys) (Shared V2)
  • GitHub Check: E2E Shared Mode Service Test (Dev Keys) (Shared V1)
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: E2E Shared Mode Service Test (Site Screenshots) (Shared V2)
  • GitHub Check: Unit Test
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: scan

]);

$this->assertEquals(409, $duplicate['headers']['status-code']);
$this->assertEquals('Document with the requested ID already exists. Try again with a different ID or use ID.unique() to generate a unique ID.', $duplicate['body']['message']);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Assert the new unique error type

We need to verify the response surfaces Exception::DOCUMENT_UNIQUE_VIOLATION, otherwise the new UniqueException path is untested.

         $this->assertEquals(409, $duplicate['headers']['status-code']);
+        $this->assertEquals(Exception::DOCUMENT_UNIQUE_VIOLATION, $duplicate['body']['type']);
         $this->assertEquals('Document with the requested ID already exists. Try again with a different ID or use ID.unique() to generate a unique ID.', $duplicate['body']['message']);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In tests/e2e/Services/Databases/Legacy/DatabasesBase.php around line 4288, the
test only asserts the error message for duplicate documents but does not assert
the error type; add an assertion that the response surfaces the new
Exception::DOCUMENT_UNIQUE_VIOLATION type (e.g. insert an assertion such as
assertEquals(Exception::DOCUMENT_UNIQUE_VIOLATION, $duplicate['body']['type'])
in addition to the existing message assertion) so the UniqueException path is
covered.

Comment on lines +4324 to +4326
$this->assertEquals(409, $document['headers']['status-code']);
$this->assertEquals('Document with the requested ID already exists. Try again with a different ID or use ID.unique() to generate a unique ID.', $document['body']['message']);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Also assert the unique violation type here

Same concern: without checking the type, the test won’t catch regressions in the new exception mapping.

         $this->assertEquals(409, $document['headers']['status-code']);
+        $this->assertEquals(Exception::DOCUMENT_UNIQUE_VIOLATION, $document['body']['type']);
         $this->assertEquals('Document with the requested ID already exists. Try again with a different ID or use ID.unique() to generate a unique ID.', $document['body']['message']);
📝 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
$this->assertEquals(409, $document['headers']['status-code']);
$this->assertEquals('Document with the requested ID already exists. Try again with a different ID or use ID.unique() to generate a unique ID.', $document['body']['message']);
}
$this->assertEquals(409, $document['headers']['status-code']);
$this->assertEquals(Exception::DOCUMENT_UNIQUE_VIOLATION, $document['body']['type']);
$this->assertEquals(
'Document with the requested ID already exists. Try again with a different ID or use ID.unique() to generate a unique ID.',
$document['body']['message']
);
🤖 Prompt for AI Agents
In tests/e2e/Services/Databases/Legacy/DatabasesBase.php around lines 4324 to
4326, the test asserts the 409 status and error message but does not assert the
error "type"; add an assertion that verifies document['body']['type'] matches
the expected unique-violation type (e.g. assertEquals('unique_violation',
$document['body']['type'])), or, if the project exposes a constant or mapped
value for that type, use that constant instead to ensure the test catches
regressions in exception-to-type mapping.

@fogelito fogelito requested a review from abnegate October 19, 2025 05:46
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.

1 participant