Skip to content

Feat disable count#10668

Merged
abnegate merged 23 commits into1.8.xfrom
feat-disable-count
Oct 29, 2025
Merged

Feat disable count#10668
abnegate merged 23 commits into1.8.xfrom
feat-disable-count

Conversation

@shimonewman
Copy link
Copy Markdown
Contributor

Disable list total response given, includeTotal param === false

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 19, 2025

📝 Walkthrough

Walkthrough

Adds a boolean query parameter total (exposed internally as includeTotal, default true, Boolean-validated) to many list and log endpoints across API controllers and platform modules. The parameter is declared in route definitions, propagated into action/method signatures, and used to gate total-count computation: when false the response total is set to 0; when true existing count logic is retained. End-to-end tests were extended to assert total === 0 for total=false requests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas needing extra attention:

  • Widespread public API signature changes across controllers and platform modules — verify routing, dependency injection, and backward compatibility.
  • Consistency of the new total param name vs internal includeTotal variable across all endpoints.
  • Constructor/endpoint parameter additions in many XList classes and correct placement of the new bool parameter in action signatures.
  • Database count gating (ensure no unintended elimination of required counts and consider performance semantics).
  • Numerous test additions that duplicate assertions — check for flakiness or redundant cases.
  • New imports of Utopia\Validator\Boolean and any related linter or dependency issues.

Suggested reviewers

  • eldadfux
  • abnegate
  • Meldiron

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.58% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The pull request title "Feat disable count" refers to a real aspect of the changeset—specifically, the feature to conditionally disable total count calculations in list endpoints. However, the title uses vague shorthand terminology that requires prior knowledge to fully understand. It does not clearly convey what is being disabled (total counts in list endpoints), how it works (via an includeTotal parameter), or the scope of the change (across numerous list endpoints). The phrasing is somewhat generic and lacks the specificity needed for a developer scanning the git history to immediately understand the primary change.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed The pull request description "Disable list total response given, includeTotal param === false" directly describes the core functionality introduced by the changeset. It clearly articulates the objective: when the includeTotal parameter is set to false, the list endpoints should not return or calculate the total count. This is directly related to the extensive changes made across multiple list endpoints (messaging, migrations, projects, storage, teams, users, vcs, databases, functions, etc.) that all follow this same pattern. Although terse, the description conveys meaningful information about the changeset's purpose.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-disable-count

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

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Oct 19, 2025

Security Scan Results for PR

Docker Image Scan Results

Package Version Vulnerability Severity
binutils 2.44-r2 CVE-2025-5244 HIGH
binutils 2.44-r2 CVE-2025-5245 HIGH
libxml2 2.13.8-r0 CVE-2025-49794 CRITICAL
libxml2 2.13.8-r0 CVE-2025-49796 CRITICAL
libxml2 2.13.8-r0 CVE-2025-49795 HIGH
libxml2 2.13.8-r0 CVE-2025-6021 HIGH
pcre2 10.43-r1 CVE-2025-58050 CRITICAL
golang.org/x/crypto v0.31.0 CVE-2025-22869 HIGH
golang.org/x/oauth2 v0.24.0 CVE-2025-22868 HIGH
stdlib 1.22.10 CVE-2025-47907 HIGH

Source Code Scan Results

🎉 No vulnerabilities found!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 47

🧹 Nitpick comments (2)
app/controllers/api/projects.php (1)

1247-1254: LGTM - Consider future query optimization.

The implementation correctly conditionally gates the total count. Note that the optimization benefit is currently limited since the data is already fetched from the database and count() on a PHP array is O(1). For more substantial performance gains, consider modifying the database query itself when includeTotal is false in future optimizations.

app/controllers/api/users.php (1)

695-695: Consider consistent approach for count queries.

There's an inconsistency in how queries are passed to count operations:

  • Lines 695 and 1077 pass $queries directly
  • Line 1148 uses extracted $filterQueries

While the database layer handles filter separation internally (per learnings), mixing approaches within the same file reduces clarity. Consider standardizing on one pattern across all list endpoints in this file for consistency.

Based on learnings

Also applies to: 1077-1077, 1145-1148

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 254f026 and d0e0f67.

📒 Files selected for processing (27)
  • app/controllers/api/account.php (2 hunks)
  • app/controllers/api/messaging.php (8 hunks)
  • app/controllers/api/migrations.php (2 hunks)
  • app/controllers/api/projects.php (6 hunks)
  • app/controllers/api/storage.php (4 hunks)
  • app/controllers/api/teams.php (5 hunks)
  • app/controllers/api/users.php (6 hunks)
  • app/controllers/api/vcs.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Proxy/Http/Rules/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-11T10:32:38.142Z
Learnt from: abnegate
PR: appwrite/appwrite#10297
File: app/controllers/api/users.php:649-657
Timestamp: 2025-08-11T10:32:38.142Z
Learning: In Appwrite's utopia-php/database (version 0.77.* and later), the database layer internally handles filter separation for count operations. When using `$dbForProject->count()` within a `skipFilters` closure, there's no need to manually separate filter queries using `Query::groupByType($queries)['filters']` as the database handles this automatically.

Applied to files:

  • app/controllers/api/migrations.php
  • src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php
  • src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php
  • app/controllers/api/users.php
  • app/controllers/api/teams.php
  • app/controllers/api/storage.php
  • app/controllers/api/vcs.php
🧬 Code graph analysis (27)
src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (1)
  • action (68-136)
src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
app/controllers/api/migrations.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (5)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (1)
  • action (72-145)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)
  • action (68-114)
src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (5)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (1)
  • action (72-145)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)
  • action (68-114)
src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php (1)
  • action (64-119)
src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php (3)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php (1)
  • action (66-130)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php (1)
  • action (68-136)
src/Appwrite/Platform/Modules/Databases/Http/TablesDB/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (4)
src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (1)
  • action (68-136)
src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php (1)
  • action (64-119)
src/Appwrite/Platform/Modules/Proxy/Http/Rules/XList.php (1)
  • action (62-120)
src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php (1)
  • action (64-114)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (5)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (1)
  • action (72-145)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
app/controllers/api/projects.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Proxy/Http/Rules/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
app/controllers/api/users.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
app/controllers/api/teams.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
app/controllers/api/storage.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (4)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (1)
  • action (72-145)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
src/Appwrite/Databases/TransactionState.php (2)
  • TransactionState (20-745)
  • countDocuments (156-210)
src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
app/controllers/api/messaging.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
app/controllers/api/account.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
app/controllers/api/vcs.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (4)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)
  • action (68-114)
🪛 GitHub Actions: Linter
src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php

[error] 1-1: PSR-12: ordered_imports failed.

src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php

[error] 1-1: PSR-12: ordered_imports failed.

src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php

[error] 1-1: PSR-12: ordered_imports failed.

src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php

[error] 1-1: PSR-12: ordered_imports failed.

src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php

[error] 1-1: PSR-12: ordered_imports failed.

src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php

[error] 1-1: PSR-12: ordered_imports failed.

src/Appwrite/Platform/Modules/Databases/Http/TablesDB/XList.php

[error] 1-1: PSR-12: ordered_imports failed.

src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php

[error] 1-1: PSR-12: ordered_imports failed.

src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php

[error] 1-1: PSR-12: ordered_imports failed.

src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php

[error] 1-1: PSR-12: ordered_imports failed.

src/Appwrite/Platform/Modules/Proxy/Http/Rules/XList.php

[error] 1-1: PSR-12: ordered_imports failed.

app/controllers/api/teams.php

[error] 1-1: PSR-12: ordered_imports failed.

src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php

[error] 1-1: PSR-12: ordered_imports failed.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: E2E Service Test (Teams)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Tokens)
  • GitHub Check: E2E Service Test (Locale)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (Realtime)
  • GitHub Check: E2E Service Test (Functions)
  • GitHub Check: E2E Service Test (Projects)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Account)
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: Unit Test
  • GitHub Check: E2E General Test
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: scan
🔇 Additional comments (12)
src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php (1)

64-64: LGTM! The includeTotal parameter implementation is correct.

The parameter is properly integrated into the action signature and the conditional total calculation correctly gates the count operation.

Also applies to: 105-105

src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php (1)

63-63: LGTM! The includeTotal parameter implementation is correct.

The parameter is properly integrated into the action signature and the conditional total calculation correctly gates the count operation.

Also applies to: 91-91

src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)

70-70: LGTM! The includeTotal parameter implementation is correct.

The parameter is properly integrated into the action signature and the conditional total calculation correctly gates the count operation.

Also applies to: 127-127

src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php (1)

67-67: LGTM! The includeTotal parameter implementation is correct.

The parameter is properly integrated into the action signature and the conditional total calculation correctly gates the count operation.

Also applies to: 110-110

src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (1)

69-69: LGTM! The includeTotal parameter implementation is correct.

The parameter is properly integrated into the action signature and the conditional total calculation correctly gates the count operation.

Also applies to: 109-109

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

73-73: LGTM! The includeTotal parameter implementation is correct.

The parameter is properly integrated into the action signature and the conditional total calculation correctly gates the count operation.

Also applies to: 117-117

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

79-79: LGTM! The includeTotal parameter implementation is correct.

The parameter is properly integrated into the action signature and the conditional total calculation correctly gates the count operation across all three code paths (transaction, with selects, and without selects).

Also applies to: 134-144

app/controllers/api/projects.php (2)

1537-1552: LGTM - Consistent implementation.

The parameter handling and conditional logic correctly follow the same pattern established for webhooks.


1841-1856: LGTM - Consistent implementation.

The parameter handling and conditional logic correctly follow the established pattern. The default value of true ensures backward compatibility.

app/controllers/api/account.php (2)

5311-5311: LGTM!

The function signature correctly includes the bool $includeTotal parameter with proper typing.


5352-5352: LGTM!

The conditional count logic correctly implements the includeTotal flag, allowing callers to skip the potentially expensive count operation when the total is not needed.

app/controllers/api/storage.php (1)

846-855: LGTM: Conditional count logic correctly implemented.

The implementation properly gates the count operation on includeTotal in both authorization paths (with and without fileSecurity), ensuring expensive count queries are skipped when not needed.

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.

Review continued from previous batch...

@github-actions
Copy link
Copy Markdown

github-actions bot commented Oct 19, 2025

✨ Benchmark results

  • Requests per second: 1,202
  • Requests with 200 status code: 216,402
  • P99 latency: 0.162162569

⚡ Benchmark Comparison

Metric This PR Latest version
RPS 1,202 1,247
200 216,402 224,538
P99 0.162162569 0.164853599

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

♻️ Duplicate comments (3)
app/controllers/api/users.php (3)

649-649: Fix typo in parameter description.

The description contains "countreturend" which should be "count returned".

This issue was already identified in a previous review.


1034-1034: Fix typo in parameter description.

Same typo: "countreturend" should be "count returned".

This issue was already identified in a previous review.


1106-1106: Fix typo in parameter description.

Same typo: "countreturend" should be "count returned".

This issue was already identified in a previous review.

🧹 Nitpick comments (4)
app/controllers/api/account.php (1)

5346-5353: Simplify count: pass full $queries; drop manual filter split

Database count already handles non-filter parts; align with other modules and reduce code.

Apply:

-        $filterQueries = Query::groupByType($queries)['filters'];
...
-        $total = $includeTotal ? $dbForProject->count('identities', $filterQueries, APP_LIMIT_COUNT) : 0;
+        $total = $includeTotal ? $dbForProject->count('identities', $queries, APP_LIMIT_COUNT) : 0;

Then remove the now-unused assignment:

-        $filterQueries = Query::groupByType($queries)['filters'];

Based on learnings.

app/controllers/api/teams.php (2)

216-220: Use $queries directly in count; remove $filterQueries

Manual separation is unnecessary; DB handles it. Matches pattern in other modules.

Apply:

-        $filterQueries = Query::groupByType($queries)['filters'];
...
-            $total = $includeTotal ? $dbForProject->count('teams', $filterQueries, APP_LIMIT_COUNT) : 0;
+            $total = $includeTotal ? $dbForProject->count('teams', $queries, APP_LIMIT_COUNT) : 0;

Based on learnings.


898-909: Same refactor for memberships count

Drop filter split; count with $queries for consistency and less code.

Apply:

-        $filterQueries = Query::groupByType($queries)['filters'];
...
-            $total = $includeTotal ? $dbForProject->count(
-                collection: 'memberships',
-                queries: $filterQueries,
-                max: APP_LIMIT_COUNT
-            ) : 0;
+            $total = $includeTotal ? $dbForProject->count(
+                collection: 'memberships',
+                queries: $queries,
+                max: APP_LIMIT_COUNT
+            ) : 0;

Based on learnings.

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

134-134: Counts correctly guarded by includeTotal; avoids unnecessary DB work.

All code paths skip count() when false, including transaction-aware counting. Consider adding an integration test that:

  • Creates N documents; asserts list with includeTotal=false returns total=0 and N items.
  • Asserts includeTotal=true returns total=N.

I can draft the test cases if you share the preferred test harness (E2E vs. module-level).

Also applies to: 138-138, 143-143

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9f80952 and 09075a0.

📒 Files selected for processing (27)
  • app/controllers/api/account.php (2 hunks)
  • app/controllers/api/messaging.php (8 hunks)
  • app/controllers/api/migrations.php (2 hunks)
  • app/controllers/api/projects.php (6 hunks)
  • app/controllers/api/storage.php (4 hunks)
  • app/controllers/api/teams.php (5 hunks)
  • app/controllers/api/users.php (6 hunks)
  • app/controllers/api/vcs.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Proxy/Http/Rules/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (12)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/XList.php
  • src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php
  • app/controllers/api/messaging.php
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php
  • app/controllers/api/projects.php
  • src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php
  • app/controllers/api/storage.php
  • app/controllers/api/migrations.php
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php
  • src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.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/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php
📚 Learning: 2025-08-11T10:32:38.142Z
Learnt from: abnegate
PR: appwrite/appwrite#10297
File: app/controllers/api/users.php:649-657
Timestamp: 2025-08-11T10:32:38.142Z
Learning: In Appwrite's utopia-php/database (version 0.77.* and later), the database layer internally handles filter separation for count operations. When using `$dbForProject->count()` within a `skipFilters` closure, there's no need to manually separate filter queries using `Query::groupByType($queries)['filters']` as the database handles this automatically.

Applied to files:

  • src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php
  • app/controllers/api/vcs.php
  • app/controllers/api/users.php
  • app/controllers/api/teams.php
🧬 Code graph analysis (15)
src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (6)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (1)
  • action (72-145)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)
  • action (68-114)
src/Appwrite/Databases/TransactionState.php (2)
  • TransactionState (20-745)
  • countDocuments (156-210)
app/controllers/api/account.php (5)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (1)
  • action (72-145)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (5)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (1)
  • action (72-145)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)
  • action (68-114)
src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php (3)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php (1)
  • action (68-136)
src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php (1)
  • action (65-121)
src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php (4)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php (1)
  • action (66-130)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php (1)
  • action (68-136)
src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)
  • action (68-114)
src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
app/controllers/api/vcs.php (3)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (1)
  • action (69-117)
app/controllers/api/users.php (3)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
src/Appwrite/Platform/Modules/Proxy/Http/Rules/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
app/controllers/api/teams.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: E2E Service Test (Users)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (Storage)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Projects)
  • GitHub Check: E2E Service Test (Realtime)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Locale)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (Functions)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (Account)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: E2E General Test
  • GitHub Check: Unit Test
  • GitHub Check: Benchmark
  • GitHub Check: scan
🔇 Additional comments (27)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (4)

21-21: LGTM: Boolean validator import added correctly.

The import is necessary for the new includeTotal parameter validation and is appropriately placed.


64-64: Parameter definition looks correct.

The includeTotal parameter is properly configured with appropriate default value (true for backward compatibility), Boolean validator, and clear description. The typo mentioned in previous reviews appears to have been addressed.


70-70: LGTM: Action signature correctly updated.

The bool $includeTotal parameter is properly positioned after route parameters and before injected dependencies, consistent with the pattern across other list endpoints in the codebase.


127-127: LGTM: Conditional total calculation implemented correctly.

The ternary logic properly gates the expensive count operation based on the includeTotal parameter, maintaining backward compatibility (default true) while enabling performance optimization when the total is not needed.

src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php (4)

23-23: Import order is correct.

The Boolean validator import is properly positioned in alphabetical order after the Utopia\Platform imports. The past concern about import ordering has been resolved.


58-60: Parameter definition looks good.

The includeTotal parameter is well-defined with appropriate validation, clear description, and a sensible default value (true) that maintains backward compatibility. The past typo concern has been resolved.


66-72: Action signature correctly updated.

The method signature properly includes the new bool $includeTotal parameter with correct type declaration, matching the route parameter configuration.


117-122: Test coverage for includeTotal parameter is missing.

While tests exist for the executions list endpoint and validate the 'total' field, there are no test cases covering the conditional behavior of the includeTotal parameter. The helper method listExecutions() in tests/e2e/Services/Functions/FunctionsBase.php supports passing arbitrary parameters, enabling easy addition of tests.

Add test cases to verify:

  • includeTotal=false returns total=0 without database count
  • includeTotal=true returns calculated total count as before
app/controllers/api/vcs.php (1)

1461-1461: LGTM! The includeTotal parameter implementation is correct.

The implementation follows the established pattern used in other list endpoints (Projects, Collections, etc.) and maintains backward compatibility with the default value of true. The conditional count logic properly uses $filterQueries for the count operation, and the typo from the previous review has been corrected.

Also applies to: 1466-1466, 1507-1507

app/controllers/api/account.php (2)

5307-5307: includeTotal param looks good

Clear description and defaults. Matches SDK/GraphQL expectations.


5311-5311: Action wiring OK

Boolean includeTotal correctly threaded into handler.

app/controllers/api/teams.php (5)

58-60: Imports OK

Boolean import added and order complies with PSR-12.


176-176: includeTotal param added — good

Clear behavior and default true.


179-179: Handler signature updated correctly

includeTotal threaded into list action.


848-848: includeTotal for memberships — good

Consistent param and description.


852-852: Memberships handler signature updated correctly

Boolean includeTotal included.

src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php (1)

14-14: LGTM! Clean implementation of includeTotal parameter.

The Boolean import and parameter declaration are correct, with proper validation and clear documentation. The parameter defaults to true for backward compatibility.

Also applies to: 56-56

src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php (1)

20-20: LGTM! Complete and correct implementation.

The includeTotal parameter is properly:

  • Imported and validated with Boolean
  • Declared with appropriate defaults and description
  • Added to the action signature
  • Used to conditionally compute totals

The logic correctly returns 0 when includeTotal is false, avoiding the performance cost of counting.

Also applies to: 58-58, 64-64, 105-105

src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php (1)

13-13: LGTM! Correct parameter addition.

The includeTotal parameter is properly declared with Boolean validation and clear documentation. The implementation follows the established pattern.

Also applies to: 52-52

src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php (1)

14-14: LGTM! Proper parameter declaration.

The includeTotal parameter is correctly added with Boolean validation and appropriate documentation, following the consistent pattern across the codebase.

Also applies to: 55-55

src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php (1)

22-22: LGTM! Well-implemented conditional total calculation.

The implementation correctly:

  • Imports and validates the parameter with Boolean
  • Adds it to the action signature in the appropriate position
  • Uses it to conditionally skip the count operation when set to false

This provides a performance optimization for clients that don't need the total count.

Also applies to: 59-59, 65-65, 112-112

src/Appwrite/Platform/Modules/Proxy/Http/Rules/XList.php (1)

18-18: LGTM! Consistent implementation across the proxy module.

The includeTotal parameter is properly integrated:

  • Boolean validation at the API boundary
  • Action signature updated correctly
  • Ternary conditional used inline for clean response construction

The pattern aligns well with other modules in this PR.

Also applies to: 55-55, 65-65, 118-118

src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (1)

21-21: LGTM! Correctly implemented for the projects module.

The includeTotal parameter addition is clean and follows the established pattern:

  • Boolean validator ensures type safety
  • Default true preserves backward compatibility
  • Conditional logic correctly bypasses expensive count when not needed

Also applies to: 63-63, 69-69, 109-109

src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (1)

22-22: LGTM! Final file completes the consistent pattern.

The includeTotal implementation in the deployments endpoint is correct and mirrors the approach across all other modules:

  • Proper Boolean validation
  • Clear parameter documentation
  • Action signature updated appropriately
  • Performance-conscious conditional counting

This completes a well-coordinated PR that uniformly adds optional total-count suppression across multiple list endpoints.

Also applies to: 61-61, 72-72, 126-126

src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (3)

25-26: Import order is now PSR-12 compliant.

Boolean correctly precedes Text. Good fix.


79-80: Signature/injection order is correct.

Parameter order aligns with defined params and injections; no routing mismatch expected.


71-71: Code changes are consistent; verify API spec and schema updates are planned.

Internal consistency verified: includeTotal param definition, Boolean validator, description text, and conditional count guards are identical across all 40+ list endpoints. The change at line 71 aligns with existing patterns.

However, SDK and GraphQL updates won't auto-regenerate from this code change alone. The SDK preview workflow (.github/workflows/sdk-preview.yml) only triggers on changes to app/config/specs/*-latest-console.json, which this PR does not modify. Confirm that:

  • API spec files will be updated separately to expose includeTotal and trigger SDK regeneration
  • Or SDKs/schema updates are being handled in a follow-up PR or external process

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

Caution

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

⚠️ Outside diff range comments (2)
app/controllers/api/messaging.php (2)

2697-2705: Missing includeTotal support on subscribers list

This endpoint doesn’t accept includeTotal and always computes total. For parity with the PR goal, add the includeTotal param and gate the count.

Proposed diff:

-    ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
+    ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
+    ->param('includeTotal', true, new Boolean(), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
...
-    ->action(function (string $topicId, array $queries, string $search, Database $dbForProject, Response $response) {
+    ->action(function (string $topicId, array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) {
...
-                'total' => $dbForProject->count('subscribers', $queries, APP_LIMIT_COUNT),
+                'total' => $includeTotal ? $dbForProject->count('subscribers', $queries, APP_LIMIT_COUNT) : 0,

Also applies to: 2762-2766


3384-3394: Undefined variable in push image URL expiry

$currentScheduledAt is used but never defined in this action, causing a notice/error.

Apply:

-            $scheduleTime = $currentScheduledAt ?? $scheduledAt;
+            $scheduleTime = $scheduledAt;

Or define $currentScheduledAt earlier if intended.

♻️ Duplicate comments (1)
app/controllers/api/users.php (1)

1148-1151: Inconsistent query handling for count operation.

This endpoint uses $filterQueries for count (line 1151) while using $queries for find (line 1150), making it inconsistent with other list endpoints in this file (users at lines 694-695, targets at lines 1079-1080) which use $queries for both operations. The manual filter separation on line 1148 is unnecessary as the database layer in v0.77.x+ handles this automatically.

Based on learnings.

This issue was already flagged in a previous review comment.

🧹 Nitpick comments (11)
tests/e2e/Services/Teams/TeamsBase.php (1)

325-341: Good coverage for includeTotal=false on /teams.

Consider extracting a small helper/assert to reuse this pattern across suites to reduce duplication.

tests/e2e/Services/Messaging/MessagingBase.php (1)

636-653: LGTM for subscribers includeTotal=false.

Optionally assert the first subscriber ID matches the earlier list to ensure data parity when only total is gated.

src/Appwrite/Platform/Modules/Functions/Http/Templates/XList.php (1)

56-56: Correct wiring of includeTotal; minor polish and coverage suggestion.

  • Param registration and action signature order are correct; total is skipped when includeTotal=false. Good.
  • Nit: align variable naming with the request param for readability.

Apply this small rename for clarity:

-    public function action(array $runtimes, array $usecases, int $limit, int $offset, bool $includeTotal, Response $response)
+    public function action(array $runtimes, array $useCases, int $limit, int $offset, bool $includeTotal, Response $response)
@@
-        if (!empty($usecases)) {
-            $templates = \array_filter($templates, function ($template) use ($usecases) {
-                return \count(\array_intersect($usecases, $template['useCases'])) > 0;
+        if (!empty($useCases)) {
+            $templates = \array_filter($templates, function ($template) use ($useCases) {
+                return \count(\array_intersect($useCases, $template['useCases'])) > 0;
             });
         }

Also, please add a small E2E/unit test for listTemplates with includeTotal=false to keep parity with other endpoints.

Also applies to: 61-86

app/controllers/api/messaging.php (2)

3311-3311: Doc vs validation mismatch for push image types

Docs allow jpeg/png/bmp; validation allows only image/png and image/jpeg. Either update docs or include image/bmp in the allowed list.

Also applies to: 3379-3381


3606-3610: Hard-coded “Temp fix for logs” date filters

Consider replacing the hard-coded OR date filter with a feature flag or removing it before release to avoid surprising log gaps.

app/controllers/api/teams.php (3)

176-180: Simplify count() usage; no manual filter grouping needed

You can pass $queries directly to count(); the DB layer separates filters internally.

Apply:

-        $filterQueries = Query::groupByType($queries)['filters'];
         try {
             $results = $dbForProject->find('teams', $queries);
-            $total = $includeTotal ? $dbForProject->count('teams', $filterQueries, APP_LIMIT_COUNT) : 0;
+            $total = $includeTotal ? $dbForProject->count('teams', $queries, APP_LIMIT_COUNT) : 0;

Based on learnings

Also applies to: 216-220


848-852: Memberships list: align count() call with queries

Same as above; pass $queries to count() directly, no need for groupByType.

-        $filterQueries = Query::groupByType($queries)['filters'];
...
-            $total = $includeTotal ? $dbForProject->count(
-                collection: 'memberships',
-                queries: $filterQueries,
-                max: APP_LIMIT_COUNT
-            ) : 0;
+            $total = $includeTotal ? $dbForProject->count(
+                collection: 'memberships',
+                queries: $queries,
+                max: APP_LIMIT_COUNT
+            ) : 0;

Based on learnings

Also applies to: 898-909


1448-1454: Team logs: includeTotal gating — LGTM

Gating is consistent. Consider removing the hard-coded “Temp fix for logs” date filter before release.

Also applies to: 1521-1525

tests/e2e/Services/Databases/TablesDB/DatabasesCustomServerTest.php (1)

68-68: Align assertEquals parameter order.

assertEquals expects the expected value first; passing the actual value first flips the diff/context when the assertion fails. Please swap the arguments so the failure output remains intuitive.

-        $this->assertEquals($databasesWithIncludeTotalFalse['headers']['status-code'], 200);
+        $this->assertEquals(200, $databasesWithIncludeTotalFalse['headers']['status-code']);
tests/e2e/Services/Account/AccountCustomClientTest.php (1)

239-257: Test logic for includeTotal=false looks good.

The test correctly verifies that when includeTotal=false, the API returns total=0 while still providing session data. This validates the feature objective.

Minor style consideration: Line 251 uses assertEquals($actual, $expected) while the rest of the file consistently uses assertEquals($expected, $actual). Consider standardizing:

-        $this->assertEquals($sessionsWithIncludeTotalFalse['headers']['status-code'], 200);
+        $this->assertEquals(200, $sessionsWithIncludeTotalFalse['headers']['status-code']);
tests/e2e/Services/Functions/FunctionsCustomClientTest.php (1)

379-395: Test validates includeTotal=false correctly.

The test confirms that includeTotal=false suppresses the total count (returns 0) while still returning template data. The logic is sound and consistent with the first test file.

Minor style consideration: Line 389 uses assertEquals($actual, $expected) which differs from the convention used in the rest of the test suite. Consider aligning for consistency:

-        $this->assertEquals($templatesWithIncludeTotalFalse['headers']['status-code'], 200);
+        $this->assertEquals(200, $templatesWithIncludeTotalFalse['headers']['status-code']);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09075a0 and fb4e3e1.

📒 Files selected for processing (15)
  • app/controllers/api/account.php (6 hunks)
  • app/controllers/api/messaging.php (16 hunks)
  • app/controllers/api/teams.php (7 hunks)
  • app/controllers/api/users.php (12 hunks)
  • src/Appwrite/Platform/Modules/Functions/Http/Templates/XList.php (3 hunks)
  • tests/e2e/Services/Account/AccountCustomClientTest.php (1 hunks)
  • tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1 hunks)
  • tests/e2e/Services/Databases/Legacy/DatabasesCustomServerTest.php (3 hunks)
  • tests/e2e/Services/Databases/TablesDB/DatabasesCustomServerTest.php (1 hunks)
  • tests/e2e/Services/Functions/FunctionsCustomClientTest.php (1 hunks)
  • tests/e2e/Services/Functions/FunctionsCustomServerTest.php (2 hunks)
  • tests/e2e/Services/Messaging/MessagingBase.php (1 hunks)
  • tests/e2e/Services/Storage/StorageBase.php (1 hunks)
  • tests/e2e/Services/Teams/TeamsBase.php (1 hunks)
  • tests/e2e/Services/Users/UsersBase.php (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-11T10:32:38.142Z
Learnt from: abnegate
PR: appwrite/appwrite#10297
File: app/controllers/api/users.php:649-657
Timestamp: 2025-08-11T10:32:38.142Z
Learning: In Appwrite's utopia-php/database (version 0.77.* and later), the database layer internally handles filter separation for count operations. When using `$dbForProject->count()` within a `skipFilters` closure, there's no need to manually separate filter queries using `Query::groupByType($queries)['filters']` as the database handles this automatically.

Applied to files:

  • app/controllers/api/users.php
  • app/controllers/api/teams.php
🧬 Code graph analysis (15)
tests/e2e/Services/Account/AccountCustomClientTest.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Scopes/ProjectCustom.php (1)
  • getProject (21-185)
tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Services/Messaging/MessagingBase.php (1)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Services/Databases/TablesDB/DatabasesCustomServerTest.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Scopes/Scope.php (1)
  • getHeaders (145-145)
tests/e2e/Services/Storage/StorageBase.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Scopes/Scope.php (1)
  • getHeaders (145-145)
tests/e2e/Services/Functions/FunctionsCustomClientTest.php (2)
tests/e2e/Client.php (2)
  • call (181-302)
  • Client (8-342)
tests/e2e/Scopes/Scope.php (1)
  • getHeaders (145-145)
src/Appwrite/Platform/Modules/Functions/Http/Templates/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
tests/e2e/Services/Databases/Legacy/DatabasesCustomServerTest.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Scopes/Scope.php (1)
  • getHeaders (145-145)
tests/e2e/Services/Teams/TeamsBase.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Scopes/Scope.php (1)
  • getHeaders (145-145)
tests/e2e/Services/Users/UsersBase.php (3)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Scopes/ProjectCustom.php (1)
  • getProject (21-185)
tests/e2e/Scopes/Scope.php (1)
  • getHeaders (145-145)
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (1)
tests/e2e/Services/Sites/SitesBase.php (1)
  • listDeployments (217-225)
app/controllers/api/messaging.php (4)
src/Appwrite/Platform/Modules/Functions/Http/Templates/XList.php (1)
  • action (61-87)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php (1)
  • action (64-119)
app/controllers/api/account.php (6)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Functions/Http/Templates/XList.php (1)
  • action (61-87)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (1)
  • action (72-145)
app/controllers/api/users.php (3)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Functions/Http/Templates/XList.php (1)
  • action (61-87)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
app/controllers/api/teams.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
⏰ 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: CodeQL
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: scan
🔇 Additional comments (16)
tests/e2e/Services/Users/UsersBase.php (1)

801-817: LGTM: includeTotal=false behavior covered for /users.

As a sanity check, confirm the GET param encodes false as expected by the Boolean validator (http_build_query can emit an empty value). If needed, normalize to '0'/'1' or 'false'/'true' at parsing.

tests/e2e/Services/Storage/StorageBase.php (1)

382-398: LGTM: includeTotal=false on bucket files list behaves as expected.

app/controllers/api/messaging.php (7)

988-992: Providers list: includeTotal gating — LGTM

Conditionally computing total with includeTotal is correct and consistent with other modules.

Also applies to: 1026-1034


1057-1063: Provider logs: includeTotal gating — LGTM

Total is gated; response shape preserved.

Also applies to: 1129-1133


2366-2372: Topic logs: includeTotal gating — LGTM

Total correctly gated.

Also applies to: 2439-2443


2788-2794: Subscriber logs: includeTotal gating — LGTM

Looks consistent with other logs endpoints.

Also applies to: 2861-2865


3519-3523: Messages list: includeTotal gating — LGTM

Parsing, search, cursor handling, and total gating look correct.

Also applies to: 3556-3565


3588-3594: Message logs: includeTotal gating — LGTM

All good.

Also applies to: 3661-3665


3687-3691: Message targets list: includeTotal gating — LGTM

Early return with total 0 for empty targets is fine; gating correct otherwise.

Also applies to: 3739-3747

app/controllers/api/users.php (5)

647-707: LGTM! Clean implementation of the includeTotal feature.

The parameter is properly defined with appropriate validator, default value, and description. The conditional total calculation correctly skips the count query when includeTotal is false, providing the intended performance benefit.


828-857: LGTM! Appropriate implementation for nested collection.

The includeTotal parameter is correctly implemented. Since sessions are already loaded as part of the user document (line 841), using count($sessions) on the in-memory array is appropriate. The conditional logic correctly returns 0 when includeTotal is false.


876-918: LGTM! Consistent implementation.

The includeTotal parameter is properly added and the conditional total calculation is correct. The in-memory count() is appropriate here since memberships are already fetched and transformed for the response payload.


937-1016: LGTM! Proper integration with Audit service.

The includeTotal parameter is correctly implemented, and the conditional logic appropriately calls $audit->countLogsByUser() only when needed, providing the intended performance benefit.


1035-1088: LGTM! Consistent with other list endpoints.

The includeTotal parameter implementation is clean and consistent. Both find() and count() correctly use the same $queries array, which aligns with the database layer's automatic filter handling.

tests/e2e/Services/Functions/FunctionsCustomServerTest.php (2)

421-432: LGTM! Well-structured test for includeTotal=false parameter.

The test correctly validates that when includeTotal=false, the API returns total=0 while still populating the deployments array. Good placement alongside the default behavior test.


1019-1030: LGTM! Consistent test pattern for executions list.

The test mirrors the deployments test pattern at lines 421-432, ensuring consistent validation of the includeTotal=false behavior across different list endpoints. The assertions comprehensively verify the expected behavior.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
tests/e2e/Services/Databases/Legacy/DatabasesCustomServerTest.php (1)

65-65: Pass includeTotal as the string 'false' so the API actually disables totals

Client::call() turns GET params into a query string with http_build_query; when you pass the boolean false it serializes to an empty value (e.g., includeTotal=), so the backend never receives a literal "false" and can fall back to the default true. That makes these tests flaky with respect to the feature they’re asserting. Please send the parameter as the string 'false' in all three spots so the request is deterministic.

-            'includeTotal' => false
+            'includeTotal' => 'false'

Apply the same change to the collections and documents calls.

Also applies to: 422-422, 4593-4593

🧹 Nitpick comments (3)
tests/e2e/Services/Teams/TeamsBase.php (1)

325-341: LGTM! Test correctly validates includeTotal=false behavior.

The test appropriately validates that when includeTotal=false is passed, the API returns total=0 while still populating the teams array with actual data. The assertions are comprehensive and align with the PR's objectives.

Optional enhancement: Consider adding custom assertion messages for easier debugging when tests fail. For example:

-        $this->assertEquals(0, $teamsWithIncludeTotalFalse['body']['total']);
+        $this->assertEquals(0, $teamsWithIncludeTotalFalse['body']['total'], 'Expected total to be 0 when includeTotal=false');
-        $this->assertGreaterThan(0, count($teamsWithIncludeTotalFalse['body']['teams']));
+        $this->assertGreaterThan(0, count($teamsWithIncludeTotalFalse['body']['teams']), 'Expected teams array to be populated even when includeTotal=false');
tests/e2e/Services/Messaging/MessagingBase.php (1)

636-653: LGTM! Test correctly validates includeTotal=false behavior for subscribers.

The test appropriately validates that when includeTotal=false is passed, the API returns total=0 while still populating the subscribers array with actual data. The implementation is consistent with the parallel test in TeamsBase.php and aligns with the PR's objectives.

Optional enhancement: Similar to the teams test, consider adding custom assertion messages for improved debugging:

-        $this->assertEquals(0, $subscribersWithIncludeTotalFalse['body']['total']);
+        $this->assertEquals(0, $subscribersWithIncludeTotalFalse['body']['total'], 'Expected total to be 0 when includeTotal=false');
-        $this->assertGreaterThan(0, count($subscribersWithIncludeTotalFalse['body']['subscribers']));
+        $this->assertGreaterThan(0, count($subscribersWithIncludeTotalFalse['body']['subscribers']), 'Expected subscribers array to be populated even when includeTotal=false');
tests/e2e/Services/Storage/StorageBase.php (1)

382-398: includeTotal=false happy-path covered; add edge coverage with queries and string input

This block looks good and validates the intended response shape and values when includeTotal=false. Consider two small additions to harden coverage:

  • Combine includeTotal=false with a query (e.g., limit(1)) to ensure gating the total doesn’t affect items returned.
  • Optionally pass 'false' (string) to guard server-side boolean coercion.

Example snippet to add after Line 399:

$filesLimitIncludeTotalFalse = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([
    'content-type' => 'application/json',
    'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
    'queries' => [ Query::limit(1)->toString() ],
    'includeTotal' => false,
]);
$this->assertEquals(200, $filesLimitIncludeTotalFalse['headers']['status-code']);
$this->assertEquals(1, count($filesLimitIncludeTotalFalse['body']['files']));
$this->assertSame(0, $filesLimitIncludeTotalFalse['body']['total']);

// Optional: accept string boolean
$filesStringFalse = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([
    'content-type' => 'application/json',
    'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
    'includeTotal' => 'false',
]);
$this->assertEquals(200, $filesStringFalse['headers']['status-code']);
$this->assertSame(0, $filesStringFalse['body']['total']);
$this->assertGreaterThan(0, count($filesStringFalse['body']['files']));
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9be7f4d and 5f3316f.

📒 Files selected for processing (10)
  • tests/e2e/Services/Account/AccountCustomClientTest.php (1 hunks)
  • tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1 hunks)
  • tests/e2e/Services/Databases/Legacy/DatabasesCustomServerTest.php (3 hunks)
  • tests/e2e/Services/Databases/TablesDB/DatabasesCustomServerTest.php (1 hunks)
  • tests/e2e/Services/Functions/FunctionsCustomClientTest.php (1 hunks)
  • tests/e2e/Services/Functions/FunctionsCustomServerTest.php (2 hunks)
  • tests/e2e/Services/Messaging/MessagingBase.php (1 hunks)
  • tests/e2e/Services/Storage/StorageBase.php (1 hunks)
  • tests/e2e/Services/Teams/TeamsBase.php (1 hunks)
  • tests/e2e/Services/Users/UsersBase.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • tests/e2e/Services/Functions/FunctionsCustomServerTest.php
  • tests/e2e/Services/Databases/Legacy/DatabasesBase.php
  • tests/e2e/Services/Users/UsersBase.php
  • tests/e2e/Services/Databases/TablesDB/DatabasesCustomServerTest.php
  • tests/e2e/Services/Functions/FunctionsCustomClientTest.php
  • tests/e2e/Services/Account/AccountCustomClientTest.php
🧰 Additional context used
🧬 Code graph analysis (4)
tests/e2e/Services/Storage/StorageBase.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Scopes/Scope.php (1)
  • getHeaders (145-145)
tests/e2e/Services/Teams/TeamsBase.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Scopes/Scope.php (1)
  • getHeaders (145-145)
tests/e2e/Services/Messaging/MessagingBase.php (1)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Services/Databases/Legacy/DatabasesCustomServerTest.php (2)
tests/e2e/Client.php (1)
  • Client (8-342)
tests/e2e/Scopes/Scope.php (1)
  • getHeaders (145-145)
⏰ 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). (19)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Realtime)
  • GitHub Check: E2E Service Test (Proxy)
  • GitHub Check: E2E Service Test (Teams)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (Storage)
  • GitHub Check: E2E Service Test (VCS)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (Functions)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Account)
  • 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
  • GitHub Check: Unit Test
  • GitHub Check: Benchmark
  • GitHub Check: scan

…ehavior across API endpoints, enhancing response handling for sessions, logs, memberships, and more.
…e-count

# Conflicts:
#	app/controllers/api/account.php
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)
app/controllers/api/users.php (1)

1108-1111: Remove manual filter separation for consistency with other endpoints.

The identities endpoint manually separates filters on Line 1108 and uses $filterQueries for count on Line 1111, while find() uses $queries on Line 1110. This is inconsistent with the users endpoint (Lines 653-654) and targets endpoint (Lines 1038-1039), which both use $queries for find and count operations.

Per the retrieved learning, the database layer in utopia-php/database v0.77.x+ automatically handles filter separation for count operations, making manual separation unnecessary.

Based on learnings.

Apply this diff to align with other endpoints:

-        $filterQueries = Query::groupByType($queries)['filters'];
         try {
             $identities = $dbForProject->find('identities', $queries);
-            $total = $includeTotal ? $dbForProject->count('identities', $filterQueries, APP_LIMIT_COUNT) : 0;
+            $total = $includeTotal ? $dbForProject->count('identities', $queries, APP_LIMIT_COUNT) : 0;
🧹 Nitpick comments (2)
app/controllers/api/teams.php (2)

213-216: Consider passing $queries directly to count().

The manual extraction of filter queries using Query::groupByType($queries)['filters'] is unnecessary. The database layer in utopia-php/database (version 0.77.*+) automatically handles filter separation for count operations.

Based on learnings

Apply this diff to simplify the code:

-        $filterQueries = Query::groupByType($queries)['filters'];
         try {
             $results = $dbForProject->find('teams', $queries);
-            $total = $includeTotal ? $dbForProject->count('teams', $filterQueries, APP_LIMIT_COUNT) : 0;
+            $total = $includeTotal ? $dbForProject->count('teams', $queries, APP_LIMIT_COUNT) : 0;
         } catch (OrderException $e) {

893-903: Consider passing $queries directly to count().

Similar to the /v1/teams endpoint, the manual extraction of filter queries is unnecessary. The database layer automatically handles filter separation for count operations.

Based on learnings

Apply this diff:

-        $filterQueries = Query::groupByType($queries)['filters'];
         try {
             $memberships = $dbForProject->find(
                 collection: 'memberships',
                 queries: $queries,
             );
-            $total = $includeTotal ? $dbForProject->count(
-                collection: 'memberships',
-                queries: $filterQueries,
-                max: APP_LIMIT_COUNT
-            ) : 0;
+            $total = $includeTotal ? $dbForProject->count(
+                collection: 'memberships',
+                queries: $queries,
+                max: APP_LIMIT_COUNT
+            ) : 0;
         } catch (OrderException $e) {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb0889f and 232f1b1.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • app/controllers/api/projects.php (6 hunks)
  • app/controllers/api/teams.php (7 hunks)
  • app/controllers/api/users.php (12 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-11T10:32:38.142Z
Learnt from: abnegate
PR: appwrite/appwrite#10297
File: app/controllers/api/users.php:649-657
Timestamp: 2025-08-11T10:32:38.142Z
Learning: In Appwrite's utopia-php/database (version 0.77.* and later), the database layer internally handles filter separation for count operations. When using `$dbForProject->count()` within a `skipFilters` closure, there's no need to manually separate filter queries using `Query::groupByType($queries)['filters']` as the database handles this automatically.

Applied to files:

  • app/controllers/api/teams.php
  • app/controllers/api/users.php
🧬 Code graph analysis (3)
app/controllers/api/teams.php (3)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
app/controllers/api/projects.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (1)
  • action (69-117)
app/controllers/api/users.php (3)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: E2E Service Test (Webhooks)
  • GitHub Check: E2E Service Test (Messaging)
  • GitHub Check: E2E Service Test (Storage)
  • GitHub Check: E2E Service Test (Tokens)
  • GitHub Check: E2E Service Test (Proxy)
  • GitHub Check: E2E Service Test (Realtime)
  • GitHub Check: E2E Service Test (Teams)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (Databases/TablesDB)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Account)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: E2E General Test
  • GitHub Check: Unit Test
  • GitHub Check: scan
🔇 Additional comments (5)
app/controllers/api/projects.php (3)

1237-1237: Implementation looks good for the webhooks endpoint.

The includeTotal parameter is properly implemented with correct validator, default value, and description. The conditional total calculation correctly avoids the count operation when includeTotal is false, aligning with the PR objective.

Also applies to: 1240-1240, 1255-1255


1535-1535: Implementation looks good for the keys endpoint.

The changes are consistent with the webhooks endpoint implementation. The includeTotal parameter follows the same pattern with correct validator, default value, and conditional logic.

Also applies to: 1538-1538, 1553-1553


1839-1839: Implementation looks good for the platforms endpoint.

The changes maintain consistency with the other endpoints in this file. The includeTotal parameter is correctly implemented with appropriate validator, default value, and conditional total calculation.

Also applies to: 1842-1842, 1857-1857

app/controllers/api/teams.php (2)

55-55: LGTM! Import is correctly ordered.

The Boolean validator import is properly placed in alphabetical order between Assoc and Text, maintaining PSR-12 compliance.


1436-1441: LGTM! Correct implementation for audit logs.

The includeTotal parameter is correctly implemented for the logs endpoint. The conditional total calculation using $audit->countLogsByResource() is appropriate and follows the expected pattern.

Also applies to: 1510-1510

…ccount endpoints, allowing control over total count calculation for sessions, logs, and identities. Updated tests to verify functionality.
…d' of github.com:appwrite/appwrite into feat-disable-count

# Conflicts:
#	composer.lock
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)
app/controllers/api/messaging.php (1)

2310-2346: APNS update: wrong credential key breaks enablement checks

Key is saved as 'bundle' but later enablement checks require 'bundleId', making enablement impossible after update.

Apply:

-        if (!empty($bundleId)) {
-            $credentials['bundle'] = $bundleId;
-        }
+        if (!empty($bundleId)) {
+            $credentials['bundleId'] = $bundleId;
+        }
♻️ Duplicate comments (1)
app/controllers/api/messaging.php (1)

2477-2480: Topics list: includeTotal change is fine; fix cursor assignment bug

Cursor should receive the Document, not an array index.

Apply:

-            $cursor->setValue($cursorDocument[0]);
+            $cursor->setValue($cursorDocument);

Also applies to: 2516-2517

🧹 Nitpick comments (1)
tests/e2e/Services/Messaging/MessagingBase.php (1)

647-664: IncludeTotal=false test looks good; consider extracting a tiny helper to reuse across list endpoints

Assertions are correct and match the new contract. To avoid repeating this pattern elsewhere (targets/logs), consider a small helper like assertIncludeTotalDisabled($resp, $groupKey) and call it in similar tests.

Example helper:

+private function assertIncludeTotalDisabled(array $response, string $groupKey): void
+{
+    $this->assertEquals(200, $response['headers']['status-code']);
+    $this->assertIsArray($response['body'][$groupKey]);
+    $this->assertIsInt($response['body']['total']);
+    $this->assertEquals(0, $response['body']['total']);
+    $this->assertGreaterThan(0, count($response['body'][$groupKey]));
+}

And usage here:

-$this->assertEquals(200, $subscribersWithIncludeTotalFalse['headers']['status-code']);
-...
-$this->assertGreaterThan(0, count($subscribersWithIncludeTotalFalse['body']['subscribers']));
+$this->assertIncludeTotalDisabled($subscribersWithIncludeTotalFalse, 'subscribers');
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ab1e510 and f18aa6b.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • app/controllers/api/messaging.php (18 hunks)
  • app/controllers/api/vcs.php (2 hunks)
  • tests/e2e/Services/Messaging/MessagingBase.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/controllers/api/vcs.php
🧰 Additional context used
🧬 Code graph analysis (2)
app/controllers/api/messaging.php (5)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)
  • action (68-114)
src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php (1)
  • action (64-119)
tests/e2e/Services/Messaging/MessagingBase.php (1)
tests/e2e/Client.php (1)
  • Client (8-342)
⏰ 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 (7)
app/controllers/api/messaging.php (7)

1070-1074: Providers: includeTotal gating is correct

Param, signature, and conditional count look consistent with the new behavior.

Also applies to: 1108-1110


1139-1140: Provider logs: includeTotal added and respected

Looks good; total is only computed when requested.

Also applies to: 1145-1145, 1212-1213


2546-2552: Topic logs: includeTotal gating is correct

No further issues spotted here.

Also applies to: 2620-2621


2969-2974: Subscriber logs: includeTotal gating is correct

All good.

Also applies to: 3043-3044


3769-3775: Message logs: includeTotal gating is correct

No issues.

Also applies to: 3843-3845


3868-3872: Message targets: includeTotal gating is correct; early empty-targets return handled

Returning total=0 for empty targets aligns with includeTotal=false semantics too. Good.

If you want to exercise the includeTotal=false path here in e2e, mirror the subscribers test with 'groupKey' => 'targets'.

Also applies to: 3920-3922


3700-3704: Add filterQueries extraction before count call; messaging.php doesn't follow established pattern

Line 3739 passes full $queries to count(), but the correct pattern across the codebase (teams, storage, migrations, users, etc.) is to extract and use only filter queries:

$filterQueries = Query::groupByType($queries)['filters'];
$total = $includeTotal ? $dbForProject->count('messages', $filterQueries, APP_LIMIT_COUNT) : 0;

Currently, limit/offset/selections get included in the count call, producing incorrect totals. Apply the same pattern used in all other list endpoints.

⛔ Skipped due to learnings
Learnt from: abnegate
PR: appwrite/appwrite#10297
File: app/controllers/api/users.php:649-657
Timestamp: 2025-08-11T10:32:38.142Z
Learning: In Appwrite's utopia-php/database (version 0.77.* and later), the database layer internally handles filter separation for count operations. When using `$dbForProject->count()` within a `skipFilters` closure, there's no need to manually separate filter queries using `Query::groupByType($queries)['filters']` as the database handles this automatically.

…1' of github.com:appwrite/appwrite into feat-disable-count

# Conflicts:
#	composer.lock
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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f18aa6b and 3300013.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • app/controllers/api/account.php (4 hunks)
  • app/controllers/api/migrations.php (2 hunks)
  • app/controllers/api/users.php (12 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/controllers/api/migrations.php
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-11T10:32:38.142Z
Learnt from: abnegate
PR: appwrite/appwrite#10297
File: app/controllers/api/users.php:649-657
Timestamp: 2025-08-11T10:32:38.142Z
Learning: In Appwrite's utopia-php/database (version 0.77.* and later), the database layer internally handles filter separation for count operations. When using `$dbForProject->count()` within a `skipFilters` closure, there's no need to manually separate filter queries using `Query::groupByType($queries)['filters']` as the database handles this automatically.

Applied to files:

  • app/controllers/api/users.php
🧬 Code graph analysis (2)
app/controllers/api/account.php (3)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
app/controllers/api/users.php (3)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
⏰ 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). (19)
  • GitHub Check: E2E Service Test (Messaging)
  • GitHub Check: E2E Service Test (Teams)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Realtime)
  • GitHub Check: E2E Service Test (Proxy)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Functions)
  • GitHub Check: E2E Service Test (Databases/TablesDB)
  • GitHub Check: E2E Service Test (Account)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • 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 (8)
app/controllers/api/account.php (3)

2823-2871: LGTM! Conditional count logic correctly implemented.

The implementation correctly gates the expensive countLogsByUser call behind the includeTotal check. When includeTotal is false, the total is set to 0 without performing the count operation, which aligns with the PR objectives and matches the pattern used in other modules.


5219-5266: LGTM! Consistent implementation with logs endpoint.

The includeTotal parameter is correctly integrated into the action signature and the conditional count logic properly skips the database count when false. The implementation is consistent with the /v1/account/logs endpoint and follows the established pattern from other XList implementations.


2817-2817: Verify the Boolean validator instantiation.

The includeTotal parameter uses new Boolean(true), but other Boolean parameters in this file (e.g., line 4081 for the mfa parameter) use new Boolean() without arguments. Please verify whether the Boolean validator accepts a parameter and if this usage is correct, or if it should be new Boolean() for consistency.

app/controllers/api/users.php (5)

608-612: includeTotal wiring for users list looks correct.

Parameter, action signature, and gated count are consistent and avoid DB count when false.

Also applies to: 651-655


788-789: Sessions list: correct conditional total.

Local count of in-memory sessions is fine (no query/limit here).

Also applies to: 792-793, 814-815


996-997: Targets list: matches pattern used elsewhere.

includeTotal parameter, signature, and DB count gating look good.

Also applies to: 999-1000, 1039-1040


1068-1071: Identities list uses unified $queries for find/count.

Aligned with DB layer’s automatic filter handling; consistent with other endpoints.

Based on learnings

Also applies to: 1109-1111


898-899: Confirm Audit::countLogsByUser ignores limit/offset.

If it honors limit/offset, returned total would be page size; ensure it computes the unbounded total for the same filters.

Also applies to: 903-904, 971-973

… multiple endpoints for consistency in response handling.
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

♻️ Duplicate comments (2)
app/controllers/api/messaging.php (1)

2877-2879: Fix Subscribers doc: wrong ALLOWED_ATTRIBUTES reference.

Doc string references Providers::ALLOWED_ATTRIBUTES; should be Subscribers::ALLOWED_ATTRIBUTES.

-    ->param('queries', [], new Subscribers(), '... You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true)
+    ->param('queries', [], new Subscribers(), '... You may filter on the following attributes: ' . implode(', ', Subscribers::ALLOWED_ATTRIBUTES), true)
app/controllers/api/users.php (1)

871-876: Use database count instead of array count for accurate totals.

Counting the PHP array $memberships on Line 875 returns the page size when $queries includes limit/offset, not the total count of all memberships. This should use $dbForProject->count() to get the actual total.

Apply this diff:

         $memberships = array_map(function ($membership) use ($dbForProject, $user) {
             $team = $dbForProject->getDocument('teams', $membership->getAttribute('teamId'));
 
             $membership
                 ->setAttribute('teamName', $team->getAttribute('name'))
                 ->setAttribute('userName', $user->getAttribute('name'))
                 ->setAttribute('userEmail', $user->getAttribute('email'));
 
             return $membership;
         }, $dbForProject->find('memberships', $queries));
 
+        $total = $includeTotal ? $dbForProject->count('memberships', $queries, APP_LIMIT_COUNT) : 0;
+
         $response->dynamic(new Document([
             'memberships' => $memberships,
-            'total' => $includeTotal ? count($memberships) : 0,
+            'total' => $total,
         ]), Response::MODEL_MEMBERSHIP_LIST);
🧹 Nitpick comments (10)
src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (1)

106-109: Inconsistent query handling compared to other XList implementations.

This implementation manually extracts filter queries on line 106 and passes $filterQueries to the count operation on line 109, while the find operation on line 108 uses the full $queries array. Other XList implementations in the codebase (e.g., Databases/XList.php, Databases/Collections/Documents/XList.php) pass $queries directly to both find() and count() operations, letting the database layer handle filter separation internally.

Consider aligning with the established pattern by passing $queries directly to the count operation:

-        $filterQueries = Query::groupByType($queries)['filters'];
         try {
             $projects = $dbForPlatform->find('projects', $queries);
-            $total = $includeTotal ? $dbForPlatform->count('projects', $filterQueries, APP_LIMIT_COUNT) : 0;
+            $total = $includeTotal ? $dbForPlatform->count('projects', $queries, APP_LIMIT_COUNT) : 0;
         } catch (Order $e) {

Based on learnings

tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1)

964-981: Use explicit scalar for GET boolean and tidy naming.

http_build_query may serialize false as an empty value. Send 0 (or 'false') to avoid ambiguity, rename the local for clarity, and use \count for consistency.

-        $attributesWithIncludeTotalFalse = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes', array_merge([
+        $attributesWithTotalFalse = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes', array_merge([
             'content-type' => 'application/json',
             'x-appwrite-project' => $this->getProject()['$id'],
             'x-appwrite-key' => $this->getProject()['apiKey']
         ]), [
-            'total' => false
+            'total' => 0
         ]);
 
-        $this->assertEquals(200, $attributesWithIncludeTotalFalse['headers']['status-code']);
-        $this->assertIsArray($attributesWithIncludeTotalFalse['body']);
-        $this->assertIsArray($attributesWithIncludeTotalFalse['body']['attributes']);
-        $this->assertIsInt($attributesWithIncludeTotalFalse['body']['total']);
-        $this->assertEquals(0, $attributesWithIncludeTotalFalse['body']['total']);
-        $this->assertGreaterThan(0, count($attributesWithIncludeTotalFalse['body']['attributes']));
+        $this->assertEquals(200, $attributesWithTotalFalse['headers']['status-code']);
+        $this->assertIsArray($attributesWithTotalFalse['body']);
+        $this->assertIsArray($attributesWithTotalFalse['body']['attributes']);
+        $this->assertIsInt($attributesWithTotalFalse['body']['total']);
+        $this->assertEquals(0, $attributesWithTotalFalse['body']['total']);
+        $this->assertGreaterThan(0, \count($attributesWithTotalFalse['body']['attributes']));
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)

101-104: Use grouped filter queries for count (consistency + safety).

Other endpoints compute filters via Query::groupByType($queries)['filters'] before counting. Align here to avoid selection/order artifacts in count.

Apply:

         try {
             $databases = $dbForProject->find('databases', $queries);
-            $total = $includeTotal ? $dbForProject->count('databases', $queries, APP_LIMIT_COUNT) : 0;
+            $filterQueries = Query::groupByType($queries)['filters'] ?? [];
+            $total = $includeTotal ? $dbForProject->count('databases', $filterQueries, APP_LIMIT_COUNT) : 0;
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)

131-144: Align counts to use grouped filters across all branches.

To mirror other endpoints and avoid selection/order interference, compute filters once and reuse for count.

         try {
             $selectQueries = Query::groupByType($queries)['selections'] ?? [];
             $collectionTableId = 'database_' . $database->getSequence() . '_collection_' . $collection->getSequence();
+            $filterQueries = Query::groupByType($queries)['filters'] ?? [];

             // Use transaction-aware document retrieval if transactionId is provided
             if ($transactionId !== null) {
                 $documents = $transactionState->listDocuments($collectionTableId, $transactionId, $queries);
-                $total = $includeTotal ? $transactionState->countDocuments($collectionTableId, $transactionId, $queries) : 0;
+                $total = $includeTotal ? $transactionState->countDocuments($collectionTableId, $transactionId, $filterQueries) : 0;
             } elseif (! empty($selectQueries)) {
                 // has selects, allow relationship on documents
                 $documents = $dbForProject->find($collectionTableId, $queries);
-                $total = $includeTotal ? $dbForProject->count($collectionTableId, $queries, APP_LIMIT_COUNT) : 0;
+                $total = $includeTotal ? $dbForProject->count($collectionTableId, $filterQueries, APP_LIMIT_COUNT) : 0;
             } else {
                 // has no selects, disable relationship loading on documents
                 /* @type Document[] $documents */
                 $documents = $dbForProject->skipRelationships(fn () => $dbForProject->find($collectionTableId, $queries));
-                $total = $includeTotal ? $dbForProject->count($collectionTableId, $queries, APP_LIMIT_COUNT) : 0;
+                $total = $includeTotal ? $dbForProject->count($collectionTableId, $filterQueries, APP_LIMIT_COUNT) : 0;
             }
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (2)

115-118: Use grouped filters for count (parity with other modules).

Align with other XList handlers by passing only filters to count.

-            $collections = $dbForProject->find('database_' . $database->getSequence(), $queries);
-            $total = $includeTotal ? $dbForProject->count('database_' . $database->getSequence(), $queries, APP_LIMIT_COUNT) : 0;
+            $collections = $dbForProject->find('database_' . $database->getSequence(), $queries);
+            $filterQueries = Query::groupByType($queries)['filters'] ?? [];
+            $total = $includeTotal ? $dbForProject->count('database_' . $database->getSequence(), $filterQueries, APP_LIMIT_COUNT) : 0;

105-110: Rename $collectionIdId for clarity.

Minor nit: $collectionIdId likely meant $collectionId. Rename to avoid confusion.

app/controllers/api/messaging.php (2)

1070-1070: Providers list: includeTotal gating looks correct; consider filter-only count.

Wiring of total param to $includeTotal and conditional count is good. For resilience with cursor/limit/order queries, consider counting on filter-only queries: Query::groupByType($queries)['filters'].

- $total = $includeTotal ? $dbForProject->count('providers', $queries, APP_LIMIT_COUNT) : 0;
+ $filters = Query::groupByType($queries)['filters'];
+ $total = $includeTotal ? $dbForProject->count('providers', $filters, APP_LIMIT_COUNT) : 0;

Also applies to: 1073-1073, 1109-1116


3700-3701: Messages list: includeTotal gating OK; consider filter-only count.

Same suggestion as providers list to count on filters only.

- $total = $includeTotal ? $dbForProject->count('messages', $queries, APP_LIMIT_COUNT) : 0;
+ $filters = Query::groupByType($queries)['filters'];
+ $total = $includeTotal ? $dbForProject->count('messages', $filters, APP_LIMIT_COUNT) : 0;

Also applies to: 3703-3704, 3739-3746

app/controllers/api/teams.php (2)

213-216: Consider using $queries directly for count for consistency.

The manual filter separation on Line 213 and subsequent use of $filterQueries for count on Line 216 may be unnecessary. Based on learnings, the database layer internally handles filter separation for count operations in version 0.77.* and later. Other list endpoints (e.g., users at lines 651-654, and databases in XList.php) use $queries directly for both find and count operations.

Consider applying this diff for consistency:

-        $filterQueries = Query::groupByType($queries)['filters'];
         try {
             $results = $dbForProject->find('teams', $queries);
-            $total = $includeTotal ? $dbForProject->count('teams', $filterQueries, APP_LIMIT_COUNT) : 0;
+            $total = $includeTotal ? $dbForProject->count('teams', $queries, APP_LIMIT_COUNT) : 0;
         } catch (OrderException $e) {

Based on learnings.


893-903: Consider using $queries directly for count for consistency.

Similar to the teams list endpoint, manual filter separation on Line 893 may be unnecessary. For consistency with other endpoints and to align with the database layer's automatic filter handling (v0.77.x+), consider using $queries directly for both find and count operations.

Apply this diff:

-        $filterQueries = Query::groupByType($queries)['filters'];
         try {
             $memberships = $dbForProject->find(
                 collection: 'memberships',
                 queries: $queries,
             );
-            $total = $includeTotal ? $dbForProject->count(
-                collection: 'memberships',
-                queries: $filterQueries,
-                max: APP_LIMIT_COUNT
-            ) : 0;
+            $total = $includeTotal ? $dbForProject->count(
+                collection: 'memberships',
+                queries: $queries,
+                max: APP_LIMIT_COUNT
+            ) : 0;
         } catch (OrderException $e) {

Based on learnings.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3300013 and a7dbb3d.

📒 Files selected for processing (38)
  • app/controllers/api/account.php (4 hunks)
  • app/controllers/api/messaging.php (18 hunks)
  • app/controllers/api/migrations.php (2 hunks)
  • app/controllers/api/projects.php (6 hunks)
  • app/controllers/api/storage.php (4 hunks)
  • app/controllers/api/teams.php (7 hunks)
  • app/controllers/api/users.php (12 hunks)
  • app/controllers/api/vcs.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/XList.php (2 hunks)
  • src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Functions/Http/Templates/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Proxy/Http/Rules/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php (4 hunks)
  • src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php (3 hunks)
  • src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php (3 hunks)
  • tests/e2e/Services/Account/AccountCustomClientTest.php (1 hunks)
  • tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1 hunks)
  • tests/e2e/Services/Databases/Legacy/DatabasesCustomServerTest.php (3 hunks)
  • tests/e2e/Services/Databases/TablesDB/DatabasesCustomServerTest.php (1 hunks)
  • tests/e2e/Services/Functions/FunctionsCustomClientTest.php (1 hunks)
  • tests/e2e/Services/Functions/FunctionsCustomServerTest.php (2 hunks)
  • tests/e2e/Services/Messaging/MessagingBase.php (1 hunks)
  • tests/e2e/Services/Storage/StorageBase.php (1 hunks)
  • tests/e2e/Services/Teams/TeamsBase.php (1 hunks)
  • tests/e2e/Services/Users/UsersBase.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (20)
  • tests/e2e/Services/Databases/Legacy/DatabasesCustomServerTest.php
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/XList.php
  • src/Appwrite/Platform/Modules/Functions/Http/Functions/XList.php
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/XList.php
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/XList.php
  • tests/e2e/Services/Databases/TablesDB/DatabasesCustomServerTest.php
  • tests/e2e/Services/Functions/FunctionsCustomServerTest.php
  • tests/e2e/Services/Teams/TeamsBase.php
  • src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php
  • src/Appwrite/Platform/Modules/Functions/Http/Templates/XList.php
  • src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php
  • tests/e2e/Services/Account/AccountCustomClientTest.php
  • src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/XList.php
  • src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php
  • tests/e2e/Services/Users/UsersBase.php
  • tests/e2e/Services/Storage/StorageBase.php
  • app/controllers/api/vcs.php
  • src/Appwrite/Platform/Modules/Proxy/Http/Rules/XList.php
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Indexes/XList.php
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-11T10:32:38.142Z
Learnt from: abnegate
PR: appwrite/appwrite#10297
File: app/controllers/api/users.php:649-657
Timestamp: 2025-08-11T10:32:38.142Z
Learning: In Appwrite's utopia-php/database (version 0.77.* and later), the database layer internally handles filter separation for count operations. When using `$dbForProject->count()` within a `skipFilters` closure, there's no need to manually separate filter queries using `Query::groupByType($queries)['filters']` as the database handles this automatically.

Applied to files:

  • src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php
  • app/controllers/api/teams.php
  • app/controllers/api/users.php
  • app/controllers/api/storage.php
  • app/controllers/api/migrations.php
📚 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/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php
  • src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php
🧬 Code graph analysis (18)
tests/e2e/Services/Functions/FunctionsCustomClientTest.php (1)
tests/e2e/Client.php (2)
  • call (181-302)
  • Client (8-342)
src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php (3)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/XList.php (1)
  • action (68-136)
src/Appwrite/Platform/Modules/Sites/Http/Logs/XList.php (1)
  • action (65-121)
tests/e2e/Services/Messaging/MessagingBase.php (1)
tests/e2e/Client.php (1)
  • Client (8-342)
src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (3)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)
  • action (68-114)
app/controllers/api/messaging.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)
  • action (68-114)
tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1)
tests/e2e/Client.php (1)
  • Client (8-342)
app/controllers/api/account.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (1)
  • action (73-128)
app/controllers/api/teams.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)
  • action (68-114)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/XList.php (3)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
app/controllers/api/users.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
app/controllers/api/storage.php (3)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)
  • action (68-114)
app/controllers/api/projects.php (2)
src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (1)
  • action (69-117)
src/Appwrite/Utopia/Response.php (1)
  • Response (158-980)
app/controllers/api/migrations.php (3)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (1)
  • action (79-176)
src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)
  • action (68-114)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php (2)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/XList.php (1)
  • action (70-148)
src/Appwrite/Databases/TransactionState.php (2)
  • TransactionState (20-745)
  • countDocuments (156-210)
src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
  • param (255-356)
⏰ 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). (16)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Webhooks)
  • GitHub Check: E2E Service Test (Locale)
  • GitHub Check: E2E Service Test (Tokens)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (VCS)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (Functions)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (Account)
  • 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: scan
🔇 Additional comments (35)
src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/XList.php (2)

14-14: LGTM: Import correctly ordered.

The Boolean validator import is properly positioned in alphabetical order between ArrayList and Text, satisfying PSR-12.


56-56: Code changes verified—parameter declaration and consumption pattern is correct and consistent.

The verification confirms both concerns from the original comment:

  1. Boolean validator pattern: The new Boolean(true) instantiation is standard and consistently used across 50+ parameter declarations throughout the codebase for controlling list result totals. This is the established pattern in this codebase.

  2. Parameter consumption: The total parameter will be automatically mapped to the bool $includeTotal parameter in the action method by the framework. This convention is verified across identical implementations in Tokens, Sites, Functions, and Databases modules, where the value controls conditional total-count computation ($total = $includeTotal ? $db->count(...) : 0).

No issues found. The implementation follows established conventions and is consistent with the codebase patterns.

src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (1)

63-63: Remove the concern about Boolean(true) — the constructor accepts a bool parameter.

The Utopia\Validator\Boolean class constructor accepts an optional bool $loose parameter (default false). Passing true enables "loose" validation that accepts string representations like 'true'/'false' and integers 0/1, which is appropriate for query string parameters. The usage new Boolean(true) is valid and intentional, not an error.

Likely an incorrect or invalid review comment.

tests/e2e/Services/Functions/FunctionsCustomClientTest.php (1)

379-395: LGTM! Clean test implementation for total=false behavior.

The test properly validates the new includeTotal=false functionality by confirming:

  • HTTP 200 response
  • Response structure integrity
  • total field is 0 when total=false
  • Templates array is still populated

The assertions are comprehensive and the test follows the established pattern in this file.

tests/e2e/Services/Messaging/MessagingBase.php (1)

647-664: LGTM! Consistent test implementation for subscribers endpoint.

The test correctly validates the total=false behavior with comprehensive assertions:

  • HTTP 200 response
  • Response structure validation
  • Type checking for total field
  • Confirms total equals 0
  • Verifies subscribers array remains populated

The implementation is consistent with the pattern used in FunctionsCustomClientTest.php, ensuring uniformity across the test suite.

tests/e2e/Services/Databases/Legacy/DatabasesBase.php (1)

964-981: Public query param is "total" — original concern is incorrect.

Routes declare the public query parameter as 'total' (->param('total', ...); e.g. app/controllers/api/*.php) and tests pass 'total' => false; $includeTotal is only the internal handler variable name. No change required.

Likely an incorrect or invalid review comment.

src/Appwrite/Platform/Modules/Sites/Http/Sites/XList.php (2)

103-106: LGTM: count gating behind includeTotal is correct and consistent.

Using filters for count and skipping it when includeTotal is false looks good and avoids unnecessary DB work.


58-65: No internal codebase issues found; manual verification of SDKs and GraphQL required.

The PHP codebase is internally consistent: all 50+ list endpoints uniformly expose the public param as 'total' while accepting it as method arg $includeTotal. No legacy includeTotal public params remain. However, verification of SDK implementations, GraphQL schema mapping, and changelog documentation cannot be completed from codebase inspection alone and requires manual review.

src/Appwrite/Platform/Modules/Databases/Http/Databases/XList.php (1)

62-69: LGTM on the new “total” param and signature wire-up.

Defaults, Boolean(true) for loose parsing, and arg positioning are correct.

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

71-80: LGTM on new param and signature; gating is correct.

Transaction-aware listing and stats are preserved; total is skipped when false.

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

67-74: LGTM on param wiring and signature change.

Boolean(true) for query parsing and arg ordering look correct.

src/Appwrite/Platform/Modules/Functions/Http/Executions/XList.php (2)

119-129: LGTM: correct use of filters for count and gating.

Matches the intended behavior and avoids unnecessary counting when disabled.


58-70: Manual verification required for downstream SDK/GraphQL parameter exposure.

The parameter naming pattern (->param('total', ...) with bool $includeTotal in the function signature) is consistent with all other list endpoints in the codebase (Databases, Storage, Teams, Users, Functions, Sites, etc.). However, SDK and GraphQL schema definitions are generated at build time and cannot be verified through source inspection. Confirm that the "total" parameter name is correctly exposed in downstream SDK clients and GraphQL schema, and that documentation reflects this consistently.

src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php (4)

22-22: LGTM - Boolean validator import added correctly.

The import is properly placed and necessary for the new parameter validation.


61-61: LGTM - Parameter declaration is correct and well-documented.

The total parameter provides a clean API to control total count calculation, with sensible defaults for backward compatibility.


68-76: LGTM - Action signature properly updated.

The includeTotal parameter is correctly typed and positioned in the method signature, maintaining good parameter organization.


122-129: LGTM - Conditional total calculation implemented correctly.

The ternary operator elegantly gates the count query based on includeTotal, providing the performance optimization intended by this feature. Filter extraction and count operation follow established patterns.

app/controllers/api/migrations.php (3)

598-600: LGTM - Parameter declaration follows established pattern.

The total parameter is correctly defined with appropriate validation and documentation.


603-603: LGTM - Action signature properly updated.

The includeTotal parameter is correctly integrated into the endpoint's parameter list.


639-645: LGTM - Conditional count logic implemented correctly.

The implementation efficiently skips the count query when not needed, following the same pattern as other endpoints in this PR.

app/controllers/api/storage.php (6)

181-183: LGTM - Parameter declaration is correct.

The total parameter follows the established pattern with proper validation and documentation.


186-186: LGTM - Action signature properly updated.

The includeTotal parameter is correctly added to the listBuckets endpoint signature.


223-231: LGTM - Conditional count logic correctly implemented.

The listBuckets endpoint properly gates the count query based on includeTotal, maintaining consistency with the broader pattern.


787-789: LGTM - Parameter declaration follows the pattern.

The total parameter is correctly defined for the listFiles endpoint.


793-793: LGTM - Action signature updated correctly.

The includeTotal parameter is properly integrated into the listFiles endpoint.


846-862: LGTM - Both authorization branches handle includeTotal correctly.

The implementation properly gates the count query in both the file-security-enabled and bucket-level-permission branches. The Authorization::skip() wrapping in the else branch correctly mirrors the find() operation's authorization handling.

app/controllers/api/account.php (2)

2817-2868: LGTM! The total parameter implementation is correct.

The changes correctly implement the feature to disable total count calculation:

  • Public API parameter named total (line 2817) with default true for backward compatibility
  • Internal parameter $includeTotal properly passed to action (line 2823)
  • Count query correctly skipped when $includeTotal is false (line 2868): $includeTotal ? $audit->countLogsByUser(...) : 0

This implementation matches the PR objectives and follows the established pattern from other endpoints.


5215-5260: LGTM! The total parameter implementation is correct.

The changes correctly implement the feature to disable total count calculation:

  • Public API parameter named total (line 5215) with default true for backward compatibility
  • Internal parameter $includeTotal properly passed to action (line 5219)
  • Count query correctly skipped when $includeTotal is false (line 5260): $includeTotal ? $dbForProject->count(...) : 0

The implementation is consistent with the logs endpoint and follows the established pattern across the codebase.

app/controllers/api/messaging.php (6)

1139-1140: Provider logs: conditional total OK.

$includeTotal ? $audit->countLogsByResource(...) : 0 is correct and avoids unnecessary work when false.

Also applies to: 1144-1145, 1212-1214


2546-2547: Topic logs: includeTotal gating LGTM.

Also applies to: 2551-2552, 2620-2621


2880-2881: Subscribers list: includeTotal gating OK.

Logic and response shape look consistent.

Also applies to: 2883-2884, 2944-2946


2970-2970: Subscriber logs: conditional total OK.

Also applies to: 2974-2975, 3043-3045


3769-3770: Message logs: conditional total OK.

Also applies to: 3774-3775, 3843-3845


3868-3869: Message targets list: includeTotal gating OK; empty-target fast path is fine.

Also applies to: 3871-3872, 3921-3923

app/controllers/api/projects.php (1)

1237-1237: Projects lists (webhooks/keys/platforms): includeTotal gating LGTM and efficient.

  • Using count($items) avoids a second DB hit and matches the contract when total=false.
  • Param wiring and signatures are consistent.

Also applies to: 1240-1241, 1255-1256, 1535-1535, 1538-1539, 1553-1554, 1840-1840, 1842-1843, 1857-1858

Comment on lines +2477 to 2481
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
->inject('dbForProject')
->inject('response')
->action(function (array $queries, string $search, Database $dbForProject, Response $response) {
->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) {
try {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix cursor assignment in topics list (breaks pagination).

$dbForProject->getDocument() returns a Document, not an array. Using $cursorDocument[0] causes a runtime error and broken pagination. Keep the includeTotal change as-is.

-            $cursor->setValue($cursorDocument[0]);
+            $cursor->setValue($cursorDocument);

Also applies to: 2505-2513, 2516-2516

🤖 Prompt for AI Agents
In app/controllers/api/messaging.php around lines 2477-2481 (and also at
2505-2513 and 2516), the code treats the result of $dbForProject->getDocument()
as an array and uses $cursorDocument[0], which is incorrect because
getDocument() returns a Document object and this breaks pagination; update the
assignment to extract the cursor from the Document using the Document API (e.g.,
call the appropriate getter or property accessor on the Document to read the
cursor field) instead of indexing into it, and ensure the rest of the pagination
logic uses that extracted scalar cursor value.

@abnegate abnegate merged commit 7b55a98 into 1.8.x Oct 29, 2025
41 checks passed
@abnegate abnegate deleted the feat-disable-count branch October 29, 2025 10:47
@coderabbitai coderabbitai bot mentioned this pull request Oct 29, 2025
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants