Conversation
📝 WalkthroughWalkthroughAdds conditional select-query support to the database query validators by introducing isSelectQueryAllowed() in Queries\Base (default false) and enabling it in Deployments. Base builds consistent attribute lists including internal system fields. Adds applySelectQueries(Request, Response, string $model) to Appwrite\Platform\Action to prune non-selected response model fields. Deployment list handlers (Functions and Sites XList) now extend the platform Base, accept Request in action(), and call applySelectQueries to apply field projections. Model::removeRule visibility changed from protected to public. E2E tests added for deployment field projections and a negative test ensuring /users rejects select by default. Docblocks updated in Response and Model. Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 PHPStan (2.1.17)Note: Using configuration file /phpstan.neon. If the excluded path can sometimes exist, append (?) parameters: ✨ Finishing Touches
🧪 Generate unit tests
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. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
Security Scan Results for PRDocker Image Scan Results
Source Code Scan Results🎉 No vulnerabilities found! |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
tests/e2e/Services/Sites/SitesCustomServerTest.php (1)
78-85: Fix class name alias usage for date validator to prevent fatal error.You import
Utopia\Database\Validator\Datetime as DatetimeValidator;but instantiatenew DateTimeValidator(). This will fail to autoload. Use the alias consistently.- $dateValidator = new DateTimeValidator(); + $dateValidator = new DatetimeValidator();
🧹 Nitpick comments (3)
src/Appwrite/Utopia/Database/Validator/Queries/Base.php (1)
63-89: Internal attributes inclusion is good; minor naming/duplication nit.Including
$id,$createdAt,$updatedAt,$sequencein both lists is right so they’re orderable/filterable/selectable. Currently,$attributesand$allAttributesend up identical. Consider renaming$allAttributesto$selectableAttributesor deriving one from the other to reduce duplication and make intent clearer.tests/e2e/Services/Functions/FunctionsCustomServerTest.php (1)
724-735: Good coverage for positive projection; consider adding a negative case.The assertions verify that
statusis included and heavy fields likesourceSizeare excluded. As a follow-up, add a negative test with an invalid field inselect()(e.g.,Query::select(['unknown'])) to assert a 400, which will guard the validator contract.$deployments = $this->listDeployments($functionId, [ 'queries' => [ Query::select(['status'])->toString(), ], ]); @@ $this->assertArrayNotHasKey('sourceSize', $deployments['body']['deployments'][1]); + // Negative: invalid select field should fail + $invalid = $this->listDeployments($functionId, [ + 'queries' => [ + Query::select(['__notAField__'])->toString(), + ], + ]); + $this->assertEquals(400, $invalid['headers']['status-code']);tests/e2e/Services/Sites/SitesCustomServerTest.php (1)
1055-1066: Nice projection assertions; mirror the Functions negative case here too.The new block validates inclusion/exclusion as intended. Please also add an invalid select field check (expect 400) to catch regressions at the Sites deployments endpoint.
$deployments = $this->listDeployments($siteId, [ 'queries' => [ Query::select(['status'])->toString(), ], ]); @@ $this->assertArrayNotHasKey('sourceSize', $deployments['body']['deployments'][1]); + // Negative: invalid select field should fail + $invalid = $this->listDeployments($siteId, [ + 'queries' => [ + Query::select(['__notAField__'])->toString(), + ], + ]); + $this->assertEquals(400, $invalid['headers']['status-code']);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
src/Appwrite/Utopia/Database/Validator/Queries/Base.php(4 hunks)src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php(1 hunks)tests/e2e/Services/Functions/FunctionsCustomServerTest.php(1 hunks)tests/e2e/Services/Sites/SitesCustomServerTest.php(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php (1)
src/Appwrite/Utopia/Database/Validator/Queries/Base.php (1)
isSelectQueryAllowed(106-109)
src/Appwrite/Utopia/Database/Validator/Queries/Base.php (2)
src/Appwrite/Utopia/Response/Model/Document.php (2)
Document(8-112)__construct(30-79)src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php (2)
isSelectQueryAllowed(26-29)__construct(21-24)
tests/e2e/Services/Sites/SitesCustomServerTest.php (1)
tests/e2e/Services/Sites/SitesBase.php (1)
listDeployments(217-225)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Benchmark
- GitHub Check: Unit Test
- GitHub Check: Check if utopia-php/database changed
- GitHub Check: scan
🔇 Additional comments (2)
src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php (1)
26-29: Keep explicit opt-in here; will be necessary once Base defaults to disallow select.Adding
isSelectQueryAllowed(): boolinDeploymentsis fine. However, right nowBase::isSelectQueryAllowed()returnstrue, so this override is redundant. I strongly recommend flipping the Base default tofalse(see comment in Base.php) and keeping this override to allow select only for deployments.Once you flip the Base default, please run e2e for other resources to confirm they don’t start accepting
select()unintentionally.src/Appwrite/Utopia/Database/Validator/Queries/Base.php (1)
44-61: Attribute harvesting and shaping looks correct.Filtering collection attributes against the allowlist and wrapping them as
Documentinstances aligns with expectations ofFilter/Order/Selectvalidators.
✨ Benchmark results
⚡ Benchmark Comparison
|
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/Appwrite/Utopia/Database/Validator/Queries/Base.php (1)
106-109: Defaulting isSelectQueryAllowed() to false avoids accidental global surface increase.Thanks for flipping this to false—matches prior feedback and keeps Select strictly opt-in.
🧹 Nitpick comments (3)
tests/e2e/Services/Users/UsersBase.php (1)
448-460: Good negative guard for non-opted-in endpoints; add minimal error-shape assertions.This verifies /users rejects Query::select() as intended while Select is opt-in. To make the failure mode more robust (and future-proof messaging changes), add a couple of light assertions on the response body.
Apply this diff to harden the check:
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'queries' => [ Query::select(['name'])->toString() ] ]); - $this->assertEquals($response['headers']['status-code'], 400); + $this->assertEquals(400, $response['headers']['status-code']); + $this->assertIsArray($response['body']); + $this->assertEquals(400, $response['body']['code'] ?? null);Optionally, consider moving this “select not supported” check into a small shared negative test to reuse across a couple of other endpoints, so we catch accidental global enablement. I can help wire that if useful.
src/Appwrite/Utopia/Database/Validator/Queries/Base.php (2)
44-61: Clarify intent: $allAttributes currently equals $attributes; consider building true “all attributes” for Select.Right now, both $attributes and $allAttributes are populated only from $allowedAttributes (plus internals later), making them identical. If the intent is to let Select project over any collection attribute (while Filter/Order remain limited to $allowedAttributes), populate $allAttributes from the full collection, and $attributes from the allowed subset.
This also matches the earlier note that $attributes are “allowed for filter queries,” while $allAttributes should “get it all.”
Apply this diff to make the intent explicit:
- foreach ($collection['attributes'] as $attribute) { - $key = $attribute['$id']; - - if (!isset($allowedAttributesLookup[$key])) { - continue; - } - - $attributeDocument = new Document([ - 'key' => $key, - 'type' => $attribute['type'], - 'array' => $attribute['array'], - ]); - - $attributes[] = $attributeDocument; - $allAttributes[] = $attributeDocument; - } + foreach ($collection['attributes'] as $attribute) { + $key = $attribute['$id']; + + // Always maintain a full list for Select() + $attributeDocument = new Document([ + 'key' => $key, + 'type' => $attribute['type'], + 'array' => $attribute['array'], + ]); + $allAttributes[] = $attributeDocument; + + // Restrict Filter/Order to allowed attributes only + if (isset($allowedAttributesLookup[$key])) { + $attributes[] = $attributeDocument; + } + }If the current behavior (Select limited to allowed attributes) is intentional for security or DX reasons, feel free to ignore—then it would help to add a short inline comment stating that Select is intentionally constrained to allowed attributes.
99-109: ConfirmSelectOpt-In Only for Deployments
- ✅ Verified that only
DeploymentsoverridesisSelectQueryAllowed(): boolto returntrue(src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php:26–29).- ✅ Base class remains
falseby default (src/Appwrite/Utopia/Database/Validator/Queries/Base.php:106–108). No other overrides found.⚠️ I did not find any existing tests invokingselect()orisSelectQueryAllowed().To prevent regressions, please add unit tests that:
- Assert that
Deploymentsqueries allowselect().- Assert that other query validators (inheriting from
Base) reject or blockselect().
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
src/Appwrite/Utopia/Database/Validator/Queries/Base.php(4 hunks)tests/e2e/Services/Users/UsersBase.php(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Benchmark
- GitHub Check: E2E Service Test (Tokens)
- GitHub Check: E2E Service Test (Console)
- GitHub Check: E2E Service Test (Site Screenshots)
- GitHub Check: E2E Service Test (Dev Keys)
- GitHub Check: E2E General Test
🔇 Additional comments (3)
src/Appwrite/Utopia/Database/Validator/Queries/Base.php (3)
14-14: Import of Select validator is correct and scoped to conditional use.Looks good; no concerns.
63-89: Nice centralization of internal attributes.Moving $id, $createdAt, $updatedAt, and $sequence into a shared $internalAttributes list and appending to both attribute sets improves consistency and avoids drift. Good call.
99-101: Select validator is correctly opt-in and appended conditionally.This aligns with the PR goal: only validators that opt in (e.g., Deployments) gain select support.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (17)
src/Appwrite/SDK/Method.php (1)
106-108: Cache or inject a single Swoole Request/Response in validateResponseModelRepeatedly instantiating
new Request(new HttpRequest())andnew Response(new HttpResponse(), $request)inside validateResponseModel can incur unnecessary overhead and makes testing fragile when the Swoole extension (or stubs) isn’t present. Consider creating or injecting a single pair of Request/Response instances and reusing them.• Location:
src/Appwrite/SDK/Method.php, methodvalidateResponseModel
• Recommended approach:
– Add private properties onMethodto hold a cached Request and Response (initialized once in the constructor or via a factory).
– UpdatevalidateResponseModelto reuse those instances instead of constructing new ones each call.Example refactor:
class Method { + private Request $cachedRequest; + private Response $cachedResponse; public function __construct(…) { // existing validation… + // Initialize a single Request/Response pair for model validation + $this->cachedRequest = new Request(new HttpRequest()); + $this->cachedResponse = new Response(new HttpResponse(), $this->cachedRequest); } protected function validateResponseModel(string|array $responseModel): void { - $request = new Request(new HttpRequest()); - $response = new Response(new HttpResponse(), $request); + $response = $this->cachedResponse; if (!\is_array($responseModel)) { $responseModel = [$responseModel]; } foreach ($responseModel as $model) { try { $response->getModel($model); } catch (\Exception $e) { self::$errors[] = "Error with {$this->getRouteName()} method: Invalid response model, make sure the model has been defined in Response.php"; } } } }This change reduces per-call instantiation and makes it easier to substitute mocks or stubs in tests.
src/Appwrite/Utopia/Response/Model/ResourceToken.php (1)
63-91: Silence PHPMD for intentionally unused $request.The new signature matches the framework, but $request isn’t used. Suppress the warning locally.
Apply:
- public function filter(Document $document, Request $request): Document + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function filter(Document $document, Request $request): Document {src/Appwrite/Utopia/Response/Model/Team.php (1)
59-70: Silence PHPMD for intentionally unused $request.Same pattern as other models; suppress the unused parameter warning.
Apply:
- public function filter(Document $document, Request $request): Document + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function filter(Document $document, Request $request): Document {src/Appwrite/Utopia/Response/Model/Project.php (1)
344-417: Use $request to apply select projections (also clears PHPMD unused-parameter warnings)Call applySelectQueries at the end so projection applies on the final shape. Safe since isSelectQueryAllowed() defaults to false here.
Apply:
- return $document; + // Apply query.select() when allowed for this model + $this->applySelectQueries($document, $request); + return $document;src/Appwrite/Utopia/Response/Model/User.php (1)
151-162: Leverage Request for optional select-based projectionAligns with Deployment model and removes PHPMD UnusedFormalParameter warning.
Apply:
- return $document; + $this->applySelectQueries($document, $request); + return $document;src/Appwrite/Utopia/Response/Model/Migration.php (1)
113-136: Apply select projection using the provided RequestKeeps behavior consistent across models; no effect unless select is allowed.
Apply:
- // errors now only have code and message. - $document->setAttribute('errors', $errors); - - return $document; + // errors now only have code and message. + $document->setAttribute('errors', $errors); + + $this->applySelectQueries($document, $request); + return $document;src/Appwrite/Utopia/Response/Model/ColumnIndex.php (1)
97-106: Consume $request to support future select queries and silence PHPMDCall applySelectQueries before returning.
Apply:
- return $document; + $this->applySelectQueries($document, $request); + return $document;tests/unit/Utopia/ResponseTest.php (1)
5-10: Centralize SwooleRequest/Response creation for more resilient testsTests are currently instantiating real Swoole objects directly (e.g.
new SwooleRequest(),new SwooleResponse()), but no factory or stub helper exists. If the Swoole extension isn’t available in CI or on a contributor’s machine, these tests will fatal. To keep things robust, add a small helper—e.g.Tests\Support\SwooleFactory::emptyRequest()and::emptyResponse()—and use that everywhere.• tests/unit/Utopia/RequestTest.php
Replace$this->request = new Request(new SwooleRequest());with
$this->request = new Request(Tests\Support\SwooleFactory::emptyRequest());• tests/unit/Utopia/ResponseTest.php
Replace$request = new Request(new SwooleRequest()); $response = new Response(new SwooleResponse(), $request);with
$request = new Request(Tests\Support\SwooleFactory::emptyRequest()); $response = new Response(Tests\Support\SwooleFactory::emptyResponse(), $request);• tests/unit/GraphQL/BuilderTest.php
Likewise swap bothnew SwooleRequest()andnew SwooleResponse()for factory calls.You can implement the factory stub under
tests/Support/SwooleFactory.php:<?php namespace Tests\Support; use Swoole\Http\Request as SwooleRequest; use Swoole\Http\Response as SwooleResponse; class SwooleFactory { public static function emptyRequest(): SwooleRequest { return new SwooleRequest(); // or a minimal stub if Swoole isn’t installed } public static function emptyResponse(): SwooleResponse { return new SwooleResponse(); } }This keeps your tests decoupled from the real extension and easy to stub or polyfill later.
src/Appwrite/Utopia/Response/Model/AttributeRelationship.php (1)
84-96: Silence PHPMD for unused $request paramMethod must match the base signature; parameter is intentionally unused. Add a suppression to keep CI green.
/** * Process Document before returning it to the client * * @return Document */ - public function filter(Document $document, Request $request): Document + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function filter(Document $document, Request $request): Document {src/Appwrite/Utopia/Response/Model/Table.php (1)
115-139: Silence PHPMD for unused $request param; terminology looks consistentParameter is required by the interface but unused here. Add suppression. Also, good job keeping “table/row” terminology consistent with prior guidance.
/** * Process Document before returning it to the client for backwards compatibility! */ - public function filter(Document $document, Request $request): Document + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function filter(Document $document, Request $request): Document {src/Appwrite/Utopia/Response/Model/Execution.php (1)
160-166: Silence PHPMD for unused $request paramExecution::filter matches the new signature but doesn’t use the Request. Suppress PHPMD to avoid noise.
- public function filter(Document $document, Request $request): Document + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function filter(Document $document, Request $request): Document {src/Appwrite/Utopia/Response/Model/Variable.php (2)
27-32: Fix description typo for $updatedAt.Change "creation" to "update" to match the field’s meaning.
- ->addRule('$updatedAt', [ - 'type' => self::TYPE_DATETIME, - 'description' => 'Variable creation date in ISO 8601 format.', + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Variable update date in ISO 8601 format.',
67-74: Docblock and PHPMD alignment for new Request param.Update the docblock to include the Request parameter and suppress the UnusedFormalParameter warning (the param is intentionally unused here).
/** * Filter * - * @param Document $document + * @param Document $document + * @param Request $request * @return Document */ - public function filter(Document $document, Request $request): Document + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function filter(Document $document, Request $request): Documentsrc/Appwrite/Utopia/Response/Model/ColumnRelationship.php (1)
79-86: Docblock and PHPMD alignment for new Request param.Add the Request param to the docblock and suppress UnusedFormalParameter to satisfy PHPMD.
/** * Process Document before returning it to the client * * @return Document */ - public function filter(Document $document, Request $request): Document + /** + * @param Document $document + * @param Request $request + * @return Document + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function filter(Document $document, Request $request): Documentsrc/Appwrite/Utopia/Response/Model/Row.php (1)
79-97: Cast $sequence to int for parity with Document::filter.Document::filter normalizes $sequence to int; Row::filter should mirror this to avoid type inconsistencies.
public function filter(DatabaseDocument $document, Request $request): DatabaseDocument { $document->removeAttribute('$collection'); $document->removeAttribute('$tenant'); + $document->setAttribute('$sequence', (int)$document->getAttribute('$sequence', 0)); foreach ($document->getAttributes() as $column) {src/Appwrite/Utopia/Response/Model.php (2)
204-232: Tighten up to satisfy PHPMD and small robustness tweaks.
- $document param in applySelectQueries is unused; $rule is unused; also guard when queries is a string.
Apply:
- public function applySelectQueries(Document $document, Request $request): void + /** + * @SuppressWarnings("UnusedFormalParameter") + */ + public function applySelectQueries(Document $_document, Request $request): void { - $queries = $request->getParam('queries', []); + $queries = $request->getParam('queries', []); + if (!\is_array($queries)) { + $queries = [$queries]; + } $queries = Query::parseQueries($queries); $selectQueries = Query::groupByType($queries)['selections'] ?? []; @@ - foreach ($this->getRules() as $ruleName => $rule) { + foreach (\array_keys($this->getRules()) as $ruleName) { if (\str_starts_with($ruleName, '$')) { continue; } if (!\in_array($ruleName, $attributes)) { $this->removeRule($ruleName); } } }
54-57: Suppress PHPMD for unused $request in base filter().Base implementation is intentionally a no-op; silence the warning.
Apply:
- public function filter(Document $document, Request $request): Document + /** + * @SuppressWarnings("UnusedFormalParameter") + */ + public function filter(Document $document, Request $request): Document { return $document; }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (25)
app/http.php(1 hunks)app/realtime.php(2 hunks)src/Appwrite/Platform/Workers/Functions.php(2 hunks)src/Appwrite/SDK/Method.php(2 hunks)src/Appwrite/Utopia/Database/Validator/Queries/Base.php(3 hunks)src/Appwrite/Utopia/Response.php(2 hunks)src/Appwrite/Utopia/Response/Model.php(3 hunks)src/Appwrite/Utopia/Response/Model/AttributeRelationship.php(2 hunks)src/Appwrite/Utopia/Response/Model/ColumnIndex.php(2 hunks)src/Appwrite/Utopia/Response/Model/ColumnRelationship.php(2 hunks)src/Appwrite/Utopia/Response/Model/Deployment.php(2 hunks)src/Appwrite/Utopia/Response/Model/Document.php(3 hunks)src/Appwrite/Utopia/Response/Model/Execution.php(2 hunks)src/Appwrite/Utopia/Response/Model/Migration.php(2 hunks)src/Appwrite/Utopia/Response/Model/Project.php(2 hunks)src/Appwrite/Utopia/Response/Model/ResourceToken.php(2 hunks)src/Appwrite/Utopia/Response/Model/Row.php(3 hunks)src/Appwrite/Utopia/Response/Model/Table.php(2 hunks)src/Appwrite/Utopia/Response/Model/Team.php(2 hunks)src/Appwrite/Utopia/Response/Model/User.php(2 hunks)src/Appwrite/Utopia/Response/Model/Variable.php(2 hunks)tests/e2e/Services/Functions/FunctionsCustomServerTest.php(1 hunks)tests/e2e/Services/Sites/SitesCustomServerTest.php(1 hunks)tests/unit/GraphQL/BuilderTest.php(2 hunks)tests/unit/Utopia/ResponseTest.php(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- src/Appwrite/Utopia/Database/Validator/Queries/Base.php
- tests/e2e/Services/Sites/SitesCustomServerTest.php
- tests/e2e/Services/Functions/FunctionsCustomServerTest.php
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-06-19T09:20:03.312Z
Learnt from: ItzNotABug
PR: appwrite/appwrite#9693
File: src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Update.php:57-59
Timestamp: 2025-06-19T09:20:03.312Z
Learning: In table-related endpoints (such as `src/Appwrite/Platform/Modules/Databases/Http/Databases/Tables/Update.php`), parameter descriptions should use "table" and "row" terminology instead of "collection" and "document" for clarity and consistency.
Applied to files:
src/Appwrite/Utopia/Response/Model/Table.phpsrc/Appwrite/Utopia/Response/Model/Row.php
📚 Learning: 2025-05-12T06:07:51.470Z
Learnt from: abnegate
PR: appwrite/appwrite#9743
File: src/Appwrite/Utopia/Request.php:0-0
Timestamp: 2025-05-12T06:07:51.470Z
Learning: In Appwrite's request handling architecture, the Request::getParams() method selects which SDK method to use based on parameter matching, but does not validate required parameters. The action execution flow handles parameter validation separately. This separation of concerns allows for more flexible handling of multi-method routes.
Applied to files:
src/Appwrite/SDK/Method.php
🧬 Code graph analysis (22)
src/Appwrite/Utopia/Response/Model/Team.php (5)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)src/Appwrite/Utopia/Response/Model/Deployment.php (1)
filter(195-199)src/Appwrite/Utopia/Response/Model/Document.php (2)
filter(82-101)Document(9-113)src/Appwrite/Utopia/Response/Model/User.php (1)
filter(151-162)
src/Appwrite/Utopia/Response/Model/AttributeRelationship.php (3)
src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)src/Appwrite/Utopia/Response/Model/ColumnIndex.php (1)
filter(97-106)src/Appwrite/Utopia/Response/Model/ColumnRelationship.php (1)
filter(84-96)
src/Appwrite/Utopia/Response/Model/ResourceToken.php (2)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)
app/http.php (1)
src/Appwrite/Utopia/Response.php (1)
Response(151-964)
src/Appwrite/Utopia/Response/Model/Migration.php (2)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)
src/Appwrite/Utopia/Response/Model/Deployment.php (2)
src/Appwrite/Utopia/Response.php (1)
Response(151-964)src/Appwrite/Utopia/Response/Model.php (3)
Model(9-233)filter(54-57)applySelectQueries(204-232)
src/Appwrite/Utopia/Response/Model/Project.php (2)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)
src/Appwrite/Utopia/Response/Model/Execution.php (5)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)src/Appwrite/Utopia/Response/Model/AttributeRelationship.php (1)
filter(84-96)src/Appwrite/Utopia/Response/Model/Deployment.php (1)
filter(195-199)src/Appwrite/Utopia/Response/Model/Document.php (2)
filter(82-101)Document(9-113)
src/Appwrite/Utopia/Response/Model/User.php (13)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)src/Appwrite/Utopia/Response/Model/AttributeRelationship.php (1)
filter(84-96)src/Appwrite/Utopia/Response/Model/ColumnIndex.php (1)
filter(97-106)src/Appwrite/Utopia/Response/Model/Deployment.php (1)
filter(195-199)src/Appwrite/Utopia/Response/Model/Document.php (2)
filter(82-101)Document(9-113)src/Appwrite/Utopia/Response/Model/Execution.php (1)
filter(160-166)src/Appwrite/Utopia/Response/Model/Migration.php (1)
filter(113-136)src/Appwrite/Utopia/Response/Model/ResourceToken.php (1)
filter(63-91)src/Appwrite/Utopia/Response/Model/Row.php (1)
filter(79-97)src/Appwrite/Utopia/Response/Model/Table.php (1)
filter(115-139)src/Appwrite/Utopia/Response/Model/Team.php (1)
filter(59-70)src/Appwrite/Utopia/Response/Model/Variable.php (1)
filter(73-80)
src/Appwrite/Platform/Workers/Functions.php (3)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (2)
Model(9-233)filter(54-57)src/Appwrite/Utopia/Response/Model/Execution.php (2)
Execution(12-167)filter(160-166)
src/Appwrite/Utopia/Response/Model/Table.php (6)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)src/Appwrite/Utopia/Response/Model/ColumnIndex.php (1)
filter(97-106)src/Appwrite/Utopia/Response/Model/Deployment.php (1)
filter(195-199)src/Appwrite/Utopia/Response/Model/Document.php (2)
filter(82-101)Document(9-113)src/Appwrite/Utopia/Response/Model/Row.php (1)
filter(79-97)
src/Appwrite/Utopia/Response/Model/ColumnIndex.php (7)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)src/Appwrite/Utopia/Response/Model/AttributeRelationship.php (1)
filter(84-96)src/Appwrite/Utopia/Response/Model/ColumnRelationship.php (1)
filter(84-96)src/Appwrite/Utopia/Response/Model/Deployment.php (1)
filter(195-199)src/Appwrite/Utopia/Response/Model/Document.php (2)
filter(82-101)Document(9-113)src/Appwrite/Utopia/Response/Model/Table.php (1)
filter(115-139)
src/Appwrite/Utopia/Response/Model.php (2)
src/Appwrite/Utopia/Response/Model/Document.php (2)
Document(9-113)filter(82-101)src/Appwrite/Utopia/Response/Model/Deployment.php (1)
filter(195-199)
src/Appwrite/Utopia/Response/Model/ColumnRelationship.php (5)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)src/Appwrite/Utopia/Response/Model/AttributeRelationship.php (1)
filter(84-96)src/Appwrite/Utopia/Response/Model/ColumnIndex.php (1)
filter(97-106)src/Appwrite/Utopia/Response/Model/Table.php (1)
filter(115-139)
src/Appwrite/Utopia/Response/Model/Variable.php (2)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)
tests/unit/GraphQL/BuilderTest.php (2)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response.php (1)
Response(151-964)
src/Appwrite/SDK/Method.php (2)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response.php (1)
Response(151-964)
tests/unit/Utopia/ResponseTest.php (2)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response.php (1)
Response(151-964)
app/realtime.php (2)
src/Appwrite/Utopia/Response.php (1)
Response(151-964)src/Appwrite/Utopia/Request.php (1)
Request(13-236)
src/Appwrite/Utopia/Response.php (2)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)
src/Appwrite/Utopia/Response/Model/Document.php (3)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)src/Appwrite/Utopia/Response/Model/Row.php (1)
filter(79-97)
src/Appwrite/Utopia/Response/Model/Row.php (3)
src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Utopia/Response/Model.php (1)
filter(54-57)src/Appwrite/Utopia/Response/Model/Document.php (1)
filter(82-101)
🪛 PHPMD (2.15.0)
src/Appwrite/Utopia/Response/Model/Team.php
59-59: Avoid unused parameters such as '$request'. (Unused Code Rules)
(UnusedFormalParameter)
src/Appwrite/Utopia/Response/Model/AttributeRelationship.php
84-84: Avoid unused parameters such as '$request'. (Unused Code Rules)
(UnusedFormalParameter)
src/Appwrite/Utopia/Response/Model/ResourceToken.php
63-63: Avoid unused parameters such as '$request'. (Unused Code Rules)
(UnusedFormalParameter)
src/Appwrite/Utopia/Response/Model/Migration.php
113-113: Avoid unused parameters such as '$request'. (Unused Code Rules)
(UnusedFormalParameter)
src/Appwrite/Utopia/Response/Model/Project.php
344-344: Avoid unused parameters such as '$request'. (Unused Code Rules)
(UnusedFormalParameter)
src/Appwrite/Utopia/Response/Model/Execution.php
160-160: Avoid unused parameters such as '$request'. (Unused Code Rules)
(UnusedFormalParameter)
src/Appwrite/Utopia/Response/Model/User.php
151-151: Avoid unused parameters such as '$request'. (Unused Code Rules)
(UnusedFormalParameter)
src/Appwrite/Utopia/Response/Model/Table.php
115-115: Avoid unused parameters such as '$request'. (Unused Code Rules)
(UnusedFormalParameter)
src/Appwrite/Utopia/Response/Model/ColumnIndex.php
97-97: Avoid unused parameters such as '$request'. (Unused Code Rules)
(UnusedFormalParameter)
src/Appwrite/Utopia/Response/Model.php
54-54: Avoid unused parameters such as '$request'. (Unused Code Rules)
(UnusedFormalParameter)
204-204: Avoid unused parameters such as '$document'. (Unused Code Rules)
(UnusedFormalParameter)
223-223: Avoid unused local variables such as '$rule'. (Unused Code Rules)
(UnusedLocalVariable)
src/Appwrite/Utopia/Response/Model/ColumnRelationship.php
84-84: Avoid unused parameters such as '$request'. (Unused Code Rules)
(UnusedFormalParameter)
src/Appwrite/Utopia/Response/Model/Variable.php
73-73: Avoid unused parameters such as '$request'. (Unused Code Rules)
(UnusedFormalParameter)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: scan
🔇 Additional comments (16)
src/Appwrite/SDK/Method.php (1)
6-9: Imports look correct.src/Appwrite/Utopia/Response/Model/Deployment.php (1)
195-199: Good: request-aware field projection for deployments.applySelectQueries here aligns with allowing query.select on deployments and will drop heavy fields like buildLogs unless requested.
tests/unit/GraphQL/BuilderTest.php (1)
18-20: Test bootstrap updated correctly for Response(Request) signature.Initialization mirrors runtime behavior; Mapper::init remains unaffected.
app/http.php (1)
429-429: All Response::__construct call sites updated
Verified via search that every instance ofnew Response(...)now includes the requiredRequestargument—in tests (ResponseTest, BuilderTest), SDK (src/Appwrite/SDK/Method.php), real-time handlers (app/realtime.php), and HTTP entrypoint (app/http.php). No remaining instantiations need updating.src/Appwrite/Utopia/Response/Model/Project.php (1)
6-6: Import added is appropriateNeeded for the new filter signature.
src/Appwrite/Utopia/Response/Model/User.php (1)
5-5: Import added is appropriatesrc/Appwrite/Utopia/Response/Model/Migration.php (1)
5-5: Import added is appropriatesrc/Appwrite/Utopia/Response/Model/ColumnIndex.php (1)
5-5: Import added is appropriatetests/unit/Utopia/ResponseTest.php (1)
21-22: LGTM: Response now receives RequestPassing Request into Response matches the new constructor and output path. Looks correct.
src/Appwrite/Platform/Workers/Functions.php (1)
11-15: Guard and Cache SwooleRequest Instantiation in Functions WorkerIn our CLI environment,
class_exists('Swoole\Http\Request')returnsfalse, so callingnew SwooleRequest()will fatally error unless the Swoole extension or a polyfill is provided. To ensure safety across builds and avoid per-call allocations, you should:
- Verify that your worker runtime actually loads the Swoole extension (or ships a compatible polyfill).
- If not, supply a minimal stub request object or factory that implements the same interface expected by
Appwrite\Utopia\Request.- Cache a single “empty” request wrapper to reuse on each filter invocation.
Apply this optional refactor in src/Appwrite/Platform/Workers/Functions.php around line 615:
class Functions extends Action { + /** @var Request|null Reused empty Request for model filtering */ + private static ?Request $emptyRequest = null; + + private static function emptyRequest(): Request + { + if (self::$emptyRequest === null) { + // Guard against missing Swoole extension; fallback to a stub or polyfill + if (class_exists(\Swoole\Http\Request::class)) { + $swooleRequest = new SwooleRequest(); + } else { + // TODO: replace with your own stub implementation + $swooleRequest = new class { + // provide only the minimal interface Utopia\Request expects + }; + } + self::$emptyRequest = new Request($swooleRequest); + } + return self::$emptyRequest; + } @@ - $realtimeExecution = $executionModel - ->filter(new Document($execution->getArrayCopy()), new Request(new SwooleRequest())); + $realtimeExecution = $executionModel + ->filter(new Document($execution->getArrayCopy()), self::emptyRequest());• Location to update:
–src/Appwrite/Platform/Workers/Functions.phpat line 615Please confirm in your worker containers that the Swoole extension (or an appropriate polyfill) is present and, if it isn’t, implement a stub factory before reusing the cached
Request.src/Appwrite/Utopia/Response/Model/Document.php (1)
82-100: Good propagation of Request through recursive filtering.Passing $request into nested filters keeps the interface consistent with Model::filter and future-proofs select/projection logic.
src/Appwrite/Utopia/Response.php (2)
723-724: Correct: model filters now receive Request.This aligns Response::output with the updated Model::filter signature.
405-409: All PHP Response instantiations include the new Request parameter
I’ve reviewed everynew Response(in the PHP codebase (excluding vendor), and all call sites now pass both the native response and aRequestinstance. The only single-argumentnew Response(…)occurrences are in Astro JS pages (using the global JS Response), not the PHP class under review. No further changes are required.src/Appwrite/Utopia/Response/Model/ColumnRelationship.php (1)
15-52: Nice terminology consistency.Using “table” in public-facing descriptions matches current guidelines.
app/realtime.php (1)
507-507: Good: Response now carries the Request context in onOpen.This aligns with the updated Response signature and enables request-aware filtering.
src/Appwrite/Utopia/Response/Model.php (1)
49-57: filter signature update validatedAll
Model::filter()subclasses have been updated to the new two-argument signature (Document, Request), and no remaining single-argument implementations were found. The breaking change has been fully propagated.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (2)
724-735: Harden select(['status']) assertions and reduce flakinessAdd minimal guards and verify system fields are retained while non-selected heavy fields are excluded.
$deployments = $this->listDeployments($functionId, [ 'queries' => [ Query::select(['status'])->toString(), ], ]); $this->assertEquals($deployments['headers']['status-code'], 200); + $this->assertIsArray($deployments['body']['deployments']); + $this->assertGreaterThanOrEqual(2, \count($deployments['body']['deployments'])); $this->assertArrayHasKey('status', $deployments['body']['deployments'][0]); $this->assertArrayHasKey('status', $deployments['body']['deployments'][1]); $this->assertArrayNotHasKey('sourceSize', $deployments['body']['deployments'][0]); $this->assertArrayNotHasKey('sourceSize', $deployments['body']['deployments'][1]); + // Internal/system attributes should remain available with select() + $this->assertArrayHasKey('$id', $deployments['body']['deployments'][0]); + // Non-selected heavy fields should be omitted + $this->assertArrayNotHasKey('buildSize', $deployments['body']['deployments'][0]); + $this->assertArrayNotHasKey('buildLogs', $deployments['body']['deployments'][0]);
736-747: Broaden coverage: type checks, multi-field select, and invalid-field error pathValidate payload shape, ensure multi-attribute projections work, and assert validator behavior for unknown fields.
// Extra select query check, for attribute not allowed by filter queries $deployments = $this->listDeployments($functionId, [ 'queries' => [ Query::select(['buildLogs'])->toString(), ], ]); $this->assertEquals($deployments['headers']['status-code'], 200); + $this->assertIsArray($deployments['body']['deployments']); + $this->assertGreaterThanOrEqual(2, \count($deployments['body']['deployments'])); $this->assertArrayHasKey('buildLogs', $deployments['body']['deployments'][0]); $this->assertArrayHasKey('buildLogs', $deployments['body']['deployments'][1]); + $this->assertIsString($deployments['body']['deployments'][0]['buildLogs']); $this->assertArrayNotHasKey('sourceSize', $deployments['body']['deployments'][0]); $this->assertArrayNotHasKey('sourceSize', $deployments['body']['deployments'][1]); + + // Multi-field projection + $deployments = $this->listDeployments($functionId, [ + 'queries' => [ + Query::select(['status', 'buildLogs'])->toString(), + ], + ]); + $this->assertEquals(200, $deployments['headers']['status-code']); + $this->assertArrayHasKey('status', $deployments['body']['deployments'][0]); + $this->assertArrayHasKey('buildLogs', $deployments['body']['deployments'][0]); + $this->assertArrayNotHasKey('sourceSize', $deployments['body']['deployments'][0]); + + // Invalid attribute should be rejected by validator + $invalid = $this->listDeployments($functionId, [ + 'queries' => [ + Query::select(['__nonExisting__'])->toString(), + ], + ]); + $this->assertEquals(400, $invalid['headers']['status-code']);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
src/Appwrite/Platform/Workers/Functions.php(2 hunks)src/Appwrite/SDK/Method.php(2 hunks)src/Appwrite/Utopia/Response/Model/Row.php(3 hunks)tests/e2e/Services/Functions/FunctionsCustomServerTest.php(1 hunks)tests/e2e/Services/Sites/SitesCustomServerTest.php(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- src/Appwrite/SDK/Method.php
- src/Appwrite/Platform/Workers/Functions.php
- src/Appwrite/Utopia/Response/Model/Row.php
- tests/e2e/Services/Sites/SitesCustomServerTest.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: scan
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/Appwrite/Utopia/Response/Model/Deployment.php (1)
5-7: Optional: duplicate rules for providerBranch elsewhere in this model.There are two addRule('providerBranch', ...) blocks in this class (Lines 134–139 and 170–175). While unchanged in this PR, duplicates can cause confusion or unintended overrides.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
src/Appwrite/Platform/Modules/Compute/Base.php(2 hunks)src/Appwrite/Utopia/Response.php(1 hunks)src/Appwrite/Utopia/Response/Model.php(1 hunks)src/Appwrite/Utopia/Response/Model/Deployment.php(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/Appwrite/Utopia/Response/Model.php
🚧 Files skipped from review as they are similar to previous changes (1)
- src/Appwrite/Utopia/Response.php
🧰 Additional context used
🪛 PHPMD (2.15.0)
src/Appwrite/Platform/Modules/Compute/Base.php
34-34: Avoid unused parameters such as '$document'. (Unused Code Rules)
(UnusedFormalParameter)
54-54: Avoid unused local variables such as '$rule'. (Unused Code Rules)
(UnusedLocalVariable)
src/Appwrite/Utopia/Response/Model/Deployment.php
196-196: Avoid unused local variables such as '$request'. (Unused Code Rules)
(UnusedLocalVariable)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
- GitHub Check: E2E Service Test (Health)
- GitHub Check: E2E Service Test (VCS)
- GitHub Check: E2E Service Test (Webhooks)
- GitHub Check: E2E Service Test (Tokens)
- GitHub Check: E2E Service Test (GraphQL)
- GitHub Check: E2E Service Test (Proxy)
- GitHub Check: E2E Service Test (Sites)
- GitHub Check: E2E Service Test (Console)
- GitHub Check: E2E Service Test (FunctionsSchedule)
- GitHub Check: E2E Service Test (Functions)
- GitHub Check: E2E Service Test (Avatars)
- GitHub Check: E2E Service Test (Databases/TablesDB)
- GitHub Check: E2E Service Test (Dev Keys)
- GitHub Check: E2E Service Test (Site Screenshots)
- GitHub Check: E2E General Test
- GitHub Check: Unit Test
- GitHub Check: Benchmark
- GitHub Check: scan
🔇 Additional comments (1)
src/Appwrite/Platform/Modules/Compute/Base.php (1)
24-63: Align applySelectQueries signature and placement
- Signature in Compute/Base.php expects
(Request $request, Response $response, Document $document)but Deployment::filter (src/Appwrite/Utopia/Response/Model/Deployment.php line 196) callsapplySelectQueries($document, $request). Drop the unused$documentparameter, update the method to(Request $request, Response $response), and fix all call-sites to pass the correct arguments.- Relocate this helper into the Response layer (Model or Response) to respect module boundaries.
- Manually confirm that
Query::groupByType(...)[‘selections’]is the correct grouping key.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
src/Appwrite/Platform/Modules/Compute/Base.php (2)
24-35: Fix docblock to match signature and intentThe docblock mentions Document but the method accepts Response and model key. Update annotations and tighten the summary.
- /** - * Helper to apply select queries - * - * Method to respect request select queries in response format, - * to prevent default rule values from being applied on not-selected attributes - * - * @param Request $request - * @param Document $document - * @return void - */ + /** + * Helper to apply select queries. + * + * Respects select([...]) in the request and prunes non-selected attributes + * from the given response model to avoid defaulting removed fields. + * + * @param Request $request + * @param Response $response + * @param string $model Response::<MODEL_*> + * @return void + */
53-62: Remove unused $rule and prefer strict lookupPHPMD flags $rule as unused. Iterate over keys only and use strict in_array to avoid surprises.
- foreach ($responseModel->getRules() as $ruleName => $rule) { + foreach (\array_keys($responseModel->getRules()) as $ruleName) { if (\str_starts_with($ruleName, '$')) { continue; } - if (!\in_array($ruleName, $attributes)) { + if (!\in_array($ruleName, $attributes, true)) { $responseModel->removeRule($ruleName); } }src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (1)
58-58: Surface select support in the SDK param descriptionClarify that projections are supported to set correct expectations for clients.
- ->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Deployments::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Deployments::ALLOWED_ATTRIBUTES) . '. Field projection via Query::select([...]) is supported for deployments.', true)src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php (1)
58-58: Document select support in Sites endpoint as wellAligns docs with behavior.
- ->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Deployments::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Deployments::ALLOWED_ATTRIBUTES) . '. Field projection via Query::select([...]) is supported for deployments.', true)
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
src/Appwrite/Platform/Modules/Compute/Base.php(2 hunks)src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php(5 hunks)src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php(4 hunks)src/Appwrite/Utopia/Response/Model.php(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php (4)
src/Appwrite/Platform/Modules/Compute/Base.php (2)
Base(22-348)applySelectQueries(34-63)src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php (1)
Deployments(5-30)src/Appwrite/Utopia/Request.php (1)
Request(13-236)src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (2)
XList(24-134)action(66-133)
src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (4)
src/Appwrite/Platform/Modules/Compute/Base.php (2)
Base(22-348)applySelectQueries(34-63)src/Appwrite/Utopia/Response.php (1)
Response(151-963)src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php (1)
Deployments(5-30)src/Appwrite/Utopia/Request.php (1)
Request(13-236)
src/Appwrite/Platform/Modules/Compute/Base.php (2)
src/Appwrite/Utopia/Response.php (2)
Response(151-963)getModel(633-640)src/Appwrite/Utopia/Response/Model.php (2)
getRules(75-78)removeRule(109-116)
🪛 PHPMD (2.15.0)
src/Appwrite/Platform/Modules/Compute/Base.php
54-54: Avoid unused local variables such as '$rule'. (Unused Code Rules)
(UnusedLocalVariable)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: E2E Service Test (Functions)
- GitHub Check: E2E Service Test (Realtime)
- GitHub Check: E2E Service Test (Messaging)
- GitHub Check: E2E Service Test (Databases/TablesDB)
- GitHub Check: E2E Service Test (Users)
- GitHub Check: E2E Service Test (Webhooks)
- GitHub Check: E2E Service Test (Databases/Legacy)
- GitHub Check: E2E Service Test (FunctionsSchedule)
- GitHub Check: E2E Service Test (Sites)
- GitHub Check: Benchmark
🔇 Additional comments (10)
src/Appwrite/Utopia/Response/Model.php (2)
45-52: Docblock clarity improvement looks goodAdding the parameter description to filter() improves self-documentation.
109-116: Public removeRule(): confirm model lifecycle to avoid leakage across requestsMaking removeRule() public enables the Base::applySelectQueries() flow. Please confirm Response models are request-scoped (not shared across requests/workers) so rule mutations can’t bleed into other requests.
src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (4)
24-24: Extending Base to reuse applySelectQueries is the right callKeeps projection logic centralized and consistent.
60-63: Request injection LGTMInjecting request enables per-call select handling without changing existing param schema.
66-73: Signature change LGTMAdding Request before Response matches the new injections and preserves DI order.
128-133: Applying select before responding is correctPruning the deployment model prior to Response::dynamic ensures projected fields only.
src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php (4)
24-24: Good reuse of Base for projectionMirrors Functions endpoint for consistency.
60-63: Request injection LGTMEnables select-aware responses without altering public API shape.
66-73: Signature update LGTMOrdering matches injected dependencies.
128-133: Projection applied at the right pointModel pruning occurs after data retrieval and before rendering — correct placement.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/Appwrite/Platform/Action.php (3)
165-171: Fix docblock typos and param annotations.Spelling: “presnet” → “present”. Also, the second param is Response (not Document) and $model is missing from the annotations.
Apply this diff:
- /** - * Helper to apply (request) select queries to response model. - * - * This prevents default values of rules to be presnet for not-selected attributes - * - * @param Request $request - * @param Document $document - * @return void - */ + /** + * Helper to apply select() queries to a response model. + * + * Prevents default values from being present for non-selected attributes. + * + * @param Request $request + * @param Response $response + * @param string $model Response::MODEL_* key + * @return void + */
185-201: Use a set for lookups and address PHPMD’s unused variable.Build a hash-set for selected attributes to get O(1) membership and remove the unused
$ruleflagged by PHPMD at Line 193.- $attributes = []; - foreach ($selectQueries as $query) { - foreach ($query->getValues() as $attribute) { - $attributes[] = $attribute; - } - } + $selected = []; + foreach ($selectQueries as $query) { + foreach ($query->getValues() as $attribute) { + $selected[$attribute] = true; + } + } - $responseModel = $response->getModel($model); - foreach ($responseModel->getRules() as $ruleName => $rule) { + $responseModel = $response->getModel($model); + foreach (\array_keys($responseModel->getRules()) as $ruleName) { if (\str_starts_with($ruleName, '$')) { continue; } - - if (!\in_array($ruleName, $attributes)) { + if (!isset($selected[$ruleName])) { $responseModel->removeRule($ruleName); } }
194-196: Confirm intent: always include internal “$” fields even when not selected.You skip pruning for keys starting with “$”. If the product expectation is “only selected” user-visible fields plus system internals, this is fine. If strict projection is desired, remove the guard or make it configurable.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
src/Appwrite/Platform/Action.php(2 hunks)src/Appwrite/Platform/Modules/Compute/Base.php(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/Appwrite/Platform/Modules/Compute/Base.php
🧰 Additional context used
🧬 Code graph analysis (1)
src/Appwrite/Platform/Action.php (2)
src/Appwrite/Utopia/Response.php (1)
Response(151-963)src/Appwrite/Utopia/Response/Model.php (2)
getRules(75-78)removeRule(109-116)
🪛 PHPMD (2.15.0)
src/Appwrite/Platform/Action.php
193-193: Avoid unused local variables such as '$rule'. (Unused Code Rules)
(UnusedLocalVariable)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: scan
🔇 Additional comments (2)
src/Appwrite/Platform/Action.php (2)
5-6: Imports look correct.Request/Response are now used by the new helper; no issues.
192-201: Model mutation persists for the rest of the request.
removeRule()mutates the Response model in-place. Ensure this Response instance isn’t reused later in the same request for a non-select path, or consider restoring rules after output if reuse is possible.
What does this PR do?
adds support for query:.seelct() to deployments, making it more optimal on Console where list doesnt need logs (logs can get large, 1MB, for some SSR builds)
Test Plan
new tests
Quick QA with COnsole
(previously this was 4xx query error, select not supported)
Related PRs and Issues
x
Checklist