Skip to content

Feat: Deployment select queries#10380

Merged
Meldiron merged 11 commits into1.8.xfrom
feat-select-queries-on-deployments
Sep 2, 2025
Merged

Feat: Deployment select queries#10380
Meldiron merged 11 commits into1.8.xfrom
feat-select-queries-on-deployments

Conversation

@Meldiron
Copy link
Copy Markdown
Contributor

@Meldiron Meldiron commented Aug 26, 2025

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

CleanShot 2025-08-26 at 15 33 25@2x CleanShot 2025-08-26 at 15 33 21@2x

(previously this was 4xx query error, select not supported)

Related PRs and Issues

x

Checklist

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Aug 26, 2025

📝 Walkthrough

Walkthrough

Adds 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

  • Feat: Lazy-load relationships #9669 — Implements select-driven field projection and related select-query handling, closely connected to the validator and response-filtering changes in this PR.

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.
Invalid entry in excludePaths:
Path "/app/sdks" is neither a directory, nor a file path, nor a fnmatch pattern.

If the excluded path can sometimes exist, append (?)
to its config entry to mark it as optional. Example:

parameters:
excludePaths:
analyseAndScan:
- app/sdks (?)

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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

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

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Aug 26, 2025

Security Scan Results for PR

Docker Image Scan Results

Package Version Vulnerability Severity
golang.org/x/crypto v0.31.0 CVE-2025-22869 HIGH
golang.org/x/oauth2 v0.24.0 CVE-2025-22868 HIGH
stdlib 1.22.10 CVE-2025-47907 HIGH

Source Code Scan Results

🎉 No vulnerabilities found!

@Meldiron Meldiron marked this pull request as ready for review August 26, 2025 13:29
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
tests/e2e/Services/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 instantiate new 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, $sequence in both lists is right so they’re orderable/filterable/selectable. Currently, $attributes and $allAttributes end up identical. Consider renaming $allAttributes to $selectableAttributes or 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 status is included and heavy fields like sourceSize are excluded. As a follow-up, add a negative test with an invalid field in select() (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.

📥 Commits

Reviewing files that changed from the base of the PR and between 34658aa and a413235.

📒 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(): bool in Deployments is fine. However, right now Base::isSelectQueryAllowed() returns true, so this override is redundant. I strongly recommend flipping the Base default to false (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 Document instances aligns with expectations of Filter/Order/Select validators.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Aug 26, 2025

✨ Benchmark results

  • Requests per second: 1,269
  • Requests with 200 status code: 228,522
  • P99 latency: 0.151478442

⚡ Benchmark Comparison

Metric This PR Latest version
RPS 1,269 1,025
200 228,522 184,568
P99 0.151478442 0.188164046

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/Appwrite/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: Confirm Select Opt-In Only for Deployments

  • ✅ Verified that only Deployments overrides isSelectQueryAllowed(): bool to return true (src/Appwrite/Utopia/Database/Validator/Queries/Deployments.php:26–29).
  • ✅ Base class remains false by default (src/Appwrite/Utopia/Database/Validator/Queries/Base.php:106–108). No other overrides found.
  • ⚠️ I did not find any existing tests invoking select() or isSelectQueryAllowed().

To prevent regressions, please add unit tests that:

  • Assert that Deployments queries allow select().
  • Assert that other query validators (inheriting from Base) reject or block select().
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a413235 and 22de107.

📒 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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (17)
src/Appwrite/SDK/Method.php (1)

106-108: Cache or inject a single Swoole Request/Response in validateResponseModel

Repeatedly instantiating new Request(new HttpRequest()) and new 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, method validateResponseModel
• Recommended approach:
– Add private properties on Method to hold a cached Request and Response (initialized once in the constructor or via a factory).
– Update validateResponseModel to 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 projection

Aligns 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 Request

Keeps 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 PHPMD

Call 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 tests

Tests 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 both new SwooleRequest() and new 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 param

Method 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 consistent

Parameter 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 param

Execution::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): Document
src/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): Document
src/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.

📥 Commits

Reviewing files that changed from the base of the PR and between 22de107 and f2dd03e.

📒 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.php
  • src/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 of new Response(...) now includes the required Request argument—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 appropriate

Needed for the new filter signature.

src/Appwrite/Utopia/Response/Model/User.php (1)

5-5: Import added is appropriate

src/Appwrite/Utopia/Response/Model/Migration.php (1)

5-5: Import added is appropriate

src/Appwrite/Utopia/Response/Model/ColumnIndex.php (1)

5-5: Import added is appropriate

tests/unit/Utopia/ResponseTest.php (1)

21-22: LGTM: Response now receives Request

Passing 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 Worker

In our CLI environment, class_exists('Swoole\Http\Request') returns false, so calling new 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.php at line 615

Please 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 every new Response( in the PHP codebase (excluding vendor), and all call sites now pass both the native response and a Request instance. The only single-argument new 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 validated

All 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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (2)

724-735: Harden select(['status']) assertions and reduce flakiness

Add 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 path

Validate 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.

📥 Commits

Reviewing files that changed from the base of the PR and between f2dd03e and 31b8e33.

📒 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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 31b8e33 and 6b8a4a0.

📒 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) calls applySelectQueries($document, $request). Drop the unused $document parameter, 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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
src/Appwrite/Platform/Modules/Compute/Base.php (2)

24-35: Fix docblock to match signature and intent

The 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 lookup

PHPMD 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 description

Clarify 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 well

Aligns 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 6b8a4a0 and b1c1acf.

📒 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 good

Adding the parameter description to filter() improves self-documentation.


109-116: Public removeRule(): confirm model lifecycle to avoid leakage across requests

Making 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 call

Keeps projection logic centralized and consistent.


60-63: Request injection LGTM

Injecting request enables per-call select handling without changing existing param schema.


66-73: Signature change LGTM

Adding Request before Response matches the new injections and preserves DI order.


128-133: Applying select before responding is correct

Pruning 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 projection

Mirrors Functions endpoint for consistency.


60-63: Request injection LGTM

Enables select-aware responses without altering public API shape.


66-73: Signature update LGTM

Ordering matches injected dependencies.


128-133: Projection applied at the right point

Model pruning occurs after data retrieval and before rendering — correct placement.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 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 $rule flagged 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.

📥 Commits

Reviewing files that changed from the base of the PR and between b1c1acf and 14194ec.

📒 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.

@Meldiron Meldiron merged commit b3fa60b into 1.8.x Sep 2, 2025
41 checks passed
@stnguyen90 stnguyen90 deleted the feat-select-queries-on-deployments branch September 5, 2025 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants