-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Database aliases, new terminologies and a migration to modules #9693
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 1.7.x
Are you sure you want to change the base?
Conversation
WalkthroughThis update introduces a comprehensive "Tables" API to the database module, paralleling the existing "Collections" API. It adds new endpoints, models, validators, error codes, and test suites for managing tables, columns, rows, and their indexes. The update also adapts event handling, response schemas, and usage statistics to support both collections/documents and tables/rows, ensuring consistency and backward compatibility across the platform. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API
participant DBModule
participant EventQueue
participant Database
Client->>API: POST /v1/databases/:databaseId/tables
API->>DBModule: Create Table
DBModule->>Database: Create Table Document & Collection
Database-->>DBModule: Table Created
DBModule->>EventQueue: Queue Table Created Event
DBModule-->>API: Table Model Response
API-->>Client: 201 Created (Table)
Client->>API: POST /v1/databases/:databaseId/tables/:tableId/rows
API->>DBModule: Create Row
DBModule->>Database: Insert Row Document
Database-->>DBModule: Row Created
DBModule->>EventQueue: Queue Row Created Event
DBModule-->>API: Row Model Response
API-->>Client: 201 Created (Row)
Client->>API: GET /v1/databases/:databaseId/tables/:tableId/columns
API->>DBModule: List Columns
DBModule->>Database: Fetch Columns
Database-->>DBModule: Columns List
DBModule-->>API: Column List Model
API-->>Client: 200 OK (Columns)
Poem
Tip ⚡️ Faster reviews with caching
Enjoy the performance boost—your workflow just got faster. ✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
Security Scan Results for PRDocker Image Scan Results
Source Code Scan Results🎉 No vulnerabilities found! |
✨ Benchmark results
⚡ Benchmark Comparison
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
🔭 Outside diff range comments (1)
tests/e2e/General/UsageTest.php (1)
45-63
: 🛠️ Refactor suggestionRemove duplicated trait-alias statements to avoid maintenance overhead
The same
as
-aliases are declared twice for several methods (e.g.listVariables
,updateVariable
,deleteDeployment
, …).
These duplicates do not break PHP at runtime (the second alias is silently ignored) but make the class noisy and error-prone – future edits may accidentally touch only one of the two lines.- FunctionsBase::listVariables insteadof SitesBase; - FunctionsBase::listVariables insteadof SitesBase; + FunctionsBase::listVariables insteadof SitesBase;…repeat for every pair.
Cleaning this block up keeps the trait-resolution readable and prevents confusion about which alias is actually in effect.
♻️ Duplicate comments (2)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (2)
467-470
:size
should accept zero – use strict null check instead ofempty()
Using
empty($size)
treats0
as "empty", so a caller cannot deliberately resize an attribute/column to0
. Anull
sentinel is already used to indicate "not provided".- if (!empty($size)) { + if ($size !== null) { $attribute->setAttribute('size', $size); }
445-451
:⚠️ Potential issueFix misplaced parentheses in getAttribute calls
There are syntax errors in the type and filter checks due to misplaced parentheses, which will cause unexpected behavior. Also, 'filter' should likely be 'format' based on other parts of the code.
- 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('format') !== $filter) { throw new Exception($this->getTypeInvalidException()); }
🧹 Nitpick comments (24)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/IP/Create.php (1)
49-49
: Documentation path needs updating for column terminologyThe documentation link still references "attribute" instead of "column" which doesn't align with the new terminology being introduced in this PR.
- description: '/docs/references/databases/create-ip-attribute.md', + description: '/docs/references/databases/create-ip-column.md',src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Integer/Update.php (1)
51-51
: Documentation path needs updating for column terminologyThe documentation link still references "attribute" instead of "column" which doesn't align with the new terminology being introduced in this PR.
- description: '/docs/references/databases/update-integer-attribute.md', + description: '/docs/references/databases/update-integer-column.md',src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Integer/Create.php (1)
49-49
: Documentation path needs updating for column terminologyThe documentation link still references "attribute" instead of "column" which doesn't align with the new terminology being introduced in this PR.
- description: '/docs/references/databases/create-integer-attribute.md', + description: '/docs/references/databases/create-integer-column.md',src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Create.php (1)
55-55
: Documentation path needs updating for row terminologyThe documentation link still references "document" instead of "row" which doesn't align with the new terminology being introduced in this PR.
- description: '/docs/references/databases/create-document.md', + description: '/docs/references/databases/create-row.md',src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Email/Update.php (2)
47-59
: Doc-link still points to “attribute” instead of “column”The SDK description references
/docs/references/databases/update-email-attribute.md
.
For the new Tables API we probably want a dedicated column page to avoid confusing users who migrate from collections → tables.- description: '/docs/references/databases/update-email-attribute.md', + description: '/docs/references/databases/update-email-column.md',(Or update the target file accordingly.)
61-67
: Consider making therequired
&default
mutual-exclusion explicitThe validator comment says “Cannot be set when column is required.”, but nothing enforces it locally; the restriction is hidden in the parent
EmailUpdate
.
A tiny runtime guard here would give earlier feedback if the parent signature ever changes:if ($required === true && $default !== null) { throw new Exception('Cannot set default when column is required'); }tests/e2e/Services/Databases/Tables/DatabasesPermissionsMemberTest.php (1)
235-257
: Potentially brittle negative-path assertionWhen the user lacks permissions the API could return 401, 403 or 404 depending
on auth vs resource visibility. UnliketestWriteDocuments
, here we assert
only401
, which may cause flaky failures if the implementation changes.- $this->assertEquals(401, $rows['headers']['status-code']); + $this->assertContains($rows['headers']['status-code'], [401, 403, 404]);tests/e2e/Services/Databases/Tables/DatabasesPermissionsTeamTest.php (1)
176-181
: Negative read assertion could mask a 403/404Similar to the member test, consider broadening the expected codes or using
assertNotEquals(200, …)
to future-proof against backend changes.tests/e2e/General/UsageTest.php (1)
422-460
: DRY: factor out the repeated “create-then-optionally-delete” loopThe two loops building databases (Collections API vs Tables API) are byte-for-byte identical except for the endpoint. Extract the common logic into a private helper:
private function seedDatabases(string $endpoint, int &$total, int &$requests): string { $databaseId = ''; for ($i = 0; $i < self::CREATE; $i++) { $name = uniqid() . ' database'; $response = $this->client->call(Client::METHOD_POST, $endpoint, /* … */); // assertions … $total++; $requests++; $databaseId = $response['body']['$id']; if ($i < (self::CREATE / 2)) { $this->client->call(Client::METHOD_DELETE, $endpoint.'/'.$databaseId, /* … */); $total--; $requests++; } } return $databaseId; }This will shave ~70 duplicated lines, shorten the test by ~250 LOC overall, and make future endpoint changes trivial.
Also applies to: 659-697
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Action.php (4)
1-8
: Adddeclare(strict_types=1);
for project-wide strict typingAll core Appwrite sources start with
declare(strict_types=1);
.
Keeping the directive consistent avoids silent type juggling and aligns with the coding-standard checks.<?php +declare(strict_types=1);
13-14
: Property should be non-nullable
$context
is initialised with a string constant and is never allowed to benull
(setter validates).
Mark it asstring
instead of?string
to better express invariants and remove a useless null-check for callers.- private ?string $context = DATABASE_INDEX_CONTEXT; + private string $context = DATABASE_INDEX_CONTEXT;
27-31
: Prefix global constants with backslash to prevent namespace lookupInside a namespace PHP first looks for a namespaced constant named
DATABASE_INDEX_CONTEXT
; if none exists it falls back to the global one.
Prefixing with\
eliminates this two-step lookup and guards against future namespace-level constants shadowing the global ones:- if (!\in_array($context, [DATABASE_INDEX_CONTEXT, DATABASE_COLUMN_INDEX_CONTEXT], true)) { + if (!\in_array($context, [\DATABASE_INDEX_CONTEXT, \DATABASE_COLUMN_INDEX_CONTEXT], true)) {Apply the same change to every occurrence of these constants.
89-94
: Typo:getGrantParentNotFoundException
→getGrandParentNotFoundException
“Grandparent” is the correct term in the rest of the codebase (
GRAND_PARENT_*
constants).
Renaming avoids confusion and improves discoverability in IDE search.tests/e2e/Services/Databases/Tables/DatabasesConsoleClientTest.php (2)
186-194
: Fix assertion parameter order
assertEquals($expected, $actual)
– currently the arguments are swapped, so a failure message would misleadingly show the actual value as “expected”.- $this->assertEquals($response['body'], ""); + $this->assertEquals("", $response['body']);
226-235
: Avoid brittle “field-count” assertions
count($response['body']) === 15
will fail the moment a new field is legitimately added to the response.
Prefer checking for the specific keys you rely on:$this->assertArrayHasKey('rowsTotal', $response['body']); $this->assertArrayHasKey('tablesTotal', $response['body']);This keeps the test future-proof while still validating contract essentials.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php (1)
165-173
: Event parameters mix “row” and “document” IDsBoth
rowId
anddocumentId
are set to the same value, even when operating on the Collections API.If consumers rely on one of these keys being absent for collections vs tables, this may break them or create redundancy. Please either:
- drop
rowId
for collections, or- document the new behaviour in event-consumer code.
tests/e2e/Services/Databases/Tables/DatabasesPermissionsGuestTest.php (2)
20-72
: Duplicate helper exists in other permissions suites
createCollection()
largely duplicates logic fromDatabasesPermissionsMemberTest
andTeamTest
. Extract this into the sharedDatabasesPermissionsScope
trait to avoid diverging behaviour and reduce maintenance.
148-150
: Global auth role mutation could leak across tests
Authorization::cleanRoles()
/ manual restore relies on each test always reaching theforeach
restore block—even when an assertion fails. Wrap the role-manipulating section intry/finally
to guarantee cleanup.tests/e2e/General/AbuseTest.php (1)
332-346
: Missing success assertion for resource creation
$movies
(table/collection) is created without verifying its HTTP status code or payload.
Adding an assertion makes failures easier to pinpoint and keeps the helper symmetrical with the earlier database assertion.$movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . "/$endpoint", [ ... ]); + $this->assertEquals(201, $movies['headers']['status-code']); + $this->assertEquals('Movies', $movies['body']['name']);tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php (1)
126-353
: High duplication between Collections- and Tables-API tests
testAttributesCollectionsAPI()
andtestAttributesTablesAPI()
differ only by
– the root endpoint (collections
vstables
),
– the term (attributes
vscolumns
).Duplicating ~200 lines makes maintenance hard; every bug-fix must be applied twice. A small data-provider or a private helper that takes
{resourceType, attributeKey}
parameters would DRY this out while preserving coverage.No functional breakage, but refactoring will:
• cut test run-time,
• make future terminology migrations cheaper,
• reduce cognitive overhead.tests/e2e/Services/Databases/Tables/DatabasesCustomClientTest.php (1)
67-69
: Avoid fixedsleep()
calls in testsHard-coded sleeps (1-3 s) make the suite slower and flaky under load.
Polling the resource until itsstatus
becomesavailable|ready
(or until a timeout) is both faster in the common case and more robust.Consider extracting a helper like:
private function waitUntilReady(callable $probe, int $timeout = 15): void { $start = time(); while (time() - $start < $timeout) { if ($probe()) { return; } usleep(200_000); // 200 ms } $this->fail('Timed-out waiting for async worker'); }and replace the bare
sleep()
statements.src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (3)
421-422
: Rename parameter for consistencyThe parameter
$filter
is used to check againstformat
throughout the code. Rename it to$format
for better consistency and clarity.- final protected function updateAttribute(string $databaseId, string $collectionId, string $key, Database $dbForProject, Event $queueForEvents, string $type, int $size = null, string $filter = null, string|bool|int|float $default = null, bool $required = null, int|float|null $min = null, int|float|null $max = null, array $elements = null, array $options = [], string $newKey = null): Document + final protected function updateAttribute(string $databaseId, string $collectionId, string $key, Database $dbForProject, Event $queueForEvents, string $type, int $size = null, string $format = null, string|bool|int|float $default = null, bool $required = null, int|float|null $min = null, int|float|null $max = null, array $elements = null, array $options = [], string $newKey = null): DocumentRemember to update the parameter usage in line 449 as well.
421-422
: Consider reducing method parameter countThe
updateAttribute
method has 15 parameters, making it difficult to maintain and understand. Consider using a structured parameter object or builder pattern.A more maintainable approach would be to accept an options array or data transfer object:
- final protected function updateAttribute(string $databaseId, string $collectionId, string $key, Database $dbForProject, Event $queueForEvents, string $type, int $size = null, string $filter = null, string|bool|int|float $default = null, bool $required = null, int|float|null $min = null, int|float|null $max = null, array $elements = null, array $options = [], string $newKey = null): Document + final protected function updateAttribute( + string $databaseId, + string $collectionId, + string $key, + Database $dbForProject, + Event $queueForEvents, + string $type, + array $attributeOptions = [] + ): DocumentThen extract values from
$attributeOptions
with default values:$size = $attributeOptions['size'] ?? null; $format = $attributeOptions['format'] ?? null; // etc.
607-616
: Set context values consistentlyWhen setting event context parameters, both
attributeId
andcolumnId
are set to the same value, as aretableId
andcollectionId
. Consider setting only the context-relevant parameters for better clarity and reduced payload size.$queueForEvents ->setContext('database', $db) ->setParam('databaseId', $databaseId) - ->setParam('attributeId', $attribute->getId()) - ->setParam('columnId', $attribute->getId()) - ->setParam('tableId', $collection->getId()) - ->setParam('collectionId', $collection->getId()) + ->setParam($this->isCollectionsAPI() ? 'attributeId' : 'columnId', $attribute->getId()) + ->setParam($this->isCollectionsAPI() ? 'collectionId' : 'tableId', $collection->getId()) ->setContext($this->isCollectionsAPI() ? 'collection' : 'table', $collection);
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (67)
.github/workflows/tests.yml
(2 hunks)src/Appwrite/Event/Realtime.php
(1 hunks)src/Appwrite/Messaging/Adapter/Realtime.php
(3 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php
(1 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
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Action.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Boolean/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Boolean/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Datetime/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Datetime/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Delete.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Email/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Email/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Enum/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Enum/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Float/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Float/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Get.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/IP/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/IP/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Integer/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Integer/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Relationship/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Relationship/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/String/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/String/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/URL/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/URL/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/XList.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Delete.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Get.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Indexes/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Indexes/Delete.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Indexes/Get.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Indexes/XList.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Logs/XList.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Delete.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Get.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Logs/XList.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/XList.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Usage/Get.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/XList.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Workers/Databases.php
(17 hunks)tests/e2e/General/AbuseTest.php
(7 hunks)tests/e2e/General/UsageTest.php
(3 hunks)tests/e2e/Services/Databases/Tables/DatabasesConsoleClientTest.php
(1 hunks)tests/e2e/Services/Databases/Tables/DatabasesCustomClientTest.php
(1 hunks)tests/e2e/Services/Databases/Tables/DatabasesPermissionsGuestTest.php
(1 hunks)tests/e2e/Services/Databases/Tables/DatabasesPermissionsMemberTest.php
(1 hunks)tests/e2e/Services/Databases/Tables/DatabasesPermissionsScope.php
(1 hunks)tests/e2e/Services/Databases/Tables/DatabasesPermissionsTeamTest.php
(1 hunks)tests/e2e/Services/GraphQL/AuthTest.php
(3 hunks)tests/e2e/Services/GraphQL/Base.php
(19 hunks)tests/e2e/Services/GraphQL/DatabaseClientTest.php
(6 hunks)tests/e2e/Services/GraphQL/DatabaseServerTest.php
(29 hunks)tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php
(11 hunks)tests/e2e/Services/Realtime/RealtimeCustomClientTest.php
(19 hunks)
✅ Files skipped from review due to trivial changes (3)
- tests/e2e/Services/Databases/Tables/DatabasesPermissionsScope.php
- tests/e2e/Services/GraphQL/AuthTest.php
- tests/e2e/Services/GraphQL/Base.php
🚧 Files skipped from review as they are similar to previous changes (47)
- tests/e2e/Services/GraphQL/DatabaseClientTest.php
- .github/workflows/tests.yml
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Boolean/Update.php
- tests/e2e/Services/Realtime/RealtimeCustomClientTest.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Datetime/Update.php
- src/Appwrite/Event/Realtime.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Get.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Update.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Datetime/Create.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Enum/Create.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Delete.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Indexes/Create.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Float/Create.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/XList.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/XList.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Logs/XList.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/String/Update.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Usage/Get.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Float/Update.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Email/Create.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/URL/Update.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Update.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/String/Create.php
- tests/e2e/Services/GraphQL/DatabaseServerTest.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Boolean/Create.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Relationship/Create.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Delete.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/XList.php
- src/Appwrite/Messaging/Adapter/Realtime.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Delete.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Create.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Indexes/XList.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Relationship/Update.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Get.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/URL/Create.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/IP/Update.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Indexes/Get.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Indexes/Delete.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Enum/Update.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Logs/XList.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php
- src/Appwrite/Platform/Modules/Databases/Workers/Databases.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Get.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php
🧰 Additional context used
🧬 Code Graph Analysis (6)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Integer/Create.php (9)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Boolean/Create.php (4)
Create
(16-69)getName
(20-23)getResponseModel
(25-28)__construct
(30-68)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Email/Create.php (4)
Create
(17-70)getName
(21-24)getResponseModel
(26-29)__construct
(31-69)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Float/Create.php (4)
Create
(17-72)getName
(21-24)getResponseModel
(26-29)__construct
(31-71)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/IP/Create.php (4)
Create
(17-70)getName
(21-24)getResponseModel
(26-29)__construct
(31-69)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/String/Create.php (1)
Create
(19-74)src/Appwrite/Utopia/Response.php (1)
Response
(151-963)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Boolean/Update.php (3)
getName
(22-25)getResponseModel
(27-30)__construct
(32-70)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Integer/Update.php (3)
getName
(23-26)getResponseModel
(28-31)__construct
(33-73)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (3)
setContext
(42-49)getSdkNamespace
(82-85)getSdkGroup
(74-77)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/IP/Create.php (8)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Boolean/Create.php (4)
Create
(16-69)getName
(20-23)getResponseModel
(25-28)__construct
(30-68)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Email/Create.php (4)
Create
(17-70)getName
(21-24)getResponseModel
(26-29)__construct
(31-69)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/String/Create.php (1)
Create
(19-74)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/URL/Create.php (1)
Create
(17-70)src/Appwrite/Utopia/Response.php (1)
Response
(151-963)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Delete.php (3)
getName
(20-23)getResponseModel
(26-29)__construct
(31-67)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/IP/Update.php (3)
getName
(23-26)getResponseModel
(28-31)__construct
(33-71)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (3)
setContext
(42-49)getSdkNamespace
(82-85)getSdkGroup
(74-77)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Create.php (4)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php (1)
Create
(30-319)src/Appwrite/SDK/Method.php (1)
Method
(9-295)src/Appwrite/Utopia/Response.php (1)
Response
(151-963)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (3)
setContext
(25-32)getSdkNamespace
(65-68)getSdkGroup
(57-60)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Email/Update.php (7)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Boolean/Update.php (4)
Update
(18-71)getName
(22-25)getResponseModel
(27-30)__construct
(32-70)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Float/Update.php (4)
Update
(19-74)getName
(23-26)getResponseModel
(28-31)__construct
(33-73)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Integer/Update.php (4)
Update
(19-74)getName
(23-26)getResponseModel
(28-31)__construct
(33-73)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/String/Update.php (1)
Update
(21-75)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/URL/Update.php (1)
Update
(19-72)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Email/Update.php (1)
Update
(21-92)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Email/Create.php (3)
getName
(21-24)getResponseModel
(26-29)__construct
(31-69)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php (9)
src/Appwrite/Platform/Modules/Databases/Workers/Databases.php (2)
Databases
(21-630)action
(54-85)src/Appwrite/Event/Event.php (1)
Event
(10-600)src/Appwrite/Extend/Exception.php (1)
Exception
(7-439)src/Appwrite/Utopia/Response.php (2)
Response
(151-963)output
(716-798)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Delete.php (1)
Delete
(19-105)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (8)
Action
(8-130)getResponseModel
(18-18)getSdkNamespace
(65-68)getSdkGroup
(57-60)getParentNotFoundException
(73-78)getNotFoundException
(83-88)setContext
(25-32)isCollectionsAPI
(45-50)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Action.php (5)
Action
(8-95)getSdkGroup
(61-64)getNotFoundException
(79-84)setContext
(25-32)isCollectionsAPI
(53-56)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php (2)
getResponseModel
(39-42)action
(86-306)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php (1)
action
(72-156)
tests/e2e/General/AbuseTest.php (1)
tests/e2e/Client.php (1)
Client
(8-317)
⏰ Context from checks skipped due to timeout of 90000ms (9)
- GitHub Check: E2E Service Test (Webhooks)
- GitHub Check: E2E Service Test (Teams)
- GitHub Check: E2E Service Test (GraphQL)
- GitHub Check: E2E Service Test (Functions)
- GitHub Check: E2E Service Test (FunctionsSchedule)
- GitHub Check: E2E Service Test (Sites)
- GitHub Check: E2E Service Test (Databases/Collections)
- GitHub Check: E2E Service Test (Databases/Tables)
- GitHub Check: Benchmark
🔇 Additional comments (10)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/IP/Create.php (1)
1-70
: Implementation looks good and follows established patternsThe Create class correctly extends IPCreate, sets the appropriate context, and configures the HTTP endpoint with all necessary parameters. The implementation is consistent with other column type classes.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Integer/Update.php (1)
1-74
: Implementation looks good and follows established patternsThe Update class correctly extends IntegerUpdate, sets the appropriate context, and configures the HTTP endpoint with all necessary parameters. The implementation is consistent with other column type update classes.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Columns/Integer/Create.php (1)
1-72
: Implementation looks good and follows established patternsThe Create class correctly extends IntegerCreate, sets the appropriate context, and configures the HTTP endpoint with all necessary parameters. The implementation is consistent with other column type classes.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Create.php (2)
1-78
: Overall implementation follows established patternsThe class correctly extends DocumentCreate and sets up an appropriate endpoint for row creation with proper parameters and injected dependencies.
76-77
:✅ Verification successful
Verify action implementation with correct parameters
A previous review comment mentioned issues with the parent::action call regarding missing the $data parameter and having a duplicated $databaseId parameter. Ensure that this has been fixed in your implementation.
🏁 Script executed:
#!/bin/bash # Verify that the action method properly handles parameters # Check for any action method implementations in the class or parent class that might handle these parameters rg -A 10 "action\s*\(\s*[^)]*databaseId[^)]*" src/Appwrite/Platform/Modules/Databases/Http/Databases/Length of output: 62830
🏁 Script executed:
#!/bin/bash # Locate the Create action in Rows FILE="src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Create.php" # Show signature of action() and any parent::action calls rg -C3 "public function action" "$FILE" rg -C3 "parent::action" "$FILE"Length of output: 298
🏁 Script executed:
#!/bin/bash # Locate the Rows/Create.php file and display its contents find src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables -type f -name 'Create.php' -print echo "===== File Content: First 200 lines =====" find src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables -type f -name 'Create.php' -exec sed -n '1,200p' {} \;Length of output: 41320
🏁 Script executed:
#!/bin/bash # Show action implementation and any parent calls in Collections/Documents/Create FILE="src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php" # Display file location echo "File: $FILE" # Show lines around public function action rg -C3 "public function action" "$FILE" # Show any parent::action calls rg -C3 "parent::action" "$FILE"Length of output: 934
Verified correct action signature in createRow
The
createRow
handler inTables/Rows/Create.php
inheritsaction()
fromCollections/Documents/Create.php
, whose method signature is now:public function action( string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, UtopiaResponse $response, Database $dbForProject, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage ): voidNo
parent::action(...)
calls remain with missing or duplicated parameters. The parameters are injected in the correct order, so this concern is resolved.tests/e2e/General/UsageTest.php (1)
681-697
: Potential dangling-ID bug
$databaseId
is reused to store the last created database even when the delete branch runs first ($i < CREATE/2
).
Ifself::CREATE
is odd, the last preserved DB will be from the second half of the loop – fine.
But any later assertion that assumes$databaseId
is also the one that owns$tableId
(created in the next loop) silently relies on this coincidence.Please assert that the
$databaseId
used for tables is really the same DB that survived the deletion pass, or store them separately ($tablesDbId
).tests/e2e/Services/Databases/Tables/DatabasesConsoleClientTest.php (1)
19-29
: 🛠️ Refactor suggestionMethod name misrepresents what is being tested
testCreateCollection
handles tables (/tables
endpoint), not collections.
Given the coexistence of both terminologies in the codebase, accurate naming is vital for maintainability and grep-ability.Rename to
testCreateTable
(and analogously update the dependent methods).-class DatabasesConsoleClientTest extends Scope -{ - … - public function testCreateCollection(): array +class DatabasesConsoleClientTest extends Scope +{ + … + public function testCreateTable(): arrayLikely an incorrect or invalid review comment.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php (1)
150-155
: Metric constant looks mismatched with the comment
addMetric(str_replace('{databaseInternalId}', …, METRIC_DATABASE_ID_OPERATIONS_WRITES), 1);
The inline comment says “per collection”, but the placeholder only contains the database internal ID. Double-check the constant name and ensure you are not accidentally aggregating per-database when per-collection was intended.src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php (1)
99-104
: Missing context for worker queue may cause stale cacheAfter queuing the database job you purge the collection cache locally (
purgeCachedDocument
) but do not enqueue a follow-up event to purge edge caches (as done in the Collection Delete path). Confirm that the worker invoked viaDATABASE_TYPE_DELETE_INDEX
eventually invalidates caches; otherwise clients may still receive the removed index.src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (1)
1-30
: Good job implementing the dual-API architecture!The abstract
Action
class provides a clean abstraction for handling both collections/attributes and tables/columns APIs through a single codebase. The context-aware exception handling and response models create an elegant solution for supporting both terminologies.
tests/e2e/Services/Databases/Tables/DatabasesPermissionsMemberTest.php
Outdated
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php
Outdated
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 16
♻️ Duplicate comments (9)
src/Appwrite/Utopia/Response/Model/Table.php (2)
114-136
: Preserve legacy attributes for backward compatibility.The current implementation removes legacy attributes after copying them to new keys. This approach might break existing API consumers who depend on the original attribute names. Consider preserving both old and new keys during a transition period to ensure backward compatibility.
$document->setAttribute('columns', $columns); + // Preserve the legacy attribute for backward compatibility + $document->setAttribute('attributes', $columns); $related = $document->getAttribute('relatedCollection'); if ($related !== null) { $document->setAttribute('relatedTable', $related); + // Keep the legacy attribute + // $document->setAttribute('relatedCollection', $related); } $documentSecurity = $document->getAttribute('documentSecurity'); $document->setAttribute('rowSecurity', $documentSecurity); + // Keep the legacy attribute + $document->setAttribute('documentSecurity', $documentSecurity); // remove anyways as they are already copied above. $document - ->removeAttribute('attributes') - ->removeAttribute('documentSecurity') - ->removeAttribute('relatedCollection');If you decide to remove legacy attributes, consider:
- Documenting this as a breaking change in your release notes
- Incrementing the major version number (following semantic versioning)
- Providing a migration guide for API consumers
144-148
: Check if target key exists before remapping.The remapping function should verify if the target key already exists before overwriting it. This prevents potential data loss if both keys were somehow present.
foreach ($columns as $i => $column) { if (isset($column['relatedCollection'])) { - $columns[$i]['relatedTable'] = $column['relatedCollection']; + if (!isset($columns[$i]['relatedTable'])) { + $columns[$i]['relatedTable'] = $column['relatedCollection']; + } unset($columns[$i]['relatedCollection']); } }tests/e2e/Services/Databases/Tables/DatabasesPermissionsGuestTest.php (2)
65-66
: Replace sleep() with a more reliable waiting mechanismHard-coded
sleep(2)
assumes the worker finishes within two seconds. In CI this is often either unnecessarily long (slowing the test suite) or not long enough (causing sporadic failures).Consider polling for the column status until it becomes
available
, or use the existing helperwaitForAttribute()
that other tests employ.
260-260
: 🛠️ Refactor suggestionReplace sleep() with a more reliable waiting mechanism
Similar to the earlier sleep(2), this hard-coded delay is brittle and can cause inconsistent test behavior.
Consider polling for the column status until it becomes
available
, or use an existing helper method.- sleep(1); + // Wait for the column to be available + $this->waitForAttribute($dbForProject, 'attributes', function ($attribute) use ($moviesId) { + return $attribute->getAttribute('collectionId') === $moviesId + && $attribute->getAttribute('key') === 'title' + && $attribute->getAttribute('status') === 'available'; + }, 10, 0.5);src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php (2)
252-283
: Guard against cyclic relationships to prevent infinite recursion
$processDocument()
is recursively called for every related document but there is no visited-set / depth limit. A cyclic relationship (A→B, B→A) will cause a stack overflow and take down the worker.Consider keeping a
SplObjectStorage
/$visitedIds
set and short-circuiting when a document has already been processed.
289-295
:⚠️ Potential issueWrong variable referenced – sensitive attributes list is always
null
The callback passed to
array_map
references$document
from the outer scope instead of the$row
(attribute) passed into the closure. This produces an array filled withnull
, sosetPayload()
never flags any relationship keys as sensitive.-$relationships = \array_map( - fn ($document) => $document->getAttribute('key'), +$relationships = \array_map( + fn ($attribute) => $attribute->getAttribute('key'), \array_filter( $collection->getAttribute('attributes', []), fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ) );tests/e2e/Services/Databases/Tables/DatabasesCustomClientTest.php (1)
14-18
:⚠️ Potential issueTrait usage error
The current trait usage will cause a fatal error. The
DatabasesBase
trait is referenced without proper namespace qualification or import.- use DatabasesBase; + use \Tests\E2E\Services\Databases\DatabasesBase;Or add an import statement at the top:
use Tests\E2E\Services\Databases\DatabasesBase;src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (2)
475-477
:empty($size)
swallows legitimate zero – use strict null check
This issue was flagged in a previous review and is still present.Using
empty()
treats0
as “empty”, preventing clients from resizing to zero.
Check fornull
instead.
453-459
:⚠️ Potential issueBroken conditional – parentheses turn the whole check into a boolean
Both lines accidentally wrap the field name in parentheses, so PHP first evaluates the comparison (
'type' !== $type
) and then passes true/false togetAttribute()
.
Consequently the validation is never executed as intended.- if ($attribute->getAttribute(('type') !== $type)) { + if ($attribute->getAttribute('type') !== $type) { ... - if ($attribute->getAttribute('type') === Database::VAR_STRING && $attribute->getAttribute(('filter') !== $filter)) { + if ( + $attribute->getAttribute('type') === Database::VAR_STRING && + $attribute->getAttribute('format') !== $filter // probable field name + ) {
🧹 Nitpick comments (19)
tests/e2e/Services/GraphQL/Collections/DatabaseServerTest.php (1)
16-16
: Consider renaming the test class to match the new terminology.While the namespace has been updated to reflect the collections module, the class name
DatabaseServerTest
still uses the old terminology. Consider renaming it toCollectionsServerTest
for better consistency with the new terminology and namespace structure.-class DatabaseServerTest extends Scope +class CollectionsServerTest extends Scopetests/e2e/Services/GraphQL/Collections/DatabaseClientTest.php (1)
14-14
: Consider renaming the test class to match the new terminology.While the namespace has been updated to reflect the collections module, the class name
DatabaseClientTest
still uses the old terminology. Consider renaming it toCollectionsClientTest
for better consistency with the new terminology and namespace structure.-class DatabaseClientTest extends Scope +class CollectionsClientTest extends Scopetests/e2e/Services/GraphQL/Tables/AuthTest.php (2)
143-143
: Investigate the need for sleep in the setup method.The
sleep(1)
call at the end of the setup method suggests there might be a race condition or timing issue with the created resources. Consider if this delay is necessary or if there's a more deterministic way to ensure resources are ready, such as waiting for specific conditions or implementing a retry mechanism.
250-251
: Consider a more specific assertion for deletion response.The assertion
assertIsNotArray
is somewhat vague. Since you're testing a successful deletion response, consider using more specific assertions that directly validate the expected response structure or status code.- $this->assertIsNotArray($row['body']); + $this->assertEmpty($row['body']); // Or more specifically check for an expected structure $this->assertEquals(204, $row['headers']['status-code']);src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Create.php (1)
51-52
: Update documentation reference to reflect tables instead of collections.The SDK description points to the collections documentation instead of tables-specific documentation. Update the documentation reference to point to the appropriate table documentation.
- description: '/docs/references/databases/create-collection.md', + description: '/docs/references/databases/create-table.md',src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Update.php (2)
50-51
: Update documentation reference to reflect tables instead of collections.The SDK description points to the collections documentation instead of tables-specific documentation. Update the documentation reference to point to the appropriate table documentation.
- description: '/docs/references/databases/update-collection.md', + description: '/docs/references/databases/update-table.md',
62-63
: Fix parameter description to reference table instead of collection.The parameter description refers to "Collection name" instead of "Table name", which is inconsistent with the class's purpose.
- ->param('name', null, new Text(128), 'Collection name. Max length: 128 chars.') + ->param('name', null, new Text(128), 'Table name. Max length: 128 chars.')tests/e2e/Services/GraphQL/Tables/AbuseTest.php (2)
32-32
: Method name inconsistent with Tables API terminology.The method name
createCollection
is called here but creates tables with the new Tables API. This mismatch in terminology could cause confusion for developers maintaining these tests.Consider renaming the helper method to
createTable
to align with the Tables API terminology:- $data = $this->createCollection(); + $data = $this->createTable();
178-178
: Add a comment explaining the sleep.The sleep is necessary for eventual consistency but lacks a comment explaining its purpose.
Add a comment to explain why this sleep is necessary:
- sleep(2); + // Sleep to ensure the column is fully indexed and available for queries + sleep(2);src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Action.php (1)
18-18
: Add more detailed documentation for abstract method.The abstract method
getResponseModel()
lacks detailed documentation about what implementing classes should return.Enhance the documentation to provide more guidance for implementers:
/** * Get the response model used in the SDK and HTTP responses. + * + * @return string The fully qualified class name of the response model to use + * for this action. This model will be used in both SDK code generation + * and HTTP responses. */ abstract protected function getResponseModel(): string;tests/e2e/Services/Databases/Tables/DatabasesConsoleClientTest.php (2)
53-54
: Assertion parameter order is inconsistent.The parameter order in this assertion puts the actual value first, unlike other assertions in the codebase that put expected value first.
- $this->assertEquals($movies['body']['name'], 'Movies'); + $this->assertEquals('Movies', $movies['body']['name']);
226-227
: Remove extra blank lines.Multiple consecutive blank lines where one would be sufficient.
]); - - $this->assertEquals(200, $response['headers']['status-code']); + + $this->assertEquals(200, $response['headers']['status-code']);tests/e2e/Services/GraphQL/Tables/DatabaseClientTest.php (2)
155-155
: Add a comment explaining the sleep.The sleep is necessary for eventual consistency but lacks a comment explaining its purpose.
- sleep(1); + // Sleep to ensure columns are fully indexed and available for row creation + sleep(1);
278-278
: Improve assertion robustness.Using
assertStringContainsString
on JSON data is brittle as it depends on the exact string representation.Consider decoding the JSON data and making a more precise assertion:
- $this->assertStringContainsString('New Row Name', $row['data']); + $decodedData = json_decode($row['data'], true); + $this->assertEquals('New Row Name', $decodedData['name']);tests/e2e/Services/Databases/Tables/DatabasesPermissionsGuestTest.php (3)
20-72
: Consider renaming method to better reflect its purposeThe method
createCollection()
is actually creating tables, not collections. This naming mismatch might create confusion when the code is maintained or reviewed later.Rename the method to
createTable()
for clarity, or update the internal variable names to be consistent with the Tables API terminology.
51-52
: Use consistent terminology in variable namesThe variables
publicCollection
andprivateCollection
store table IDs, not collection IDs. This inconsistent naming might lead to confusion.- $publicCollection = ['id' => $publicMovies['body']['$id']]; - $privateCollection = ['id' => $privateMovies['body']['$id']]; + $publicTable = ['id' => $publicMovies['body']['$id']]; + $privateTable = ['id' => $privateMovies['body']['$id']];And update all references to these variables accordingly.
68-70
: Align return variable names with Tables API terminologyThe return array uses
publicCollectionId
andprivateCollectionId
even though they refer to table IDs, not collection IDs.- 'publicCollectionId' => $publicCollection['id'], - 'privateCollectionId' => $privateCollection['id'], + 'publicTableId' => $publicTable['id'], + 'privateTableId' => $privateTable['id'],And update all references to these variables accordingly.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php (1)
32-33
: Remove or address the TODO commentThe comment "we should correctly & carefully set the context later" suggests incomplete implementation or a reminder for future work. Either implement the suggested change or remove the comment if it's no longer applicable.
tests/e2e/Services/GraphQL/Tables/DatabaseServerTest.php (1)
150-152
: Avoid fixedsleep()
– replace with polling for eventual consistencyHard-coded sleeps (1–3 s) slow the suite and are flaky under load.
Prefer a helper that polls the API until the column status isavailable
or a timeout occurs.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
src/Appwrite/Event/Realtime.php
(3 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php
(1 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
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Action.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Update.php
(1 hunks)src/Appwrite/Utopia/Response/Model/Table.php
(1 hunks)tests/e2e/General/AbuseTest.php
(7 hunks)tests/e2e/Services/Databases/Tables/DatabasesConsoleClientTest.php
(1 hunks)tests/e2e/Services/Databases/Tables/DatabasesCustomClientTest.php
(1 hunks)tests/e2e/Services/Databases/Tables/DatabasesPermissionsGuestTest.php
(1 hunks)tests/e2e/Services/Databases/Tables/DatabasesPermissionsMemberTest.php
(1 hunks)tests/e2e/Services/GraphQL/Base.php
(23 hunks)tests/e2e/Services/GraphQL/Collections/AbuseTest.php
(2 hunks)tests/e2e/Services/GraphQL/Collections/AuthTest.php
(4 hunks)tests/e2e/Services/GraphQL/Collections/DatabaseClientTest.php
(7 hunks)tests/e2e/Services/GraphQL/Collections/DatabaseServerTest.php
(30 hunks)tests/e2e/Services/GraphQL/Tables/AbuseTest.php
(1 hunks)tests/e2e/Services/GraphQL/Tables/AuthTest.php
(1 hunks)tests/e2e/Services/GraphQL/Tables/DatabaseClientTest.php
(1 hunks)tests/e2e/Services/GraphQL/Tables/DatabaseServerTest.php
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
- src/Appwrite/Event/Realtime.php
- tests/e2e/Services/Databases/Tables/DatabasesPermissionsMemberTest.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php
- tests/e2e/General/AbuseTest.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php
🧰 Additional context used
🧠 Learnings (1)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Action.php (1)
Learnt from: ItzNotABug
PR: appwrite/appwrite#9693
File: src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php:85-86
Timestamp: 2025-05-10T04:12:13.012Z
Learning: The class `Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Indexes\Action` defines a method `getGrantParentNotFoundException()` which is used to handle cases where a parent resource (like a database collection) is not found.
🧬 Code Graph Analysis (4)
tests/e2e/Services/GraphQL/Collections/AuthTest.php (1)
tests/e2e/Client.php (1)
Client
(8-317)
tests/e2e/Services/GraphQL/Tables/AbuseTest.php (4)
tests/e2e/Client.php (1)
Client
(8-317)tests/e2e/Services/GraphQL/Collections/AbuseTest.php (6)
AbuseTest
(15-185)setUp
(21-28)testRateLimitEnforced
(30-63)createCollection
(117-184)testComplexQueryBlocked
(65-97)testTooManyQueriesBlocked
(99-115)tests/e2e/Services/GraphQL/Base.php (1)
getQuery
(482-2938)src/Appwrite/Utopia/Request.php (1)
getHeaders
(147-169)
src/Appwrite/Utopia/Response/Model/Table.php (13)
src/Appwrite/Utopia/Response.php (1)
Response
(151-963)src/Appwrite/Event/Database.php (1)
Database
(9-186)src/Appwrite/Utopia/Response/Model/Document.php (1)
Document
(8-92)src/Appwrite/Utopia/Response/Model/ColumnIndex.php (3)
getName
(70-73)getType
(78-81)filter
(83-93)src/Appwrite/Utopia/Response/Model/Index.php (2)
getName
(69-72)getType
(77-80)src/Appwrite/Utopia/Response/Model/ColumnRelationship.php (3)
getName
(63-66)getType
(73-76)filter
(83-95)src/Appwrite/Utopia/Response/Model/Column.php (2)
getName
(71-74)getType
(81-84)src/Appwrite/Utopia/Response/Model/ColumnBoolean.php (2)
getName
(45-48)getType
(55-58)src/Appwrite/Utopia/Response/Model/ColumnDatetime.php (2)
getName
(53-56)getType
(63-66)src/Appwrite/Utopia/Response/Model/ColumnEmail.php (1)
getType
(62-65)src/Appwrite/Utopia/Response/Model/ColumnEnum.php (1)
getType
(69-72)src/Appwrite/Utopia/Response/Model/ColumnFloat.php (1)
getType
(69-72)src/Appwrite/Utopia/Response/Model/ColumnIP.php (1)
getType
(62-65)
tests/e2e/Services/Databases/Tables/DatabasesPermissionsGuestTest.php (4)
tests/e2e/Client.php (1)
Client
(8-317)tests/e2e/Services/Databases/Tables/DatabasesPermissionsScope.php (1)
getServerHeader
(79-86)tests/e2e/Services/Databases/Tables/DatabasesPermissionsMemberTest.php (2)
permissionsProvider
(29-105)testReadDocuments
(199-270)tests/e2e/Services/Databases/Tables/DatabasesPermissionsTeamTest.php (1)
testReadDocuments
(167-181)
⏰ Context from checks skipped due to timeout of 90000ms (18)
- GitHub Check: E2E Service Test (Webhooks)
- GitHub Check: E2E Service Test (Proxy)
- GitHub Check: E2E Service Test (Teams)
- GitHub Check: E2E Service Test (Users)
- GitHub Check: E2E Service Test (Messaging)
- GitHub Check: E2E Service Test (Migrations)
- GitHub Check: E2E Service Test (Locale)
- GitHub Check: E2E Service Test (Storage)
- GitHub Check: E2E Service Test (Sites)
- GitHub Check: E2E Service Test (FunctionsSchedule)
- GitHub Check: E2E Service Test (Realtime)
- GitHub Check: E2E Service Test (Functions)
- GitHub Check: E2E Service Test (GraphQL)
- GitHub Check: E2E Service Test (Databases)
- GitHub Check: E2E Service Test (Avatars)
- GitHub Check: E2E Service Test (Account)
- GitHub Check: E2E General Test
- GitHub Check: Benchmark
🔇 Additional comments (30)
tests/e2e/Services/GraphQL/Collections/AbuseTest.php (3)
3-3
: Namespace updated to reflect collections module structure.The namespace has been updated from
Tests\E2E\Services\GraphQL
toTests\E2E\Services\GraphQL\Collections
, which aligns with the modularization of collections-related tests in the PR. This change improves code organization by properly categorizing tests by their domain.
9-9
: Base trait properly imported for shared functionality.Adding the import for
Tests\E2E\Services\GraphQL\Base
allows the test to reuse common GraphQL testing functionality shared between Collections and Tables tests, supporting the dual API structure introduced in this PR.
117-117
: Type declaration added to improve code safety.Adding the return type declaration
: array
to thecreateCollection
method improves type safety and code readability, making it clear that this method returns an array containing the created database and collection IDs.tests/e2e/Services/GraphQL/Collections/AuthTest.php (3)
3-3
: Namespace updated to reflect collections module structure.The namespace has been updated from
Tests\E2E\Services\GraphQL
toTests\E2E\Services\GraphQL\Collections
, which aligns with the modularization of collections-related tests in the PR.
9-9
: Base trait properly imported for shared functionality.Adding the import for
Tests\E2E\Services\GraphQL\Base
allows the test to reuse common GraphQL testing functionality shared between Collections and Tables tests.
182-182
:✅ Verification successful
GraphQL schema key updated from databases to collections terminology.
The response key references have been updated from a
databases*
prefix to acollections*
prefix (collectionsCreateDocument
,collectionsGetDocument
), which aligns with the new terminology introduced in this PR. This ensures the tests correctly validate the response structure from the updated GraphQL schema.Let's verify that this naming convention change is consistent with the GraphQL schema definition:
Also applies to: 191-191, 241-241
🏁 Script executed:
#!/bin/bash # Check if the GraphQL schema uses the new collections terminology rg -A 3 "type.*Collections|type.*Document" --type phpLength of output: 2317
🏁 Script executed:
#!/bin/bash # Search for GraphQL schema keys for create/get document in collections or databases rg -n "collectionsCreateDocument" rg -n "databasesCreateDocument" rg -n "collectionsGetDocument" rg -n "databasesGetDocument" # Search for GraphQL field definitions referencing these keys rg -n "->field('collectionsCreateDocument'" rg -n "->field('databasesCreateDocument'" rg -n "->field('collectionsGetDocument'" rg -n "->field('databasesGetDocument'" # List GraphQL schema files by extension fd -e graphql fd -e gqlLength of output: 3368
🏁 Script executed:
#!/bin/bash set -e # Search for GraphQL usage in code files (excluding tests) rg -n "GraphQL" --type php | grep -v "tests/e2e" || true # List directories with GraphQL in name fd -t d GraphQL || true # Search for field definitions for createDocument & getDocument including database prefix rg -n "CreateDocument" --type php | grep -E "databases|collections" || true rg -n "GetDocument" --type php | grep -E "databases|collections" || trueLength of output: 10510
Approve GraphQL terminology update
All GraphQL operation names have been correctly renamed fromdatabasesCreateDocument
/databasesGetDocument
tocollectionsCreateDocument
/collectionsGetDocument
. There are no remainingdatabases*
keys in tests or schema code.Affected files:
- tests/e2e/Services/GraphQL/Collections/AuthTest.php (lines 182, 191, 241)
- tests/e2e/Services/GraphQL/Collections/DatabaseClientTest.php (lines 185, 245)
- tests/e2e/Services/GraphQL/Collections/DatabaseServerTest.php (lines 878, 1179)
- tests/e2e/Services/GraphQL/Base.php (lines 1075, 1096)
tests/e2e/Services/GraphQL/Collections/DatabaseServerTest.php (3)
3-3
: Namespace updated to reflect collections module structure.The namespace has been updated from
Tests\E2E\Services\GraphQL
toTests\E2E\Services\GraphQL\Collections
, which aligns with the modularization of collections-related tests in the PR.
10-10
: Base trait properly imported for shared functionality.Adding the import for
Tests\E2E\Services\GraphQL\Base
allows the test to reuse common GraphQL testing functionality shared between Collections and Tables tests.
139-140
: GraphQL schema references updated from databases to collections terminology.Multiple assertions throughout the file have been updated to use the collections-prefixed response keys instead of the databases-prefixed keys, aligning with the new terminology introduced in this PR. This comprehensive update ensures all test assertions correctly validate the responses from the updated GraphQL schema.
Also applies to: 172-174, 242-247, 310-312, 380-385, 449-451, 526-530, 594-596, 724-726, 791-793, 827-827, 832-832, 878-878, 1046-1046, 1073-1073, 1099-1099, 1126-1126, 1152-1152, 1179-1179, 1310-1310
tests/e2e/Services/GraphQL/Collections/DatabaseClientTest.php (3)
3-3
: Namespace updated to reflect collections module structure.The namespace has been updated from
Tests\E2E\Services\GraphQL
toTests\E2E\Services\GraphQL\Collections
, which aligns with the modularization of collections-related tests in the PR.
9-9
: Base trait properly imported for shared functionality.Adding the import for
Tests\E2E\Services\GraphQL\Base
allows the test to reuse common GraphQL testing functionality shared between Collections and Tables tests.
112-112
: GraphQL schema references updated from databases to collections terminology.Multiple assertions throughout the file have been updated to use the collections-prefixed response keys instead of the databases-prefixed keys, aligning with the new terminology introduced in this PR. This comprehensive update ensures all test assertions correctly validate the responses from the updated GraphQL schema.
Also applies to: 144-144, 185-185, 218-218, 245-245, 275-275
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Delete.php (1)
72-156
: Code handles attribute deletion properly with comprehensive validationThe implementation correctly:
- Validates database, collection, and attribute existence
- Checks for index dependencies before allowing deletion
- Handles relationship attributes and their two-way relationships
- Updates attribute status and purges cached documents
- Adapts database actions based on current API context (Collections or Tables)
- Sends appropriate events with parameters for both context types
This is a robust implementation with good error handling.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (1)
8-138
: Well-designed abstraction for context-aware document operationsThis abstract class provides a solid foundation for handling both Collections API and Tables API operations with the same codebase. The context-switching methods and exception mapping are clean and effective.
Key strengths:
- Clear distinction between contexts with constants
- Type-safe context setting with validation
- Consistent exception mapping based on current context
- Centralized SDK namespace and group handling
- Protected helper methods that encapsulate context-specific logic
This approach will simplify maintenance as both APIs evolve.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php (1)
86-232
: Document update implementation handles permissions and relationships properlyThe implementation correctly:
- Validates input data and permissions
- Checks authorization for managing permissions
- Maintains existing permissions when none are provided
- Processes nested relationships recursively
- Tracks operation count for metrics
- Sets appropriate headers for debugging
The approach to handling nested document relationships is thorough and supports both single relationships and arrays of related documents.
tests/e2e/Services/GraphQL/Base.php (10)
58-84
: Well-structured column constants parallel to attribute constantsThe column-related constants are implemented as direct parallels to the existing attribute constants, facilitating the transition to the new Tables/Columns terminology while maintaining consistency with the existing Collections/Attributes API.
85-96
: Clean separation of index operations for both APIsThe clear separation between attribute indexes and column indexes in the constants will make it easier for developers to understand which API they're working with, while maintaining consistent operation naming across both APIs.
104-110
: Row operations mirror document operationsThe new row operations constants match the existing document operations, providing a consistent API experience across both terminologies.
386-459
: Column fragments mirror attribute fragments structureThe column fragments implementation provides the same structure and functionality as the attribute fragments, ensuring consistent GraphQL query capabilities across both APIs.
567-611
: Tables GraphQL queries mirror Collections queriesThe implementation of table queries follows the same pattern as collection queries, ensuring consistency across both APIs and making it easier for developers to transition between them.
788-963
: Comprehensive column operations mirror attribute operationsThe column operations for all data types (string, integer, float, etc.) are implemented to match their attribute counterparts, ensuring feature parity between the two APIs.
997-1029
: Column index operations mirror attribute index operationsThe column index operations follow the same pattern as attribute index operations, with appropriate naming changes to reflect the new terminology.
1051-1071
: Tables column operations mirror collection attribute operationsThe implementation of column list and get operations use the column fragments in the same way that attribute operations use attribute fragments, maintaining consistency between the APIs.
1102-1130
: Row operations mirror document operationsThe row operations (get, list, create) are implemented to mirror document operations, ensuring consistency between the two APIs and facilitating developer transition.
1204-1217
: Row update and delete match document operationsThe row update and delete operations match their document counterparts, completing the parallel implementation between the two APIs.
tests/e2e/Services/Databases/Tables/DatabasesCustomClientTest.php (5)
20-108
: Comprehensive test for permission mappingThis test thoroughly validates how permissions are propagated from the table level to row level, confirming that:
write
permission at table level converts tocreate
,update
, anddelete
write
permission at row level converts to onlyupdate
anddelete
(notcreate
)- Trying to add
create
permission to a row returns an errorThe test effectively verifies the security model is working as expected.
110-227
: Thorough permission validation testThis test validates an important permission behavior: when a row has been created by a server-side operation, a client should be able to update it without needing to explicitly adjust permissions. The test:
- Creates database, table, and adds a column
- Creates a row with server credentials with specific permissions
- Verifies a client can update the row without having update permission
- Properly cleans up resources afterwards
The test includes appropriate sleep intervals to wait for asynchronous database workers to complete their tasks.
229-318
: Two-way relationship test with onDelete behaviorThis test confirms that a two-way relationship between tables can be properly established and updated, specifically verifying that the
onDelete
behavior can be changed from "cascade" to "restrict" and is correctly reflected in both related tables.
320-476
: Comprehensive relationship constraints testThis test verifies important constraints for relationships between tables:
- Duplicate
twoWayKey
values are rejected with appropriate error messages- Default
twoWayKey
generation works when omitted- Multiple many-to-many relationships on the same table are correctly restricted
The test includes appropriate validation of response status codes and error messages.
478-892
: Thorough relationship permission testThis extensive test verifies permission behavior for operations involving relationships:
- Tests updating nested relationships with and without proper permissions
- Validates that permission checks are properly applied to each level of related entities
- Tests linking of existing and newly created related entities
- Verifies proper error codes when permissions are missing
The test establishes a complex hierarchy of related tables with varying permission settings to thoroughly test all scenarios.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Action.php
Outdated
Show resolved
Hide resolved
tests/e2e/Services/Databases/Tables/DatabasesConsoleClientTest.php
Outdated
Show resolved
Hide resolved
tests/e2e/Services/Databases/Tables/DatabasesConsoleClientTest.php
Outdated
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php
Outdated
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php
Show resolved
Hide resolved
There was a problem hiding this 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 (4)
tests/e2e/Services/Databases/Tables/DatabasesConsoleClientTest.php (2)
129-129
: Variable name inconsistent with Tables API terminology.The variable name uses "Collection" terminology but is used with table operations.
- $moviesCollectionId = $data['moviesId']; + $moviesTableId = $data['moviesId'];
154-154
: Variable name inconsistent with Tables API terminology.The variable name uses "Collection" terminology but is used with table operations.
- $moviesCollectionId = $data['moviesId']; + $moviesTableId = $data['moviesId'];src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php (1)
122-133
:Permission::aggregate()
may receivenull
– call after the fallback is built
Permission::aggregate()
is executed before thenull
‐check. If the helper expects an array (as it does in other Appwrite helpers) it will throw a type error whenpermissions
is omitted from the request.- // Map aggregate permissions to into the set of individual permissions they represent. - $permissions = Permission::aggregate($permissions, $allowedPermissions); - - // Add permissions for current the user if none were provided. - if (\is_null($permissions)) { + // Add permissions for the current user if none were provided. + if (\is_null($permissions)) { $permissions = []; if (!empty($user->getId())) { foreach ($allowedPermissions as $permission) { $permissions[] = (new Permission($permission, 'user', $user->getId()))->toString(); } } } + + // Map aggregate permissions into the individual permissions they represent. + $permissions = Permission::aggregate($permissions, $allowedPermissions);tests/e2e/Services/GraphQL/Base.php (1)
28-29
: Constants now use consistent singular form.The UPDATE_TABLE and DELETE_TABLE constants are now correctly using the singular form ('update_table' and 'delete_table') which aligns with the other operation constants in the codebase.
🧹 Nitpick comments (11)
tests/e2e/Services/Databases/Tables/DatabasesConsoleClientTest.php (4)
19-98
: Method implementation looks good, but variable naming in return value could be improved.The
testCreateTable
method effectively tests table creation under various conditions, including when the database is disabled. However, the return value on line 97 could be more consistent with the Tables API terminology.- return ['moviesId' => $movies['body']['$id'], 'databaseId' => $databaseId, 'tvShowsId' => $tvShows['body']['$id']]; + return ['tableId' => $movies['body']['$id'], 'databaseId' => $databaseId, 'tvShowsTableId' => $tvShows['body']['$id']];This would require updating the variable names in dependent test methods.
159-159
: Update method parameter to match variable naming.For consistency, update the parameter name in the API call to match the variable name.
- $table = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/tables/' . $moviesCollectionId, array_merge([ + $table = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/tables/' . $moviesTableId, array_merge([
257-257
: Update variable name in the request endpoint.The endpoint uses "randomCollectionId" which is inconsistent with the Tables API terminology.
- $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables/randomCollectionId/usage', array_merge([ + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables/randomTableId/usage', array_merge([
134-142
: Use more descriptive variable name.The method correctly tests retrieving a specific table when both database and table are disabled, but consider using a more descriptive variable name.
- $table = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables/' . $moviesCollectionId, array_merge([ + $moviesTable = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/tables/' . $moviesTableId, array_merge([Then update the assertions accordingly.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php (2)
125-126
: Fix grammar in commentThere's a grammatical error in the comment.
- // Add permissions for current the user if none were provided. + // Add permissions for the current user if none were provided.
301-318
: Clearly document the purpose of sensitive relationships markingThe code marks relationships as sensitive in the event payload, but doesn't provide a comment explaining why this is necessary or what the implications are.
Consider adding a clarifying comment before the event queuing code:
$relationships = \array_map( fn ($document) => $document->getAttribute('key'), \array_filter( $collection->getAttribute('attributes', []), fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP ) ); + // Mark relationship fields as sensitive to prevent exposing potentially private related document data + // in events and notifications $queueForEvents ->setParam('databaseId', $databaseId) ->setContext('database', $database) ->setParam('collectionId', $collection->getId()) ->setParam('tableId', $collection->getId()) ->setParam('documentId', $document->getId()) ->setParam('rowId', $document->getId()) ->setPayload($response->getPayload(), sensitive: $relationships) ->setContext($this->getCollectionsEventsContext(), $collection);src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (2)
91-118
: Add validation for empty cursorDocument arrayThe code could handle the case where
$cursorDocument
is an empty array more explicitly, though it does check this withempty($cursorDocument)
. A slightly more robust approach would be to check the array size before accessing index 0.$indexId = $cursor->getValue(); $cursorDocument = Authorization::skip(fn () => $dbForProject->find('indexes', [ Query::equal('collectionInternalId', [$collection->getInternalId()]), Query::equal('databaseInternalId', [$database->getInternalId()]), Query::equal('key', [$indexId]), Query::limit(1) ])); - if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) { + if (empty($cursorDocument) || count($cursorDocument) === 0 || $cursorDocument[0]->isEmpty()) { throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Index '{$indexId}' for the 'cursor' value not found."); } $cursor->setValue($cursorDocument[0]);
126-127
: Improve variable naming for collection/table-specific error message componentsThe variables used for constructing error messages are named with singular forms, but they represent plural concepts in the message. This could be a source of confusion when reading the code.
- $documents = $this->isCollectionsAPI() ? 'documents' : 'rows'; - $attribute = $this->isCollectionsAPI() ? 'attribute' : 'column'; + $documentsOrRows = $this->isCollectionsAPI() ? 'documents' : 'rows'; + $attributeOrColumn = $this->isCollectionsAPI() ? 'attribute' : 'column'; - $message = "The order $attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all $documents order $attribute values are non-null."; + $message = "The order $attributeOrColumn '{$e->getAttribute()}' had a null value. Cursor pagination requires all $documentsOrRows order $attributeOrColumn values are non-null.";src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Action.php (3)
27-29
: Consider using constant values in error messageThe error message in the
setContext
method uses string literals instead of the constant names themselves, which could lead to inconsistency if the constant values change.if (!\in_array($context, [DATABASE_INDEX_CONTEXT, DATABASE_COLUMN_INDEX_CONTEXT], true)) { - throw new \InvalidArgumentException("Invalid context '$context'. Must be either `DATABASE_COLUMN_INDEX_CONTEXT` or `DATABASE_INDEX_CONTEXT`."); + throw new \InvalidArgumentException("Invalid context '$context'. Must be either DATABASE_COLUMN_INDEX_CONTEXT or DATABASE_INDEX_CONTEXT."); }
10-14
: Document default context value with a commentThe class initializes
$context
withDATABASE_INDEX_CONTEXT
, but it's not immediately clear why this is the default. Adding a comment would clarify the design decision./** * The current API context (either 'columnIndex' or 'index'). + * + * Defaults to DATABASE_INDEX_CONTEXT for compatibility with the collections API. */ private ?string $context = DATABASE_INDEX_CONTEXT;
156-163
: Rename method for clarityThe method
getCollectionsEventsContext()
might be confusing since it returns either "collection" or "table". A more accurate name would better reflect its purpose./** - * Get the correct collections context for Events queue. + * Get the context string for Events queue (either "collection" or "table"). */ - final protected function getCollectionsEventsContext(): string + final protected function getEventContextString(): string { return $this->isCollectionsAPI() ? 'collection' : 'table'; }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Action.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php
(1 hunks)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php
(1 hunks)tests/e2e/Services/Databases/Tables/DatabasesConsoleClientTest.php
(1 hunks)tests/e2e/Services/GraphQL/Base.php
(29 hunks)tests/e2e/Services/GraphQL/Collections/AbuseTest.php
(3 hunks)tests/e2e/Services/GraphQL/Tables/AbuseTest.php
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- tests/e2e/Services/GraphQL/Collections/AbuseTest.php
- tests/e2e/Services/GraphQL/Tables/AbuseTest.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Get.php
- src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php
🧰 Additional context used
🧠 Learnings (1)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Action.php (1)
Learnt from: ItzNotABug
PR: appwrite/appwrite#9693
File: src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php:85-86
Timestamp: 2025-05-10T04:12:13.012Z
Learning: The class `Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Indexes\Action` defines a method `getGrantParentNotFoundException()` which is used to handle cases where a parent resource (like a database collection) is not found.
🧬 Code Graph Analysis (1)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php (14)
src/Appwrite/Platform/Modules/Databases/Workers/Databases.php (2)
Databases
(21-630)action
(54-85)src/Appwrite/Event/Event.php (3)
Event
(10-600)reset
(389-395)setPayload
(206-215)src/Appwrite/Extend/Exception.php (1)
Exception
(7-439)src/Appwrite/SDK/Method.php (1)
Method
(9-295)src/Appwrite/Utopia/Response.php (2)
Response
(151-963)dynamic
(671-704)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php (3)
Create
(27-232)getResponseModel
(36-39)action
(80-231)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Create.php (1)
Create
(19-72)src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Rows/Create.php (1)
Create
(19-78)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Action.php (4)
Action
(8-163)getResponseModel
(18-18)getContext
(47-50)setContext
(25-32)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php (4)
Action
(25-627)getResponseModel
(35-35)getContext
(54-57)setContext
(42-49)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Delete.php (2)
getResponseModel
(33-36)action
(74-125)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Delete.php (2)
getResponseModel
(35-38)action
(80-175)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php (2)
getResponseModel
(39-42)action
(86-306)src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Get.php (2)
getResponseModel
(34-37)action
(72-156)
⏰ Context from checks skipped due to timeout of 90000ms (18)
- GitHub Check: E2E Service Test (Migrations)
- GitHub Check: E2E Service Test (VCS)
- GitHub Check: E2E Service Test (Tokens)
- GitHub Check: E2E Service Test (Locale)
- GitHub Check: E2E Service Test (Webhooks)
- GitHub Check: E2E Service Test (Storage)
- GitHub Check: E2E Service Test (Teams)
- GitHub Check: E2E Service Test (Realtime)
- GitHub Check: E2E Service Test (Health)
- GitHub Check: E2E Service Test (Avatars)
- GitHub Check: E2E Service Test (GraphQL)
- GitHub Check: E2E Service Test (Functions)
- GitHub Check: E2E Service Test (Account)
- GitHub Check: E2E Service Test (Projects)
- GitHub Check: E2E Service Test (Console)
- GitHub Check: E2E Service Test (Databases)
- GitHub Check: E2E Service Test (Dev Keys)
- GitHub Check: E2E General Test
🔇 Additional comments (16)
tests/e2e/Services/Databases/Tables/DatabasesConsoleClientTest.php (4)
105-119
: Test method looks good.The method correctly tests listing tables when the database is disabled and verifies the expected response.
196-235
: Test method for database usage looks good.The method correctly tests both success and failure cases for retrieving database usage statistics. It verifies invalid range parameters return 400 status code and valid parameters return 200 with appropriate response structure.
237-280
: Test method for table usage looks good.The method correctly tests both success and failure cases for retrieving table usage statistics, including non-existent table IDs. It verifies the response structure and data types.
282-335
: Test method for table logs looks good.The method effectively tests retrieving table logs with various query parameters, including limit and offset. It verifies the response structure and ensures proper pagination.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php (1)
54-54
:❌ Incorrect review comment
Audit label is inconsistent with the documents API
audits.event
is set todocument.create
, but based on the context of this PR which introduces both collections/documents and tables/rows terminology, this might require dynamic context handling similar to other parts of the code.
🏁 Script executed:
#!/bin/bash # Search for other audit event labels in the codebase to check for consistency echo "Searching for audit event labels in Collections and Tables contexts..." rg --no-filename "audits\.event.*document\." src/ echo "---------" rg --no-filename "audits\.event.*row\." src/Length of output: 591
Audit label matches controller context – no change needed
I verified that the Collections controllers consistently use
document.*
audit labels (document.create
,document.update
,document.delete
) and the Tables controllers userow.*
labels (row.create
,row.update
,row.delete
). The existing approach already scopes labels by context, so no dynamic handling is required here. Please disregard this comment.Likely an incorrect or invalid review comment.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Action.php (1)
89-94
: Method name correction implementedThe method name
getGrandParentNotFoundException()
has been properly implemented, addressing the previously identified typo where it was incorrectly namedgetGrantParentNotFoundException()
.tests/e2e/Services/GraphQL/Base.php (10)
24-29
: The Tables API constants match the Collections API pattern.The new constants for Tables operations follow the same naming pattern as the existing Collections API constants, ensuring consistency in the codebase. This parallel structure will make it easier for developers to work with both APIs.
58-83
: Column operations mirror attribute operations consistently.The Columns API operation constants maintain the same structure and naming convention as their Attribute counterparts, providing a consistent parallel between the two APIs. Each column type (string, integer, float, boolean, URL, email, IP, enum, datetime, relationship) has corresponding create and update operations.
91-96
: Column Index operations follow established pattern.The Column Index constants follow the same pattern as Attribute Indexes, maintaining consistency throughout the codebase.
104-109
: Row operations mirror document operations appropriately.The Row operations constants follow the same pattern as their Document counterparts, establishing a clear parallel between the two APIs.
387-460
: Column fragments mirror attribute fragments consistently.The new column fragments have the same structure as their attribute counterparts, ensuring a consistent representation of column types in GraphQL responses. This parallel implementation will make it easier for clients to adapt to the new Tables API.
568-612
: Table queries maintain consistent structure with Collection queries.The GraphQL queries for Table operations mirror their Collection counterparts in structure and naming conventions, ensuring a consistent API experience.
789-964
: Column operation queries follow the same pattern as attributes.The GraphQL queries for Column operations maintain the same structure and behavior as their Attribute counterparts, with appropriate renaming from "collection" to "table" and "attribute" to "column".
2704-2704
: Added databaseId field to Collection response matches Tables implementation.The addition of the databaseId field to the Collection queries ensures consistency with the new Tables implementation, which also includes this field.
2936-3178
: Complex query implementation for tables mirrors collections.The complex query for tables follows the same pattern as the collections version, creating a complete testing environment with database, table, columns, and users. This provides comprehensive test coverage for the new Tables API.
310-310
: Split complex query operations for collections and tables.The complex query operation has been appropriately split into two variants: one for collections and one for tables, allowing for specific testing of each API.
What does this PR do?
This PR does the following -
database
controller to a module structureTable
API, similar to Collections with newColumn
&Row
APIsCollection
andTable
events until we fully deprecateCollection
APIsTable
APIs alongsideCollection
APIs for improved coverage to make sure everything is consistent across versions!Test Plan
Unit & E2E Tests!
Related PRs and Issues
N/A.
Checklist