Skip to content

Add spatial column validation during required mode and tests for exis…#10509

Merged
abnegate merged 5 commits into1.8.xfrom
fix-spatials-type-required-col
Sep 18, 2025
Merged

Add spatial column validation during required mode and tests for exis…#10509
abnegate merged 5 commits into1.8.xfrom
fix-spatials-type-required-col

Conversation

@ArnabChatterjee20k
Copy link
Copy Markdown
Member

@ArnabChatterjee20k ArnabChatterjee20k commented Sep 17, 2025

…ting data in databases

What does this PR do?

  • Previously , when we have existing data and creating a required spatial col it was getting failed;

  • Reasons

  1. When we generate cols we generate with not required
  2. Now when we are creating a spatial col with required -> we already have previous data -> so the column is getting filled with null
  3. The spatial col is meant to be not null at the sql if required is checked
  4. So insertion of null to not null giving error
  • Fix
    Adding a check to send error message to user as a validation step

  • Why no changes in utopia database lib?
    We can add changes to utopia lib but that runs in the workers. For validation steps, they are done in the api level before
    creating the attribute.
    Also the database namespace will not be available internally in the utopia lib and can be added as a separate independent pr

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 Sep 17, 2025

📝 Walkthrough

Walkthrough

Adds a pre-validation to Collections Attributes createAttribute to reject adding a required spatial attribute when the DB adapter lacks spatial-index-null support and the target collection/table already contains rows; in that case it throws a StructureException with message "Failed to add required spatial column: existing rows present. Make the column optional." The check occurs after preparing the attribute Document and before checkAttribute/creation. Renames getInvalidStructureException() → getStructureException() and updates StructureException handling across multiple Documents and Attributes flows to use the new method. Adds end-to-end tests exercising spatial-column creation on existing data for both Legacy and TablesDB paths and updates several TablesDB tests to POST /tablesdb.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title concisely describes the main change—adding validation for required spatial columns—and notes accompanying tests for existing data, which matches the changes in the diff and PR objectives. It is specific and focused, making the primary intent clear to reviewers.
Description Check ✅ Passed The PR description clearly documents the problem, root causes, the API-level validation fix, and the rationale for not modifying the utopia database library, which aligns with the raw_summary and pr_objectives. It also references added tests but leaves the Test Plan as a placeholder, so while related it could benefit from concrete test steps.
✨ 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-spatials-type-required-col

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.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Sep 17, 2025

Security Scan Results for PR

Docker Image Scan Results

Package Version Vulnerability Severity
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

Caution

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

⚠️ Outside diff range comments (2)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (1)

492-498: Bug: incorrect parentheses cause boolean used as key in getAttribute().

$attribute->getAttribute(('type') !== $type) evaluates the comparison first, yielding a boolean key. Same issue for 'filter'. This breaks validation.

-        if ($attribute->getAttribute(('type') !== $type)) {
+        if ($attribute->getAttribute('type') !== $type) {
             throw new Exception($this->getTypeInvalidException());
         }
 
-        if ($attribute->getAttribute('type') === Database::VAR_STRING && $attribute->getAttribute(('filter') !== $filter)) {
+        if ($attribute->getAttribute('type') === Database::VAR_STRING && $attribute->getAttribute('filter') !== $filter) {
             throw new Exception($this->getTypeInvalidException());
         }
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (1)

3065-3072: Endpoint migration mostly correct — two remaining '/databases' calls need updating

Update these POST calls to '/tablesdb' and align headers/payload with the TablesDB tests.

  • tests/e2e/Services/Databases/TablesDB/DatabasesPermissionsMemberTest.php:119
  • tests/e2e/Services/Databases/TablesDB/DatabasesCustomClientTest.php:123
🧹 Nitpick comments (5)
tests/e2e/Services/Databases/Legacy/DatabasesBase.php (2)

7871-7871: Strengthen the 400 assertions with a minimal reason check.

Assert that an error message is present so failures are easier to triage without over‑coupling to exact text.

-        $this->assertEquals(400, $point['headers']['status-code']);
+        $this->assertEquals(400, $point['headers']['status-code']);
+        $this->assertNotEmpty($point['body']['message'] ?? null);

-        $this->assertEquals(400, $line['headers']['status-code']);
+        $this->assertEquals(400, $line['headers']['status-code']);
+        $this->assertNotEmpty($line['body']['message'] ?? null);

-        $this->assertEquals(400, $poly['headers']['status-code']);
+        $this->assertEquals(400, $poly['headers']['status-code']);
+        $this->assertNotEmpty($poly['body']['message'] ?? null);

Also applies to: 7894-7894, 7917-7917


7929-7930: Clean up created resources to avoid cross‑test leakage.

This test creates a standalone database/collection; deleting them keeps e2e runs tidy.

-        $this->assertEquals(202, $poly['headers']['status-code']);
+        $this->assertEquals(202, $poly['headers']['status-code']);
+
+        // Cleanup to avoid leaking DB/collection across e2e runs
+        $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $colId, array_merge([
+            'content-type' => 'application/json',
+            'x-appwrite-project' => $this->getProject()['$id'],
+            'x-appwrite-key' => $this->getProject()['apiKey']
+        ]));
+        $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, array_merge([
+            'content-type' => 'application/json',
+            'x-appwrite-project' => $this->getProject()['$id'],
+            'x-appwrite-key' => $this->getProject()['apiKey']
+        ]));
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (2)

381-383: Preserve original StructureException as the previous throwable.

Pass $e as previous to retain stack context.

-        } catch (StructureException $e) {
-            throw new Exception($this->getInvalidStructureException(), $e->getMessage());
+        } catch (StructureException $e) {
+            throw new Exception($this->getInvalidStructureException(), $e->getMessage(), null, $e);
         }

392-397: Guard undefined index ‘twoWay’.

Use null-coalescing to avoid notices when options['twoWay'] isn’t set.

-        if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) {
+        if ($type === Database::VAR_RELATIONSHIP && ($options['twoWay'] ?? false)) {
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (1)

8831-8959: Add minimal assertions and cleanup to harden the new spatial-on-existing-data test.

  • Consider asserting response body shape (e.g., presence of “message”) for 400s to reduce false positives.
  • Add explicit cleanup to avoid test data leakage across runs.

Apply this diff to add cleanup at the end of the test:

         $this->assertEquals(202, $poly['headers']['status-code']);
+
+        // Cleanup to prevent residue affecting subsequent tests
+        $this->client->call(Client::METHOD_DELETE, '/tablesdb/' . $databaseId . '/tables/' . $tableId, array_merge([
+            'content-type' => 'application/json',
+            'x-appwrite-project' => $this->getProject()['$id'],
+            'x-appwrite-key' => $this->getProject()['apiKey']
+        ]));
+        $this->client->call(Client::METHOD_DELETE, '/tablesdb/' . $databaseId, array_merge([
+            'content-type' => 'application/json',
+            'x-appwrite-project' => $this->getProject()['$id'],
+            'x-appwrite-key' => $this->getProject()['apiKey']
+        ]));
     }

Optionally, after creating the optional spatial columns, fetch one back to assert required=false and default=null once the worker completes (mirrors patterns used elsewhere in this file).

📜 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 14062fc and 4815780.

📒 Files selected for processing (3)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (1 hunks)
  • tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1 hunks)
  • tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (2)
src/Appwrite/Extend/Exception.php (1)
  • Exception (7-447)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (3)
  • getDuplicateException (133-138)
  • getLimitException (183-188)
  • getInvalidStructureException (163-168)
tests/e2e/Services/Databases/Legacy/DatabasesBase.php (3)
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (1)
  • testSpatialColCreateOnExistingData (8831-8959)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Scopes/Scope.php (1)
  • getHeaders (145-145)
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1)
  • testSpatialColCreateOnExistingData (7802-7930)
⏰ 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). (6)
  • GitHub Check: scan-pr / osv-scan
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: Check if utopia-php/database changed
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: Linter
  • GitHub Check: scan
🔇 Additional comments (4)
tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1)

7802-7930: Good regression coverage for required spatial attributes with existing rows.

Scenario mirrors TablesDB and validates the API pre‑validation (400) and the non‑required fallback path (202). Looks solid.

tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (3)

3738-3746: Good switch to /tablesdb in permissions test.

Call shape and assertions are consistent with the rest of TablesDB tests.


3932-3940: Good: /tablesdb endpoint usage is consistent here too.

No issues spotted.


4288-4295: Database creation via /tablesdb is correct.

Headers and expected status code align with the rest of the file.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Sep 17, 2025

✨ Benchmark results

  • Requests per second: 1,216
  • Requests with 200 status code: 218,991
  • P99 latency: 0.159663101

⚡ Benchmark Comparison

Metric This PR Latest version
RPS 1,216 1,024
200 218,991 184,405
P99 0.159663101 0.189991398

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

♻️ Duplicate comments (1)
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (1)

9022-9059: Non-null spatial defaults covered — resolves earlier question

This block validates defaults other than null for point/line/polygon as previously discussed.

🧹 Nitpick comments (2)
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (2)

8831-8959: Add cleanup and (optionally) assert error type to harden the test

  • Missing teardown leaves a database/table around; add cleanup to avoid resource buildup and test interference.
  • Optional: also assert the error type to verify we hit the pre-validation path (keep message assertion out if unstable).

Apply this diff near the end of the test:

         $this->assertEquals(202, $poly['headers']['status-code']);
+        
+        // Cleanup
+        $this->client->call(Client::METHOD_DELETE, '/tablesdb/' . $databaseId . '/tables/' . $tableId, array_merge([
+            'content-type' => 'application/json',
+            'x-appwrite-project' => $this->getProject()['$id'],
+            'x-appwrite-key' => $this->getProject()['apiKey']
+        ]));
+        $this->client->call(Client::METHOD_DELETE, '/tablesdb/' . $databaseId, array_merge([
+            'content-type' => 'application/json',
+            'x-appwrite-project' => $this->getProject()['$id'],
+            'x-appwrite-key' => $this->getProject()['apiKey']
+        ]));

8961-9059: Verify default propagation on new rows and add teardown

The test creates optional spatial columns with non-null defaults but doesn’t verify that a new row receives those defaults. Add a quick insert/assert plus cleanup.

Apply this diff after creating the polygon column:

         $this->assertEquals(202, $poly['headers']['status-code']);
+
+        // Wait for worker to apply columns
+        sleep(2);
+
+        // Insert a new row and assert defaults are applied
+        $new = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows', array_merge([
+            'content-type' => 'application/json',
+            'x-appwrite-project' => $this->getProject()['$id'],
+        ], $this->getHeaders()), [
+            'rowId' => ID::unique(),
+            'data' => ['description' => 'after-defaults'],
+            'permissions' => [
+                Permission::read(Role::user($this->getUser()['$id'])),
+                Permission::update(Role::user($this->getUser()['$id'])),
+                Permission::delete(Role::user($this->getUser()['$id'])),
+            ]
+        ]);
+        $this->assertEquals(201, $new['headers']['status-code']);
+        $this->assertEquals([0.0, 0.0], $new['body']['loc']);
+        $this->assertEquals([[0.0, 0.0], [1.0, 1.0]], $new['body']['route']);
+        $this->assertEquals([[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]], $new['body']['area']);
+
+        // Cleanup
+        $this->client->call(Client::METHOD_DELETE, '/tablesdb/' . $databaseId . '/tables/' . $tableId, array_merge([
+            'content-type' => 'application/json',
+            'x-appwrite-project' => $this->getProject()['$id'],
+            'x-appwrite-key' => $this->getProject()['apiKey']
+        ]));
+        $this->client->call(Client::METHOD_DELETE, '/tablesdb/' . $databaseId, array_merge([
+            'content-type' => 'application/json',
+            'x-appwrite-project' => $this->getProject()['$id'],
+            'x-appwrite-key' => $this->getProject()['apiKey']
+        ]));
📜 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 4815780 and 5b09ebe.

📒 Files selected for processing (2)
  • tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1 hunks)
  • tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/e2e/Services/Databases/Legacy/DatabasesBase.php
🧰 Additional context used
🧬 Code graph analysis (1)
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Services/Databases/Legacy/DatabasesBase.php (2)
  • testSpatialColCreateOnExistingData (7802-7930)
  • testSpatialColCreateOnExistingDataWithDefaults (7932-8030)
⏰ 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). (5)
  • GitHub Check: E2E Service Test (Webhooks)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Databases/TablesDB)
  • GitHub Check: Benchmark
🔇 Additional comments (4)
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (4)

3065-3073: Switch to /tablesdb endpoint looks correct

Endpoint aligns with TablesDB suite; assertions remain valid.


3738-3748: Consistent TablesDB database creation

Good move to POST /tablesdb here too; keeps this suite homogenous.


3932-3941: TablesDB endpoint update: LGTM

Path change is accurate and matches neighboring tests.


4288-4296: Use of /tablesdb in empty-permissions test is consistent

No issues spotted.

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

Caution

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

⚠️ Outside diff range comments (1)
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (1)

4106-4106: Fix class-name typo: CLient → Client

This will fatal at runtime when executing the request.

Apply:

-        $this->client->call(CLient::METHOD_PUT, '/tablesdb/' . $databaseId . '/tables/' . $tableId, [
+        $this->client->call(Client::METHOD_PUT, '/tablesdb/' . $databaseId . '/tables/' . $tableId, [
🧹 Nitpick comments (2)
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (2)

8831-8959: Strengthen failure assertions and validate existing-row nulls

  • Also assert the error message content on 400 to lock the new API validation.
  • Optionally, fetch the pre-existing row to assert the new spatial columns are null.

Example patch:

@@
-        $this->assertEquals(400, $point['headers']['status-code']);
+        $this->assertEquals(400, $point['headers']['status-code']);
+        $this->assertStringContainsString('existing rows', $point['body']['message'] ?? '');
@@
-        $this->assertEquals(400, $line['headers']['status-code']);
+        $this->assertEquals(400, $line['headers']['status-code']);
+        $this->assertStringContainsString('existing rows', $line['body']['message'] ?? '');
@@
-        $this->assertEquals(400, $poly['headers']['status-code']);
+        $this->assertEquals(400, $poly['headers']['status-code']);
+        $this->assertStringContainsString('existing rows', $poly['body']['message'] ?? '');
@@
         $this->assertEquals(202, $poly['headers']['status-code']);
+
+        // Optionally verify existing row gets nulls for new columns
+        $existing = $this->client->call(
+            Client::METHOD_GET,
+            '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $row['body']['$id'],
+            array_merge(['content-type' => 'application/json','x-appwrite-project' => $this->getProject()['$id']], $this->getHeaders())
+        );
+        $this->assertEquals(200, $existing['headers']['status-code']);
+        $this->assertArrayHasKey('loc', $existing['body']);
+        $this->assertArrayHasKey('route', $existing['body']);
+        $this->assertArrayHasKey('area', $existing['body']);
+        $this->assertNull($existing['body']['loc']);
+        $this->assertNull($existing['body']['route']);
+        $this->assertNull($existing['body']['area']);

Optionally add cleanup at the end to drop the created table/database to reduce test-suite residue.


8961-9094: Defaults test looks good; add one negative case for “required + default”

Pre-validation should still block required spatial column when rows exist, even if a non-null default is provided. Add a quick 400 assertion for that combo to guard against regressions.

Example:

@@
         $this->assertEquals(201, $row['headers']['status-code']);
@@
+        // Required with non-null default should still be rejected when rows exist
+        $requiredPointWithDefault = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/point', array_merge([
+            'content-type' => 'application/json',
+            'x-appwrite-project' => $this->getProject()['$id'],
+            'x-appwrite-key' => $this->getProject()['apiKey']
+        ]), [
+            'key' => 'loc_required',
+            'required' => true,
+            'default' => [1.0, 1.0]
+        ]);
+        $this->assertEquals(400, $requiredPointWithDefault['headers']['status-code']);
📜 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 5b09ebe and 52ceddc.

📒 Files selected for processing (2)
  • tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1 hunks)
  • tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/e2e/Services/Databases/Legacy/DatabasesBase.php
🧰 Additional context used
🧬 Code graph analysis (1)
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Services/Databases/Legacy/DatabasesBase.php (2)
  • testSpatialColCreateOnExistingData (7802-7930)
  • testSpatialColCreateOnExistingDataWithDefaults (7932-8065)
⏰ 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 Service Test (Locale)
  • GitHub Check: E2E Service Test (Tokens)
  • GitHub Check: E2E Service Test (Projects)
  • GitHub Check: E2E Service Test (Migrations)
  • GitHub Check: E2E Service Test (Storage)
  • GitHub Check: E2E Service Test (Teams)
  • GitHub Check: E2E Service Test (Webhooks)
  • GitHub Check: E2E Service Test (VCS)
  • GitHub Check: E2E Service Test (Proxy)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Account)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: E2E General Test
🔇 Additional comments (3)
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (3)

3065-3065: Endpoint migration to /tablesdb – OK

Switch to TablesDB API looks consistent with the rest of the test.


3738-3738: Endpoint migration to /tablesdb – OK

Good alignment with TablesDB surface.


3931-3931: Endpoint migration to /tablesdb – OK

No issues spotted with this change.

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

♻️ Duplicate comments (1)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (1)

369-381: Tighten spatial “existing rows” pre-check and make message context-aware.

Use strict type check, avoid chaining under unary not, and say “attribute” vs “column”. Also reuse $type/$required locals.

Apply:

-            if (
-                !$dbForProject->getAdapter()->getSupportForSpatialIndexNull() &&
-                \in_array($attribute->getAttribute('type'), Database::SPATIAL_TYPES) &&
-                $attribute->getAttribute('required')
-            ) {
-                $hasData = !Authorization::skip(fn () => $dbForProject
-                    ->findOne('database_' . $db->getSequence() . '_collection_' . $collection->getSequence()))
-                    ->isEmpty();
-
-                if ($hasData) {
-                    throw new StructureException('Failed to add required spatial column: existing rows present. Make the column optional.');
-                }
-            }
+            $isSpatial = \in_array($type, Database::SPATIAL_TYPES, true);
+            if (
+                !$dbForProject->getAdapter()->getSupportForSpatialIndexNull()
+                && $isSpatial
+                && $required
+            ) {
+                $rows = 'database_' . $db->getSequence() . '_collection_' . $collection->getSequence();
+                $existing = Authorization::skip(fn () => $dbForProject->findOne($rows));
+                if ($existing instanceof Document && !$existing->isEmpty()) {
+                    $entity = $this->isCollectionsAPI() ? 'attribute' : 'column';
+                    throw new StructureException("Failed to add required spatial $entity: existing rows present. Make the $entity optional.");
+                }
+            }
🧹 Nitpick comments (1)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (1)

433-433: Propagate the message here too for parity.

Carry $e->getMessage() like above.

Apply:

-            } catch (StructureException) {
-                throw new Exception($this->getStructureException());
+            } catch (StructureException $e) {
+                throw new Exception($this->getStructureException(), $e->getMessage());
📜 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 52ceddc and 0e2c5d9.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (4 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (1 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php (1 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php (1 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php (1 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php (1 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php (2)
src/Appwrite/Extend/Exception.php (1)
  • Exception (7-447)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (1)
  • getStructureException (163-168)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php (3)
src/Appwrite/Extend/Exception.php (1)
  • Exception (7-447)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (1)
  • getStructureException (125-130)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (1)
  • getStructureException (163-168)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php (3)
src/Appwrite/Extend/Exception.php (1)
  • Exception (7-447)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (1)
  • getStructureException (125-130)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (1)
  • getStructureException (163-168)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Update.php (3)
src/Appwrite/Extend/Exception.php (1)
  • Exception (7-447)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (1)
  • getStructureException (125-130)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (1)
  • getStructureException (163-168)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (1)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (1)
  • getStructureException (125-130)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Upsert.php (3)
src/Appwrite/Extend/Exception.php (1)
  • Exception (7-447)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (1)
  • getStructureException (125-130)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (1)
  • getStructureException (163-168)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (2)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (1)
  • getStructureException (163-168)
src/Appwrite/Extend/Exception.php (1)
  • Exception (7-447)
⏰ 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). (3)
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: scan
🔇 Additional comments (9)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (2)

163-168: Rename looks good; mappings remain correct.

DOCUMENTS → document_invalid_structure, TABLES → row_invalid_structure.


163-168: No leftover references to getInvalidStructureException — resolved.
Ran rg -nP '\bgetInvalidStructureException\s*\(' -S — no matches found.

src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (2)

125-130: Consistent error-type mapping.

Matches Documents side; good.


389-390: Good: preserve inner StructureException message.

This improves debuggability.

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

261-262: Unified invalid-structure handling.

Switch to getStructureException() with original message retained. Looks good.

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

133-134: LGTM on error mapping consistency.

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

378-379: LGTM; preserves message and standardizes type.

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

152-153: LGTM; consistent with other paths.

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

250-251: LGTM; standardized exception type + message preserved.

@abnegate abnegate merged commit 34f3501 into 1.8.x Sep 18, 2025
86 checks passed
@abnegate abnegate deleted the fix-spatials-type-required-col branch September 18, 2025 03:29
This was referenced Oct 10, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 23, 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