Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@abnegate
Copy link
Member

@abnegate abnegate commented Nov 3, 2025

This PR contains updates to the Android SDK for version 11.3.0.

Summary by CodeRabbit

Release Notes - Version 11.3.0

  • New Features
    • Added optional total parameter to list operations across Account, Databases, Functions, Storage, Teams, and TablesDb services to skip row counting for improved performance.
    • Introduced Operator class for atomic row modifications, supporting increment, decrement, multiply, divide, modulo, power, array, string, and date operations.
    • Added SCHEDULED execution status for function executions.

@coderabbitai
Copy link

coderabbitai bot commented Nov 3, 2025

Walkthrough

This pull request releases version 11.3.0 of the Appwrite Android SDK. The changes introduce a new total optional parameter to multiple list query methods across Account, Databases, Functions, Storage, TablesDb, and Teams services to allow skipping row count calculations for performance optimization. A new Operator class with factory methods for atomic row modifications (increment, decrement, multiply, array operations, etc.) is added. The ExecutionStatus enum gains a new SCHEDULED state. Query helper methods for date filtering are refactored to use internal helper functions. Documentation and examples across Java and Kotlin are updated to reflect these new parameters and to use typed Permission/Role objects instead of string literals. The SDK version header is incremented to 11.3.0 throughout.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Operator.kt (new file): Comprehensive new class with DSL and 18+ factory methods requiring validation of input constraints (NaN/Infinity checks, divisor validation) and JSON serialization logic
  • Query.kt refactoring: Logic changes for date filter implementations using helper functions instead of direct Query object construction need careful verification
  • Service method additions (Account, Databases, Functions, Storage, TablesDb, Teams): Repetitive total parameter additions across ~8 files with consistent patterns, reducing per-file review complexity but requiring verification across all call sites
  • ExecutionStatus.kt: New enum constant SCHEDULED addition is straightforward but should verify no serialization conflicts
  • Documentation consistency: 30+ example files updated with Permission/Role typing and total parameters; verify consistency across Java and Kotlin examples

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title Check ❓ Inconclusive The PR title "feat: Android SDK update for version 11.3.0" references a real aspect of the changeset—the version bump to 11.3.0—but it is overly generic and vague in its description of the actual changes. The title emphasizes the version number while omitting the substantive feature additions documented in CHANGELOG.md: the new total parameter for list queries (to skip row counting for performance) and the new Operator class for atomic row modifications. The word "update" is non-descriptive and doesn't convey what functional changes were made, making it difficult for someone scanning history to understand the primary improvements delivered in this release. Consider revising the title to be more specific about the main features being added, such as "feat: Add total parameter for query optimization and Operator class for atomic updates" or "feat: Release v11.3.0 with list query performance improvements and atomic modification support". This would help reviewers and future developers quickly understand the key value delivered by this changeset.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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 dev

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.

Copy link

@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: 9

Caution

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

⚠️ Outside diff range comments (1)
docs/examples/java/databases/create-document.md (1)

17-22: Critical: Kotlin syntax in Java example.

The mapOf() function is Kotlin syntax and will not compile in Java. Java examples should use standard Java map construction. Replace with Java syntax like Map.of() (Java 9+) or new HashMap<>() / new LinkedHashMap<>().

Apply this diff to fix the syntax:

    databases.createDocument(
        "<DATABASE_ID>", // databaseId 
        "<COLLECTION_ID>", // collectionId 
        "<DOCUMENT_ID>", // documentId 
-        mapOf(
+        Map.of(
            "username" to "walter.obrien",
            "email" to "[email protected]",
            "fullName" to "Walter O'Brien",
            "age" to 30,
            "isAdmin" to false
-        ), // data
+        ), // data

Also replace the to operator with proper Java map entry syntax:

-        Map.of(
+        Map.ofEntries(
-            "username" to "walter.obrien",
+            Map.entry("username", "walter.obrien"),
-            "email" to "[email protected]",
+            Map.entry("email", "[email protected]"),
-            "fullName" to "Walter O'Brien",
+            Map.entry("fullName", "Walter O'Brien"),
-            "age" to 30,
+            Map.entry("age", 30),
-            "isAdmin" to false
+            Map.entry("isAdmin", false)
-        ), // data
+        ), // data
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa10b91 and 9668122.

📒 Files selected for processing (45)
  • CHANGELOG.md (1 hunks)
  • README.md (2 hunks)
  • docs/examples/java/account/list-identities.md (1 hunks)
  • docs/examples/java/account/list-logs.md (1 hunks)
  • docs/examples/java/databases/create-document.md (2 hunks)
  • docs/examples/java/databases/list-documents.md (1 hunks)
  • docs/examples/java/databases/update-document.md (2 hunks)
  • docs/examples/java/databases/upsert-document.md (2 hunks)
  • docs/examples/java/functions/list-executions.md (1 hunks)
  • docs/examples/java/storage/create-file.md (2 hunks)
  • docs/examples/java/storage/list-files.md (1 hunks)
  • docs/examples/java/storage/update-file.md (2 hunks)
  • docs/examples/java/tablesdb/create-row.md (2 hunks)
  • docs/examples/java/tablesdb/list-rows.md (1 hunks)
  • docs/examples/java/tablesdb/update-row.md (2 hunks)
  • docs/examples/java/tablesdb/upsert-row.md (2 hunks)
  • docs/examples/java/teams/list-memberships.md (1 hunks)
  • docs/examples/java/teams/list.md (1 hunks)
  • docs/examples/kotlin/account/list-identities.md (1 hunks)
  • docs/examples/kotlin/account/list-logs.md (1 hunks)
  • docs/examples/kotlin/databases/create-document.md (2 hunks)
  • docs/examples/kotlin/databases/list-documents.md (1 hunks)
  • docs/examples/kotlin/databases/update-document.md (2 hunks)
  • docs/examples/kotlin/databases/upsert-document.md (2 hunks)
  • docs/examples/kotlin/functions/list-executions.md (1 hunks)
  • docs/examples/kotlin/storage/create-file.md (2 hunks)
  • docs/examples/kotlin/storage/list-files.md (1 hunks)
  • docs/examples/kotlin/storage/update-file.md (2 hunks)
  • docs/examples/kotlin/tablesdb/create-row.md (2 hunks)
  • docs/examples/kotlin/tablesdb/list-rows.md (1 hunks)
  • docs/examples/kotlin/tablesdb/update-row.md (2 hunks)
  • docs/examples/kotlin/tablesdb/upsert-row.md (2 hunks)
  • docs/examples/kotlin/teams/list-memberships.md (1 hunks)
  • docs/examples/kotlin/teams/list.md (1 hunks)
  • library/src/main/java/io/appwrite/Client.kt (1 hunks)
  • library/src/main/java/io/appwrite/Operator.kt (1 hunks)
  • library/src/main/java/io/appwrite/Query.kt (3 hunks)
  • library/src/main/java/io/appwrite/enums/ExecutionStatus.kt (1 hunks)
  • library/src/main/java/io/appwrite/models/Execution.kt (1 hunks)
  • library/src/main/java/io/appwrite/services/Account.kt (2 hunks)
  • library/src/main/java/io/appwrite/services/Databases.kt (5 hunks)
  • library/src/main/java/io/appwrite/services/Functions.kt (1 hunks)
  • library/src/main/java/io/appwrite/services/Storage.kt (1 hunks)
  • library/src/main/java/io/appwrite/services/TablesDb.kt (5 hunks)
  • library/src/main/java/io/appwrite/services/Teams.kt (3 hunks)
🔇 Additional comments (35)
docs/examples/kotlin/teams/list.md (1)

14-14: LGTM!

The new total parameter has been correctly added as an optional parameter with proper Kotlin named-argument syntax. Setting it to false aligns with the PR objective to optimize performance by skipping row count calculations. The inline comment clearly indicates this parameter is optional.

docs/examples/kotlin/account/list-logs.md (1)

13-13: ✓ Documentation update looks good.

The new total parameter is correctly added with proper Kotlin named-argument syntax and an appropriate default value (false) that demonstrates the performance optimization intent. The inline comment correctly marks it as optional.

library/src/main/java/io/appwrite/enums/ExecutionStatus.kt (1)

13-15: LGTM! New SCHEDULED status added correctly.

The new enum constant follows the same pattern as existing values and is properly annotated for JSON serialization. The syntax is correct with the comma after FAILED and semicolon terminator after SCHEDULED.

library/src/main/java/io/appwrite/models/Execution.kt (1)

55-55: LGTM! Documentation updated to reflect new status.

The KDoc now correctly documents all possible execution status values, including the newly added "scheduled" state. This change is consistent with the ExecutionStatus enum update.

library/src/main/java/io/appwrite/Query.kt (1)

254-296: LGTM! Clean refactor that improves maintainability.

The date-filter methods now delegate to existing helper functions (lessThan, greaterThan, between) rather than duplicating query construction logic. This follows the DRY principle and makes the code easier to maintain. The behavior is preserved, and the special Appwrite attributes ($createdAt, $updatedAt) are correctly referenced.

docs/examples/java/teams/list.md (1)

14-14: LGTM!

The new total parameter is correctly documented and demonstrates the performance optimization feature mentioned in the changelog. Setting it to false in the example is a good choice as it shows the performance-optimized usage.

docs/examples/java/tablesdb/update-row.md (1)

4-5: Excellent type safety improvement!

The refactor from string-based permissions to typed Permission.read(Role.any()) objects provides compile-time safety and better IDE support. This prevents runtime errors from malformed permission strings.

Also applies to: 18-18

library/src/main/java/io/appwrite/Client.kt (1)

90-90: LGTM!

SDK version header correctly updated to 11.3.0, consistent with the version bump across the codebase.

README.md (1)

41-41: LGTM!

Dependency versions correctly updated to 11.3.0 for both Gradle and Maven, consistent with the release version.

Also applies to: 52-52

CHANGELOG.md (1)

3-7: LGTM!

The changelog entry properly documents the new features in version 11.3.0. The total parameter addition is clearly described and aligns with the performance optimization changes seen throughout the codebase.

docs/examples/kotlin/databases/upsert-document.md (1)

4-5: LGTM!

The typed permission objects provide compile-time safety and better developer experience. The implementation is consistent with the Java examples and follows proper Kotlin conventions.

Also applies to: 18-18

library/src/main/java/io/appwrite/services/Storage.kt (1)

25-25: Well-implemented performance optimization!

The new total parameter is properly implemented with:

  • Clear documentation explaining the performance benefit
  • Optional nullable type (Boolean?) with null default for backward compatibility
  • Correct propagation to the API parameters map
  • @JvmOverloads annotation ensures Java interoperability

Also applies to: 33-33, 41-41

library/src/main/java/io/appwrite/services/Account.kt (1)

186-186: Consistently implemented across both methods!

The total parameter is properly added to both listIdentities and listLogs methods with:

  • Consistent documentation and implementation pattern
  • Optional nullable type for backward compatibility
  • Correct API parameter propagation
  • @JvmOverloads annotation for Java interoperability

The implementation matches the pattern in Storage.kt and other services.

Also applies to: 192-192, 198-198, 277-277, 283-283, 289-289

docs/examples/kotlin/tablesdb/list-rows.md (1)

16-16: LGTM!

The addition of the optional total parameter is correctly placed and syntactically sound. This aligns with the PR's API changes to add performance optimization controls.

docs/examples/kotlin/tablesdb/update-row.md (1)

4-5: LGTM!

The imports for Permission and Role are correctly added, and the use of typed permission objects (Permission.read(Role.any())) is the proper pattern. This improves type safety over string-based permissions.

Also applies to: 18-18

docs/examples/java/databases/create-document.md (1)

4-5: LGTM on permission objects.

The imports and use of typed Permission/Role objects are correct for Java. The pattern is consistent with the PR's modernization goals.

Also applies to: 24-24

docs/examples/kotlin/account/list-identities.md (1)

13-13: LGTM!

The optional total parameter is correctly added to the listIdentities call. This matches the API changes and provides users with performance optimization control.

docs/examples/java/databases/list-documents.md (1)

16-16: LGTM on parameter.

The addition of the total parameter is correctly positioned and follows the API changes.

docs/examples/java/storage/create-file.md (1)

5-6: LGTM on permission objects.

The imports for Permission and Role and the use of typed permission objects are correct and follow the pattern established in the PR.

docs/examples/kotlin/tablesdb/upsert-row.md (1)

4-5: LGTM!

The imports and use of typed permission objects are correct for Kotlin. This follows the PR's pattern of modernizing permission handling.

Also applies to: 18-18

docs/examples/kotlin/storage/update-file.md (1)

4-5: LGTM!

The imports and use of typed permission objects are correctly implemented for Kotlin, consistent with the PR's modernization of permission handling patterns.

Also applies to: 17-17

docs/examples/kotlin/databases/list-documents.md (1)

16-16: LGTM!

The total parameter is correctly added using Kotlin named parameter syntax and aligns with the 11.3.0 API changes.

docs/examples/kotlin/storage/list-files.md (1)

15-15: LGTM!

The total parameter addition uses correct Kotlin named parameter syntax.

docs/examples/kotlin/databases/update-document.md (1)

4-5: LGTM!

Permission and Role imports are correctly added, and the typed permission usage Permission.read(Role.any()) is idiomatic Kotlin and aligns with the PR's shift to typed permissions.

Also applies to: 18-18

docs/examples/kotlin/functions/list-executions.md (1)

14-14: API parameter addition is correctly reflected. The new total parameter is properly added with idiomatic Kotlin named syntax and clear documentation.

docs/examples/java/databases/upsert-document.md (1)

4-5: Permissions correctly typed and imports added. Transitioning from string-based permissions to typed Permission and Role objects improves type safety and IDE support. All necessary imports are in place.

Also applies to: 18-18

docs/examples/kotlin/tablesdb/create-row.md (1)

4-5: Permissions correctly updated to typed syntax. Import statements are properly added and the permission construction is idiomatic Kotlin. Example remains clear and correct.

Also applies to: 24-24

docs/examples/java/tablesdb/upsert-row.md (1)

4-5: Permissions correctly typed with necessary imports. The change to Permission.read(Role.any()) is consistent across all similar examples and provides type safety benefits.

Also applies to: 18-18

docs/examples/kotlin/storage/create-file.md (1)

5-6: Permissions API usage correctly updated. New imports are properly positioned and typed permission construction is consistent with other Kotlin examples in the PR.

Also applies to: 18-18

docs/examples/kotlin/databases/create-document.md (1)

4-5: Permission typing correctly applied. Imports are properly added and the syntax is consistent with other document creation examples in both Kotlin and Java.

Also applies to: 24-24

docs/examples/java/account/list-logs.md (1)

13-13: New API parameter correctly added. The total parameter is properly positioned in the method call and documented inline, consistent with other list method examples.

docs/examples/java/tablesdb/list-rows.md (1)

16-16: API parameter addition is correct and consistently applied. The total parameter is properly positioned in the method signature and documented, matching the pattern across all list methods in the PR.

library/src/main/java/io/appwrite/services/Functions.kt (1)

22-36: LGTM! Clean implementation of the total parameter.

The optional total parameter is properly implemented with:

  • Clear KDoc documentation explaining its purpose
  • Nullable Boolean type with sensible default (null)
  • Correct forwarding to API parameters
  • Backward compatibility via @JvmOverloads for Java callers
library/src/main/java/io/appwrite/services/Databases.kt (2)

222-245: LGTM! Consistent implementation across overloads.

The total parameter is properly added to the generic listDocuments method with correct KDoc, type signature, and API parameter mapping. The implementation maintains consistency with other services in this PR.


270-292: LGTM! Proper parameter delegation.

The non-generic overload correctly forwards the total parameter to the generic implementation. Good practice to maintain consistency even for deprecated methods.

Account account = new Account(client);

account.listIdentities(
listOf(), // queries (optional)
Copy link

@coderabbitai coderabbitai bot Nov 3, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix Kotlin syntax in Java example: listOf() is not available.

Line 12 uses listOf(), which is a Kotlin stdlib function and will not compile in Java code.

Apply this diff to fix the Java syntax:

  account.listIdentities(
-     listOf(), // queries (optional)
+     Arrays.asList(), // queries (optional)
      false, // total (optional)

Alternatively, if targeting Java 9+:

-     listOf(), // queries (optional)
+     List.of(), // queries (optional)

Add the import if using Arrays.asList():

import java.util.Arrays;
🤖 Prompt for AI Agents
In docs/examples/java/account/list-identities.md around line 12, the Java
example incorrectly uses Kotlin's listOf(); replace it with a Java-compatible
expression such as Collections.emptyList() or, for Java 9+, List.of(), or
Arrays.asList(...) if you need elements. If you choose Arrays.asList(), add the
import java.util.Arrays; if you use Collections.emptyList() or List.of(), ensure
the appropriate java.util imports (java.util.Collections or java.util.List) are
present.

Copy link
Member

Choose a reason for hiding this comment

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

seems like a legit comment @abnegate

Copy link
Member

Choose a reason for hiding this comment

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

not a blocker for release rn, but maybe need a backlog task

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

databases.listDocuments(
"<DATABASE_ID>", // databaseId
"<COLLECTION_ID>", // collectionId
listOf(), // queries (optional)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Kotlin syntax in Java example.

The listOf() function is Kotlin syntax and will not compile in Java. Replace with Java syntax like List.of() (Java 9+) or Arrays.asList() for compatibility.

Apply this diff:

    databases.listDocuments(
        "<DATABASE_ID>", // databaseId 
        "<COLLECTION_ID>", // collectionId 
-        listOf(), // queries (optional)
+        List.of(), // queries (optional)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
listOf(), // queries (optional)
List.of(), // queries (optional)
🤖 Prompt for AI Agents
In docs/examples/java/databases/list-documents.md around line 14, the example
uses Kotlin's listOf(), which is invalid in Java; replace it with
Java-compatible syntax such as List.of(...) (Java 9+) or Arrays.asList(...) and
ensure the example imports or references java.util.List/Arrays appropriately so
the code compiles in Java.

Comment on lines 17 to +18
mapOf( "a" to "b" ), // data (optional)
listOf("read("any")"), // permissions (optional)
listOf(Permission.read(Role.any())), // permissions (optional)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix Kotlin syntax in Java example: mapOf() with to operator and listOf() are not available in Java.

Lines 17–18 use Kotlin-specific constructs that will not compile in Java:

  • mapOf("a" to "b") uses Kotlin's mapOf() function and to infix operator
  • listOf(...) is a Kotlin stdlib function

Apply this diff to fix the Java syntax:

  databases.updateDocument(
      "<DATABASE_ID>", // databaseId 
      "<COLLECTION_ID>", // collectionId 
      "<DOCUMENT_ID>", // documentId 
-     mapOf( "a" to "b" ), // data (optional)
+     new HashMap<String, Object>() {{ put("a", "b"); }}, // data (optional)
-     listOf(Permission.read(Role.any())), // permissions (optional)
+     Arrays.asList(Permission.read(Role.any())), // permissions (optional)
      "<TRANSACTION_ID>", // transactionId (optional)

Alternatively, if targeting Java 9+:

-     mapOf( "a" to "b" ), // data (optional)
+     Map.of("a", "b"), // data (optional)
-     listOf(Permission.read(Role.any())), // permissions (optional)
+     List.of(Permission.read(Role.any())), // permissions (optional)

Add the imports:

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
🤖 Prompt for AI Agents
In docs/examples/java/databases/update-document.md around lines 17–18, the
snippet uses Kotlin-only constructs (mapOf("a" to "b") and listOf(...)) which
won't compile in Java; replace them with Java equivalents such as creating a Map
(e.g., new HashMap<>() and put("a","b") or Map.of("a","b") for Java 9+) and
creating a List (e.g., Arrays.asList(...) or List.of(...) for Java 9+), and add
the corresponding imports (java.util.Map, java.util.HashMap or java.util.Map.of,
java.util.Arrays or java.util.List.of) as needed so the example compiles in
Java.


functions.listExecutions(
"<FUNCTION_ID>", // functionId
listOf(), // queries (optional)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix Kotlin syntax in Java example.

The example uses listOf(), which is a Kotlin function and won't compile in Java code.

Replace with valid Java syntax:

-    listOf(), // queries (optional)
+    Arrays.asList(), // queries (optional)

Or alternatively:

-    listOf(), // queries (optional)
+    Collections.emptyList(), // queries (optional)

You'll also need to add the appropriate import:

import java.util.Arrays;
// or
import java.util.Collections;
🤖 Prompt for AI Agents
In docs/examples/java/functions/list-executions.md around line 13, the snippet
uses the Kotlin-only call `listOf()` which will not compile in Java; replace it
with a Java equivalent such as Arrays.asList(...) for a populated list or
Collections.emptyList() for an empty list and add the corresponding import
statement (import java.util.Arrays; or import java.util.Collections;) at the top
of the Java example.

"<FILE_ID>", // fileId
InputFile.fromPath("file.png"), // file
listOf("read("any")"), // permissions (optional)
listOf(Permission.read(Role.any())), // permissions (optional)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Kotlin syntax in Java example.

The listOf() function is Kotlin syntax and will not compile in Java. Replace with List.of() (Java 9+) or Arrays.asList().

Apply this diff:

    storage.createFile(
        "<BUCKET_ID>", // bucketId 
        "<FILE_ID>", // fileId 
        InputFile.fromPath("file.png"), // file 
-        listOf(Permission.read(Role.any())), // permissions (optional)
+        List.of(Permission.read(Role.any())), // permissions (optional)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
listOf(Permission.read(Role.any())), // permissions (optional)
List.of(Permission.read(Role.any())), // permissions (optional)
🤖 Prompt for AI Agents
In docs/examples/java/storage/create-file.md around line 18, the example uses
Kotlin's listOf() which won't compile in Java; replace it with a Java collection
factory such as List.of(Permission.read(Role.any())) (Java 9+) or
Arrays.asList(Permission.read(Role.any()))) and ensure the corresponding import
(java.util.List or java.util.Arrays) is present at the top of the example.


storage.listFiles(
"<BUCKET_ID>", // bucketId
listOf(), // queries (optional)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix Kotlin syntax in Java example: listOf() is not available.

Line 13 uses listOf(), which is a Kotlin stdlib function and will not compile in Java code. Use Java collection APIs instead.

Apply this diff to fix the Java syntax:

  storage.listFiles(
      "<BUCKET_ID>", // bucketId 
-     listOf(), // queries (optional)
+     Arrays.asList(), // queries (optional)
      "<SEARCH>", // search (optional)
      false, // total (optional)

Alternatively, if targeting Java 9+, use List.of():

-     listOf(), // queries (optional)
+     List.of(), // queries (optional)

Add the import if using Arrays.asList():

import java.util.Arrays;
🤖 Prompt for AI Agents
In docs/examples/java/storage/list-files.md around line 13, the example
incorrectly uses Kotlin's listOf(), which won't compile in Java; replace it with
a Java collection initializer such as Arrays.asList(...) and add the import
java.util.Arrays, or if the project targets Java 9+ use List.of(... ) instead
(and import java.util.List if needed); update the example call and imports
accordingly so the snippet compiles as Java.

Comment on lines +4 to +5
import io.appwrite.Permission;
import io.appwrite.Role;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix Kotlin syntax in Java example: listOf() is not available.

Imports for Permission and Role are correct, but line 17 uses listOf(), which is a Kotlin stdlib function and will not compile in Java code.

Apply this diff to fix the Java syntax:

  storage.updateFile(
      "<BUCKET_ID>", // bucketId 
      "<FILE_ID>", // fileId 
      "<NAME>", // name (optional)
-     listOf(Permission.read(Role.any())), // permissions (optional)
+     Arrays.asList(Permission.read(Role.any())), // permissions (optional)
      new CoroutineCallback<>((result, error) -> {

Alternatively, if targeting Java 9+, use List.of():

-     listOf(Permission.read(Role.any())), // permissions (optional)
+     List.of(Permission.read(Role.any())), // permissions (optional)

Add the import if using Arrays.asList():

import java.util.Arrays;

Also applies to: 17-17

🤖 Prompt for AI Agents
In docs/examples/java/storage/update-file.md around lines 4-5 (and line 17), the
example incorrectly uses Kotlin's listOf() in Java code; replace listOf(...)
with a Java equivalent (either Arrays.asList(...) and add import
java.util.Arrays;, or if targeting Java 9+, use List.of(...)) and ensure the
corresponding import is added when using Arrays.asList to make the example valid
Java.

"isAdmin" to false
), // data
listOf("read("any")"), // permissions (optional)
listOf(Permission.read(Role.any())), // permissions (optional)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix Kotlin syntax in Java example: listOf() is not available.

Line 24 uses listOf(), which is a Kotlin stdlib function and will not compile in Java code.

Apply this diff to fix the Java syntax:

      ), // data 
-     listOf(Permission.read(Role.any())), // permissions (optional)
+     Arrays.asList(Permission.read(Role.any())), // permissions (optional)
      "<TRANSACTION_ID>", // transactionId (optional)

Alternatively, if targeting Java 9+:

-     listOf(Permission.read(Role.any())), // permissions (optional)
+     List.of(Permission.read(Role.any())), // permissions (optional)

Add the import if using Arrays.asList():

import java.util.Arrays;
🤖 Prompt for AI Agents
In docs/examples/java/tablesdb/create-row.md around line 24, the example uses
Kotlin's listOf() which is invalid in Java; replace it with a Java list factory
such as Arrays.asList(...) (and add import java.util.Arrays) or, for Java 9+,
use List.of(...), ensuring imports (java.util.List) are present as needed and
adjust the syntax to match Java generics.

Comment on lines +26 to +128
fun increment(value: Number = 1, max: Number? = null): String {
require(!value.toDouble().isNaN() && !value.toDouble().isInfinite()) { "Value cannot be NaN or Infinity" }
max?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Max cannot be NaN or Infinity" } }
val values = mutableListOf<Any?>(value)
max?.let { values.add(it) }
return Operator("increment", values).toJson()
}

fun decrement(value: Number = 1, min: Number? = null): String {
require(!value.toDouble().isNaN() && !value.toDouble().isInfinite()) { "Value cannot be NaN or Infinity" }
min?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Min cannot be NaN or Infinity" } }
val values = mutableListOf<Any?>(value)
min?.let { values.add(it) }
return Operator("decrement", values).toJson()
}

fun multiply(factor: Number, max: Number? = null): String {
require(!factor.toDouble().isNaN() && !factor.toDouble().isInfinite()) { "Factor cannot be NaN or Infinity" }
max?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Max cannot be NaN or Infinity" } }
val values = mutableListOf<Any?>(factor)
max?.let { values.add(it) }
return Operator("multiply", values).toJson()
}

fun divide(divisor: Number, min: Number? = null): String {
require(!divisor.toDouble().isNaN() && !divisor.toDouble().isInfinite()) { "Divisor cannot be NaN or Infinity" }
min?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Min cannot be NaN or Infinity" } }
require(divisor.toDouble() != 0.0) { "Divisor cannot be zero" }
val values = mutableListOf<Any?>(divisor)
min?.let { values.add(it) }
return Operator("divide", values).toJson()
}

fun modulo(divisor: Number): String {
require(!divisor.toDouble().isNaN() && !divisor.toDouble().isInfinite()) { "Divisor cannot be NaN or Infinity" }
require(divisor.toDouble() != 0.0) { "Divisor cannot be zero" }
return Operator("modulo", listOf(divisor)).toJson()
}

fun power(exponent: Number, max: Number? = null): String {
require(!exponent.toDouble().isNaN() && !exponent.toDouble().isInfinite()) { "Exponent cannot be NaN or Infinity" }
max?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Max cannot be NaN or Infinity" } }
val values = mutableListOf<Any?>(exponent)
max?.let { values.add(it) }
return Operator("power", values).toJson()
}

fun arrayAppend(values: List<Any?>): String {
return Operator("arrayAppend", values).toJson()
}

fun arrayPrepend(values: List<Any?>): String {
return Operator("arrayPrepend", values).toJson()
}

fun arrayInsert(index: Int, value: Any): String {
return Operator("arrayInsert", listOf(index, value)).toJson()
}

fun arrayRemove(value: Any): String {
return Operator("arrayRemove", listOf(value)).toJson()
}

fun arrayUnique(): String {
return Operator("arrayUnique", emptyList()).toJson()
}

fun arrayIntersect(values: List<Any?>): String {
return Operator("arrayIntersect", values).toJson()
}

fun arrayDiff(values: List<Any?>): String {
return Operator("arrayDiff", values).toJson()
}

fun arrayFilter(condition: Condition, value: Any? = null): String {
val values = listOf<Any?>(condition.value, value)
return Operator("arrayFilter", values).toJson()
}

fun stringConcat(value: Any): String {
return Operator("stringConcat", listOf(value)).toJson()
}

fun stringReplace(search: String, replace: String): String {
return Operator("stringReplace", listOf(search, replace)).toJson()
}

fun toggle(): String {
return Operator("toggle", emptyList()).toJson()
}

fun dateAddDays(days: Int): String {
return Operator("dateAddDays", listOf(days)).toJson()
}

fun dateSubDays(days: Int): String {
return Operator("dateSubDays", listOf(days)).toJson()
}

fun dateSetNow(): String {
return Operator("dateSetNow", emptyList()).toJson()
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Return operators as structured objects, not JSON strings

Each factory currently calling .toJson() returns a raw string. When consumers place that value inside data/permissions maps, our serializer will emit it as a quoted string (e.g. "count":"{\"method\":\"increment\",\"values\":[1]}"), so the server never sees the expected object form and atomic updates break. We need these helpers to return Operator instances so the Gson (or equivalent) serializer can embed them as nested JSON objects.

Apply the pattern below across all factory methods:

-        fun increment(value: Number = 1, max: Number? = null): String {
+        fun increment(value: Number = 1, max: Number? = null): Operator {-            return Operator("increment", values).toJson()
+            return Operator("increment", values)
         }

Do the same for decrement, multiply, divide, array/string/date helpers, etc., removing the .toJson() call and updating the return types to Operator.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fun increment(value: Number = 1, max: Number? = null): String {
require(!value.toDouble().isNaN() && !value.toDouble().isInfinite()) { "Value cannot be NaN or Infinity" }
max?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Max cannot be NaN or Infinity" } }
val values = mutableListOf<Any?>(value)
max?.let { values.add(it) }
return Operator("increment", values).toJson()
}
fun decrement(value: Number = 1, min: Number? = null): String {
require(!value.toDouble().isNaN() && !value.toDouble().isInfinite()) { "Value cannot be NaN or Infinity" }
min?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Min cannot be NaN or Infinity" } }
val values = mutableListOf<Any?>(value)
min?.let { values.add(it) }
return Operator("decrement", values).toJson()
}
fun multiply(factor: Number, max: Number? = null): String {
require(!factor.toDouble().isNaN() && !factor.toDouble().isInfinite()) { "Factor cannot be NaN or Infinity" }
max?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Max cannot be NaN or Infinity" } }
val values = mutableListOf<Any?>(factor)
max?.let { values.add(it) }
return Operator("multiply", values).toJson()
}
fun divide(divisor: Number, min: Number? = null): String {
require(!divisor.toDouble().isNaN() && !divisor.toDouble().isInfinite()) { "Divisor cannot be NaN or Infinity" }
min?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Min cannot be NaN or Infinity" } }
require(divisor.toDouble() != 0.0) { "Divisor cannot be zero" }
val values = mutableListOf<Any?>(divisor)
min?.let { values.add(it) }
return Operator("divide", values).toJson()
}
fun modulo(divisor: Number): String {
require(!divisor.toDouble().isNaN() && !divisor.toDouble().isInfinite()) { "Divisor cannot be NaN or Infinity" }
require(divisor.toDouble() != 0.0) { "Divisor cannot be zero" }
return Operator("modulo", listOf(divisor)).toJson()
}
fun power(exponent: Number, max: Number? = null): String {
require(!exponent.toDouble().isNaN() && !exponent.toDouble().isInfinite()) { "Exponent cannot be NaN or Infinity" }
max?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Max cannot be NaN or Infinity" } }
val values = mutableListOf<Any?>(exponent)
max?.let { values.add(it) }
return Operator("power", values).toJson()
}
fun arrayAppend(values: List<Any?>): String {
return Operator("arrayAppend", values).toJson()
}
fun arrayPrepend(values: List<Any?>): String {
return Operator("arrayPrepend", values).toJson()
}
fun arrayInsert(index: Int, value: Any): String {
return Operator("arrayInsert", listOf(index, value)).toJson()
}
fun arrayRemove(value: Any): String {
return Operator("arrayRemove", listOf(value)).toJson()
}
fun arrayUnique(): String {
return Operator("arrayUnique", emptyList()).toJson()
}
fun arrayIntersect(values: List<Any?>): String {
return Operator("arrayIntersect", values).toJson()
}
fun arrayDiff(values: List<Any?>): String {
return Operator("arrayDiff", values).toJson()
}
fun arrayFilter(condition: Condition, value: Any? = null): String {
val values = listOf<Any?>(condition.value, value)
return Operator("arrayFilter", values).toJson()
}
fun stringConcat(value: Any): String {
return Operator("stringConcat", listOf(value)).toJson()
}
fun stringReplace(search: String, replace: String): String {
return Operator("stringReplace", listOf(search, replace)).toJson()
}
fun toggle(): String {
return Operator("toggle", emptyList()).toJson()
}
fun dateAddDays(days: Int): String {
return Operator("dateAddDays", listOf(days)).toJson()
}
fun dateSubDays(days: Int): String {
return Operator("dateSubDays", listOf(days)).toJson()
}
fun dateSetNow(): String {
return Operator("dateSetNow", emptyList()).toJson()
}
fun increment(value: Number = 1, max: Number? = null): Operator {
require(!value.toDouble().isNaN() && !value.toDouble().isInfinite()) { "Value cannot be NaN or Infinity" }
max?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Max cannot be NaN or Infinity" } }
val values = mutableListOf<Any?>(value)
max?.let { values.add(it) }
return Operator("increment", values)
}
fun decrement(value: Number = 1, min: Number? = null): Operator {
require(!value.toDouble().isNaN() && !value.toDouble().isInfinite()) { "Value cannot be NaN or Infinity" }
min?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Min cannot be NaN or Infinity" } }
val values = mutableListOf<Any?>(value)
min?.let { values.add(it) }
return Operator("decrement", values)
}
fun multiply(factor: Number, max: Number? = null): Operator {
require(!factor.toDouble().isNaN() && !factor.toDouble().isInfinite()) { "Factor cannot be NaN or Infinity" }
max?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Max cannot be NaN or Infinity" } }
val values = mutableListOf<Any?>(factor)
max?.let { values.add(it) }
return Operator("multiply", values)
}
fun divide(divisor: Number, min: Number? = null): Operator {
require(!divisor.toDouble().isNaN() && !divisor.toDouble().isInfinite()) { "Divisor cannot be NaN or Infinity" }
min?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Min cannot be NaN or Infinity" } }
require(divisor.toDouble() != 0.0) { "Divisor cannot be zero" }
val values = mutableListOf<Any?>(divisor)
min?.let { values.add(it) }
return Operator("divide", values)
}
fun modulo(divisor: Number): Operator {
require(!divisor.toDouble().isNaN() && !divisor.toDouble().isInfinite()) { "Divisor cannot be NaN or Infinity" }
require(divisor.toDouble() != 0.0) { "Divisor cannot be zero" }
return Operator("modulo", listOf(divisor))
}
fun power(exponent: Number, max: Number? = null): Operator {
require(!exponent.toDouble().isNaN() && !exponent.toDouble().isInfinite()) { "Exponent cannot be NaN or Infinity" }
max?.let { require(!it.toDouble().isNaN() && !it.toDouble().isInfinite()) { "Max cannot be NaN or Infinity" } }
val values = mutableListOf<Any?>(exponent)
max?.let { values.add(it) }
return Operator("power", values)
}
fun arrayAppend(values: List<Any?>): Operator {
return Operator("arrayAppend", values)
}
fun arrayPrepend(values: List<Any?>): Operator {
return Operator("arrayPrepend", values)
}
fun arrayInsert(index: Int, value: Any): Operator {
return Operator("arrayInsert", listOf(index, value))
}
fun arrayRemove(value: Any): Operator {
return Operator("arrayRemove", listOf(value))
}
fun arrayUnique(): Operator {
return Operator("arrayUnique", emptyList())
}
fun arrayIntersect(values: List<Any?>): Operator {
return Operator("arrayIntersect", values)
}
fun arrayDiff(values: List<Any?>): Operator {
return Operator("arrayDiff", values)
}
fun arrayFilter(condition: Condition, value: Any? = null): Operator {
val values = listOf<Any?>(condition.value, value)
return Operator("arrayFilter", values)
}
fun stringConcat(value: Any): Operator {
return Operator("stringConcat", listOf(value))
}
fun stringReplace(search: String, replace: String): Operator {
return Operator("stringReplace", listOf(search, replace))
}
fun toggle(): Operator {
return Operator("toggle", emptyList())
}
fun dateAddDays(days: Int): Operator {
return Operator("dateAddDays", listOf(days))
}
fun dateSubDays(days: Int): Operator {
return Operator("dateSubDays", listOf(days))
}
fun dateSetNow(): Operator {
return Operator("dateSetNow", emptyList())
}
🤖 Prompt for AI Agents
library/src/main/java/io/appwrite/Operator.kt around lines 26 to 128: the
factory functions currently return JSON strings (they call .toJson() and have
return type String) which causes serializers to embed them as quoted strings;
change each factory to return the Operator instance instead of its JSON by
removing the .toJson() call and updating the function return type from String to
Operator for all methods (increment, decrement, multiply, divide, modulo, power,
array*, string*, toggle, date* and others in this block); ensure each function
constructs and returns Operator("name", values) directly so the client
serializer can embed it as a nested JSON object.

@abnegate abnegate merged commit ec4ba5b into main Nov 3, 2025
2 checks passed
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