Skip to content

Conversation

@abnegate
Copy link
Member

@abnegate abnegate commented Sep 4, 2025

Summary by CodeRabbit

  • New Features

    • Added upsertDocument helper for single-document upserts.
  • Breaking Changes

    • Renamed createOrUpdateDocuments → upsertDocuments.
    • Renamed createOrUpdateDocumentsWithIncrease → upsertDocumentsWithIncrease.
  • Improvements

    • Batch upsert APIs support an optional onError callback.
    • onNext callbacks now receive both the new and previous document versions.
    • Upsert behavior made consistent across adapters and mirror flows.
  • Tests

    • End-to-end tests updated to use the new upsert* APIs.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 4, 2025

Warning

Rate limit exceeded

@abnegate has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 15 minutes and 45 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 48220ca and 55d04ee.

📒 Files selected for processing (2)
  • src/Database/Database.php (23 hunks)
  • src/Database/Mirror.php (8 hunks)

Walkthrough

Public API rename from createOrUpdateDocuments() to upsertDocuments() across Adapter, Pool, SQL adapter, Database, and Mirror. Database adds an optional onError callback, introduces upsertDocument helper, and changes onNext to receive (new, old). Mirror and tests updated to use the new names and callback shape.

Changes

Cohort / File(s) Summary
API rename: Adapter & implementations
src/Database/Adapter.php, src/Database/Adapter/Pool.php, src/Database/Adapter/SQL.php
Renamed createOrUpdateDocuments(...)upsertDocuments(...) with same parameters/returns; Pool delegates using __FUNCTION__.
Database upsert API & callbacks
src/Database/Database.php
Renamed public methods to upsertDocuments(...) and upsertDocumentsWithIncrease(...); added optional onError callback; onNext now receives (new, old); added upsertDocument(...) helper; minor formatting tweaks (e.g., SPATIAL_TYPES).
Mirror upsert propagation
src/Database/Mirror.php
Replaced/added upsertDocuments(...); delegates to source/destination upsert paths; onNext now receives (new, old); preserves before/after create-or-update hooks; onError wired for source calls.
Tests: rename to upsert
tests/e2e/Adapter/Scopes/DocumentTests.php, tests/e2e/Adapter/Scopes/GeneralTests.php, tests/e2e/Adapter/Scopes/SpatialTests.php
Updated calls from createOrUpdateDocuments*upsertDocuments* and createOrUpdateDocumentsWithIncreaseupsertDocumentsWithIncrease; expectations unchanged.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant DB as Database
  participant AD as Adapter (SQL/Pool/…)

  Client->>DB: upsertDocuments(collection, documents, batchSize, onNext?, onError?)
  loop For each batch
    DB->>DB: snapshot old state per document
    DB->>AD: upsertDocuments(collectionDoc, attribute?, changes)
    AD-->>DB: results[]
    loop For each result
      DB->>DB: try onNext(newDoc, oldDoc)
      alt onNext throws and onError provided
        DB->>Client: onError(error, newDoc, oldDoc)
      else onNext throws and no onError
        DB-->>Client: throw error
      end
    end
  end
  DB-->>Client: totalCount
  note right of DB: upsertDocument delegates to upsertDocumentsWithIncrease for single doc
Loading
sequenceDiagram
  autonumber
  participant SRC as Mirror (source DB)
  participant DST as Mirror (destination DB)
  participant AD as Adapter
  participant Hooks as Filters

  SRC->>SRC: upsertDocuments(collection, docs, batch, onNext?, onError?)
  SRC->>DST: upsertDocuments(collection, docs, batch, onNext?, onError?)
  loop Each document
    DST->>Hooks: beforeCreateOrUpdateDocument(doc)
    DST->>AD: upsertDocuments(collectionDoc, attribute?, changes)
    AD-->>DST: newDoc
    DST->>Hooks: afterCreateOrUpdateDocument(newDoc)
    DST->>SRC: onNext(newDoc, oldDoc)
    alt onNext throws
      SRC->>SRC: onError?(error, newDoc, oldDoc) or throw
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • fogelito

Poem

I hop through fields of docs and keys,
I rename carrots to “upserts” with ease.
I nibble old and new to compare,
If errors sprout, I’ll call who’s there.
One batch, one doc—tests cheer and clap,
A rabbit’s tidy refactor rap. 🥕🐇

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

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.
    • 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.
  • 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 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/Issue comments)

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

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit 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.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

@abnegate abnegate marked this pull request as ready for review September 4, 2025 11:52
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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/e2e/Adapter/Scopes/DocumentTests.php (1)

535-541: Make onNext callback arity-aware in upsertDocuments
In both src/Database/Mirror.php (around lines 796–799) and src/Database/Database.php’s upsertDocumentsWithIncrease implementation (around line 5337), the code currently always calls onNext($doc, $old). That will throw an ArgumentCountError for existing one-parameter closures in tests (e.g. tests/e2e/Adapter/Scopes/DocumentTests.php at lines 640–643, 5569–5571, 5600–5602, etc.). Update those sites to inspect the callable’s parameter count and invoke it with only the required arguments (one or two) to maintain backward compatibility.

src/Database/Database.php (1)

4621-4641: Bug: timestamp conflict check uses the new document’s updatedAt instead of the original.
This can falsely throw ConflictException (especially when $updates sets $updatedAt to now). Capture/check the original updatedAt before overwriting $document.

Apply this diff inside the foreach ($batch as $index => $document) loop:

-                    $new = new Document(\array_merge($document->getArrayCopy(), $updates->getArrayCopy()));
+                    $new = new Document(\array_merge($document->getArrayCopy(), $updates->getArrayCopy()));
+                    $originalUpdatedAt = $document->getUpdatedAt();
@@
-                    $document = $new;
-
-                    // Check if document was updated after the request timestamp
-                    try {
-                        $oldUpdatedAt = new \DateTime($document->getUpdatedAt());
+                    $document = $new;
+                    // Check if document was updated after the request timestamp (use original value)
+                    try {
+                        $oldUpdatedAt = new \DateTime($originalUpdatedAt);
                     } catch (Exception $e) {
                         throw new DatabaseException($e->getMessage(), $e->getCode(), $e);
                     }
🧹 Nitpick comments (4)
src/Database/Adapter/SQL.php (1)

2093-2249: Rename implemented; consider stabilizing columns across changes and handling spatial WKT explicitly.

Two optional hardening tweaks:

  • Ensure every Change has identical, sorted attribute keys; otherwise $columns (from the last item) may not match earlier bind tuples.
  • For spatial attributes, bind WKT (convertArrayToWKT) rather than JSON to avoid relying on engine-specific coercion.

Apply minimal validation and WKT binding:

@@
-            $attributes = [];
+            $attributes = [];
             $bindIndex = 0;
             $batchKeys = [];
             $bindValues = [];
+            $firstKeys = null;
+            $columnsSQL = '';
@@
-                \ksort($attributes);
+                \ksort($attributes);
+                $keys = \array_keys($attributes);
+                if ($firstKeys === null) {
+                    $firstKeys = $keys;
+                    $cols = [];
+                    foreach ($firstKeys as $key => $attr) {
+                        /** @var string $attr */
+                        $cols[$key] = "{$this->quote($this->filter($attr))}";
+                    }
+                    $columnsSQL = '(' . \implode(', ', $cols) . ')';
+                } elseif ($keys !== $firstKeys) {
+                    throw new DatabaseException('All upsert changes must have identical attribute sets');
+                }
-
-                $columns = [];
-                foreach (\array_keys($attributes) as $key => $attr) {
-                    /**
-                     * @var string $attr
-                     */
-                    $columns[$key] = "{$this->quote($this->filter($attr))}";
-                }
-                $columns = '(' . \implode(', ', $columns) . ')';
@@
-                foreach ($attributes as $attributeKey => $attrValue) {
-                    if (\is_array($attrValue)) {
-                        $attrValue = \json_encode($attrValue);
-                    }
-
-                    if (in_array($attributeKey, $spatialAttributes)) {
+                foreach ($attributes as $attributeKey => $attrValue) {
+                    if (in_array($attributeKey, $spatialAttributes)) {
+                        // Convert array geometry to WKT for ST_GeomFromText
+                        if (\is_array($attrValue)) {
+                            $attrValue = $this->convertArrayToWKT($attrValue);
+                        }
                         $bindKey = 'key_' . $bindIndex;
                         $bindKeys[] = "ST_GeomFromText(:" . $bindKey . ")";
                     } else {
+                        if (\is_array($attrValue)) {
+                            $attrValue = \json_encode($attrValue);
+                        }
                         $attrValue = (\is_bool($attrValue)) ? (int)$attrValue : $attrValue;
                         $bindKey = 'key_' . $bindIndex;
                         $bindKeys[] = ':' . $bindKey;
                     }
@@
-            $stmt = $this->getUpsertStatement($name, $columns, $batchKeys, $attributes, $bindValues, $attribute);
+            $stmt = $this->getUpsertStatement($name, $columnsSQL, $batchKeys, $attributes, $bindValues, $attribute);

To validate uniform attribute keys across generated Change objects, inspect the builder in Database::upsertDocumentsWithIncrease and ensure it normalizes/ksorts keys for all changes.

src/Database/Mirror.php (2)

788-790: Optional: propagate onError to destination too.

If you want parity with Database API, pass $onError to destination as well. Today destination errors are only logged via logError.

Example:

-                $this->destination->upsertDocuments(
+                $this->destination->upsertDocuments(
                     $collection,
                     $clones,
                     $batchSize,
-                    null,
+                    null,
+                    $onError,
                 )

832-840: Optional: align returned count source vs destination across Mirror methods.

createDocuments returns source count; update/delete/upsert return destination count. Consider standardizing on source count to avoid surprises.

src/Database/Database.php (1)

4663-4666: Limit handling: prefer >= to avoid edge cases.
Use >= like deleteDocuments does; prevents overshoot/looping if counts diverge.

-            } elseif ($originalLimit && $modified == $originalLimit) {
+            } elseif ($originalLimit && $modified >= $originalLimit) {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 fcd166b and 0c6e693.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • src/Database/Adapter.php (1 hunks)
  • src/Database/Adapter/Pool.php (1 hunks)
  • src/Database/Adapter/SQL.php (1 hunks)
  • src/Database/Database.php (21 hunks)
  • src/Database/Mirror.php (4 hunks)
  • tests/e2e/Adapter/Scopes/DocumentTests.php (28 hunks)
  • tests/e2e/Adapter/Scopes/GeneralTests.php (3 hunks)
  • tests/e2e/Adapter/Scopes/SpatialTests.php (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
src/Database/Adapter/Pool.php (2)
src/Database/Adapter.php (1)
  • upsertDocuments (752-756)
src/Database/Adapter/SQL.php (1)
  • upsertDocuments (2093-2250)
tests/e2e/Adapter/Scopes/GeneralTests.php (5)
src/Database/Database.php (1)
  • upsertDocuments (5110-5125)
src/Database/Mirror.php (1)
  • upsertDocuments (784-856)
src/Database/Adapter.php (1)
  • upsertDocuments (752-756)
src/Database/Adapter/Pool.php (1)
  • upsertDocuments (248-251)
src/Database/Adapter/SQL.php (1)
  • upsertDocuments (2093-2250)
src/Database/Adapter/SQL.php (4)
src/Database/Database.php (1)
  • upsertDocuments (5110-5125)
src/Database/Mirror.php (1)
  • upsertDocuments (784-856)
src/Database/Adapter.php (1)
  • upsertDocuments (752-756)
src/Database/Adapter/Pool.php (1)
  • upsertDocuments (248-251)
tests/e2e/Adapter/Scopes/SpatialTests.php (5)
src/Database/Database.php (1)
  • upsertDocuments (5110-5125)
src/Database/Mirror.php (1)
  • upsertDocuments (784-856)
src/Database/Adapter.php (1)
  • upsertDocuments (752-756)
src/Database/Adapter/Pool.php (1)
  • upsertDocuments (248-251)
src/Database/Adapter/SQL.php (1)
  • upsertDocuments (2093-2250)
src/Database/Adapter.php (4)
src/Database/Database.php (1)
  • upsertDocuments (5110-5125)
src/Database/Mirror.php (1)
  • upsertDocuments (784-856)
src/Database/Adapter/Pool.php (1)
  • upsertDocuments (248-251)
src/Database/Adapter/SQL.php (1)
  • upsertDocuments (2093-2250)
tests/e2e/Adapter/Scopes/DocumentTests.php (5)
src/Database/Database.php (3)
  • count (6450-6486)
  • upsertDocuments (5110-5125)
  • upsertDocumentsWithIncrease (5141-5356)
src/Database/Adapter.php (2)
  • count (825-825)
  • upsertDocuments (752-756)
src/Database/Adapter/Pool.php (2)
  • count (273-276)
  • upsertDocuments (248-251)
src/Database/Adapter/SQL.php (2)
  • count (2521-2583)
  • upsertDocuments (2093-2250)
src/Database/Mirror.php (1)
  • upsertDocuments (784-856)
src/Database/Database.php (7)
src/Database/Document.php (5)
  • getPermissions (93-96)
  • removeAttribute (287-293)
  • getId (63-66)
  • Document (12-470)
  • isEmpty (396-399)
src/Database/Mirror.php (2)
  • upsertDocuments (784-856)
  • onError (78-81)
src/Database/Adapter.php (2)
  • upsertDocuments (752-756)
  • withTransaction (377-425)
src/Database/Adapter/Pool.php (1)
  • upsertDocuments (248-251)
src/Database/Adapter/SQL.php (1)
  • upsertDocuments (2093-2250)
src/Database/Validator/Authorization.php (2)
  • Authorization (7-225)
  • skip (160-170)
src/Database/Change.php (1)
  • getOld (13-16)
src/Database/Mirror.php (4)
src/Database/Database.php (2)
  • upsertDocuments (5110-5125)
  • Database (37-7274)
src/Database/Adapter.php (1)
  • upsertDocuments (752-756)
src/Database/Adapter/Pool.php (1)
  • upsertDocuments (248-251)
src/Database/Adapter/SQL.php (1)
  • upsertDocuments (2093-2250)
🪛 PHPMD (2.15.0)
src/Database/Mirror.php

789-789: Avoid unused parameters such as '$onError'. (Unused Code Rules)

(UnusedFormalParameter)

🔇 Additional comments (21)
tests/e2e/Adapter/Scopes/GeneralTests.php (3)

515-520: Rename to upsertDocuments looks correct.

Call site matches the new Database API and existing gating by getSupportForUpserts().


553-562: LGTM on API rename (batch upsert for multiple tenants).

Consistent with the new method. No behavioral changes introduced here.


585-593: LGTM on API rename (updates via upsert).

Call site aligns with the new upsertDocuments API.

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

1584-1584: Comment update matches the API rename.

No action needed.

src/Database/Adapter/Pool.php (1)

248-251: Delegation method renamed correctly.

Matches Adapter::upsertDocuments and routes via FUNCTION as expected.

src/Database/Adapter.php (1)

752-756: Abstract rename aligns with the new API.

Signature and docblock remain coherent with “upsert” semantics.

src/Database/Mirror.php (1)

820-827: Guard new filter hooks to prevent undefined method errors
Ensure calls to beforeCreateOrUpdateDocument and afterCreateOrUpdateDocument are wrapped in method_exists checks, falling back to the legacy beforeCreateDocument/afterCreateDocument if the new methods aren’t implemented:

--- a/src/Database/Mirror.php
+++ b/src/Database/Mirror.php
@@ lines 820-827
-                foreach ($this->writeFilters as $filter) {
-                    $clone = $filter->beforeCreateOrUpdateDocument(
+                foreach ($this->writeFilters as $filter) {
+                    if (method_exists($filter, 'beforeCreateOrUpdateDocument')) {
+                        $clone = $filter->beforeCreateOrUpdateDocument(
                             source: $this->source,
                             destination: $this->destination,
                             collectionId: $collection,
                             document: $clone,
-                    );
+                        );
+                    } else {
+                        $clone = $filter->beforeCreateDocument(
+                            source: $this->source,
+                            destination: $this->destination,
+                            collectionId: $collection,
+                            document: $clone,
+                        );
+                    }
                 }
@@ lines 843-850
-                foreach ($this->writeFilters as $filter) {
-                    $filter->afterCreateOrUpdateDocument(
+                foreach ($this->writeFilters as $filter) {
+                    if (method_exists($filter, 'afterCreateOrUpdateDocument')) {
+                        $filter->afterCreateOrUpdateDocument(
                             source: $this->source,
                             destination: $this->destination,
                             collectionId: $collection,
                             document: $clone,
-                    );
+                        );
+                    } else {
+                        $filter->afterCreateDocument(
+                            source: $this->source,
+                            destination: $this->destination,
+                            collectionId: $collection,
+                            document: $clone,
+                        );
+                    }
                 }

Applies to both the create-or-update and update-or-create loops.

src/Database/Database.php (14)

63-63: Formatting nit: SPATIAL_TYPES list looks good.
No behavior change; consistent with surrounding constants.


3829-3829: Docblock matches callback shape in createDocuments.
The parameter type for onNext reflects the actual callback usage.


4286-4292: Permissions comparison guard is correct.
Sorting and comparing arrays to decide skipPermissionsUpdate is fine and matches similar logic elsewhere.


4476-4495: UpdateDocuments: new callback signatures are clear.
Adding onError and passing $old to onNext is a sensible API improvement.


4650-4658: onNext/onError wrapping is correct.
Cloned $old by index and try/catch with onError is good.


5110-5125: upsertDocuments delegating to withIncrease (with onError) is clean.
Signature and forwarding order look correct.


5141-5150: upsertDocumentsWithIncrease: API docs and parameters look good.
onNext($new, ?$old) and optional onError are clear.


5308-5313: Authorization::skip within transaction is appropriate here.
Adapter upsert executes atomically without read permission requirements.


5324-5345: Post-upsert callback semantics are correct.
Decoding before invoking onNext and providing nullable $old matches the contract; try/catch routes to onError properly.


6012-6026: deleteDocuments: improved callbacks (onNext with $old, onError).
API symmetry with update/upsert; looks good.


6105-6155: Cloning $old and purging cache per-tenant is sound.
Index alignment and error handling are fine.


6562-6576: Encode: normalize empty internal date strings to null.
Good robustness improvement; avoids invalid dates leaking into storage.


6978-6992: convertQuery: guard on empty attribute is correct.
Prevents accessing properties on empty Document; keeps datetime normalization intact.


7236-7260: decodeSpatialData: safer closing-paren handling.
Using strrpos avoids mismatches for nested parentheses; OK for POINT/LINESTRING/POLYGON.

abnegate and others added 2 commits September 5, 2025 00:15
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

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

5086-5093: Past concern resolved: closure arity and non-null return are fixed.

  • Closure now accepts two args; null-result fallback ensures a Document is returned.

Also applies to: 5095-5100

🧹 Nitpick comments (2)
src/Database/Database.php (2)

5190-5199: Improve no-op detection by filling optionals before comparing with old.
Currently, the equality check may miss no-ops when caller omits optional fields present in $old. Move the “Force matching optional parameter sets” block before the comparison.

Apply:

-            if (
-                empty($attribute)
-                && $skipPermissionsUpdate
-                && $old->getAttributes() == $document->getAttributes()
-            ) {
-                // If not updating a single attribute and the
-                // document is the same as the old one, skip it
-                unset($documents[$key]);
-                continue;
-            }
+            // Normalize optionals first to compare apples-to-apples
+            foreach ($collectionAttributes as $attr) {
+                if (!$attr->getAttribute('required') && !\array_key_exists($attr['$id'], (array)$document)) {
+                    $document->setAttribute(
+                        $attr['$id'],
+                        $old->getAttribute($attr['$id'], ($attr['default'] ?? null))
+                    );
+                }
+            }
+            if (
+                empty($attribute)
+                && $skipPermissionsUpdate
+                && $old->getAttributes() == $document->getAttributes()
+            ) {
+                unset($documents[$key]);
+                continue;
+            }
@@
-            // Force matching optional parameter sets
-            // Doesn't use decode as that intentionally skips null defaults to reduce payload size
-            foreach ($collectionAttributes as $attr) {
-                if (!$attr->getAttribute('required') && !\array_key_exists($attr['$id'], (array)$document)) {
-                    $document->setAttribute(
-                        $attr['$id'],
-                        $old->getAttribute($attr['$id'], ($attr['default'] ?? null))
-                    );
-                }
-            }

Also applies to: 5237-5246


7241-7241: Minor parsing robustness for decodeSpatialData.
Use preg_split('/\s+/') for coords to tolerate extra whitespace; trim() around substrings.

Apply (illustrative):

-            $coords = explode(' ', trim($inside));
+            $coords = preg_split('/\s+/', trim($inside));
@@
-            $points = explode(',', $inside);
+            $points = array_map('trim', explode(',', $inside));
@@
-            $rings = explode('),(', $inside);
+            $rings = array_map('trim', explode('),(', $inside));

Also applies to: 7251-7251, 7264-7264

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 0c6e693 and 48220ca.

📒 Files selected for processing (1)
  • src/Database/Database.php (21 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/Database/Database.php (6)
src/Database/Document.php (4)
  • getPermissions (93-96)
  • removeAttribute (287-293)
  • getId (63-66)
  • Document (12-470)
src/Database/Adapter.php (2)
  • upsertDocuments (752-756)
  • withTransaction (377-425)
src/Database/Adapter/SQL.php (1)
  • upsertDocuments (2093-2250)
src/Database/Mirror.php (2)
  • upsertDocuments (784-856)
  • onError (78-81)
src/Database/Validator/Authorization.php (2)
  • Authorization (7-225)
  • skip (160-170)
src/Database/Change.php (1)
  • getOld (13-16)
🪛 PHPMD (2.15.0)
src/Database/Database.php

5090-5090: Avoid unused parameters such as '$_old'. (Unused Code Rules)

(UnusedFormalParameter)

⏰ 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 (MySQL)
  • GitHub Check: Adapter Tests (Postgres)
  • GitHub Check: Adapter Tests (SharedTables/Postgres)
  • GitHub Check: Adapter Tests (SharedTables/MySQL)
  • GitHub Check: Adapter Tests (MariaDB)
  • GitHub Check: Adapter Tests (Pool)
  • GitHub Check: Adapter Tests (SharedTables/SQLite)
  • GitHub Check: Adapter Tests (SharedTables/MariaDB)
  • GitHub Check: Adapter Tests (SQLite)
  • GitHub Check: Unit Test
🔇 Additional comments (9)
src/Database/Database.php (9)

63-63: LGTM: SPATIAL_TYPES formatting is fine.


3829-3829: Docblock OK: createDocuments onNext(Document) type is accurate.


4476-4478: Callback shape standardization (onNext(new, old), optional onError) looks good.

  • Matches usages later in method bodies; consistent across update/upsert/delete.

Please verify all call sites across the repo now pass two params to onNext for updateDocuments, upsertDocuments, upsertDocumentsWithIncrease, and deleteDocuments.

Also applies to: 5108-5110, 5114-5120, 5137-5151, 6016-6018


4600-4601: Good: clone old state and invoke onNext(updated, old) with error routing.

Also applies to: 4650-4656


5114-5129: LGTM: upsertDocuments delegates correctly including onError and batchSize.


5312-5316: Transaction + per-doc callbacks look solid; confirm adapter order guarantee.

  • Mapping $batch[$index] to $chunk[$index] assumes adapter preserves order and cardinality.

Confirm the adapter contract specifies stable ordering. If not guaranteed, consider associating old by ID to decouple from ordering.

Also applies to: 5329-5349


6565-6579: Nice: normalize empty date strings to null before encoding.


6982-6996: Safer convertQuery: only transform when attribute is known.


6016-6018: LGTM: deleteDocuments onNext(old included), cloning old state, error routing.

Also applies to: 6110-6110, 6146-6156

@abnegate abnegate merged commit e4a03ba into main Sep 4, 2025
15 checks passed
@abnegate abnegate deleted the feat-rename branch September 4, 2025 12:36
@coderabbitai coderabbitai bot mentioned this pull request Sep 14, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 2, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 21, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 30, 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.

2 participants