Skip to content
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Add this to your package's `pubspec.yaml` file:

```yml
dependencies:
appwrite: ^18.0.0
appwrite: ^19.0.0
```

You can install packages from the command line:
Expand Down
6 changes: 5 additions & 1 deletion docs/examples/account/update-prefs.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,9 @@ Client client = Client()
Account account = Account(client);

User result = await account.updatePrefs(
prefs: {},
prefs: {
"language": "en",
"timezone": "UTC",
"darkTheme": true
},
);
8 changes: 7 additions & 1 deletion docs/examples/databases/create-document.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ Document result = await databases.createDocument(
databaseId: '<DATABASE_ID>',
collectionId: '<COLLECTION_ID>',
documentId: '<DOCUMENT_ID>',
data: {},
data: {
"username": "walter.obrien",
"email": "[email protected]",
"fullName": "Walter O'Brien",
"age": 30,
"isAdmin": false
},
permissions: ["read("any")"], // optional
);
Comment on lines 20 to 21
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix invalid permissions syntax in Dart snippet.

Use typed builders to avoid quoting issues.

Apply:

-    permissions: ["read("any")"], // optional
+    permissions: [Permission.read(Role.any())], // 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
permissions: ["read("any")"], // optional
);
permissions: [Permission.read(Role.any())], // optional
);
🤖 Prompt for AI Agents
In docs/examples/databases/create-document.md around lines 20 to 21, the Dart
snippet uses invalid permissions syntax permissions: ["read("any")"] — replace
the quoted raw string with the Dart typed builder form (use the appropriate
Permission/read builder function or constructor with a plain 'any' argument) so
permissions are constructed as typed objects instead of strings; update the
example to call the Permission builder API consistently with the surrounding
snippet and remove the nested quotes/parentheses error.

8 changes: 7 additions & 1 deletion docs/examples/tablesdb/create-row.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ Row result = await tablesDB.createRow(
databaseId: '<DATABASE_ID>',
tableId: '<TABLE_ID>',
rowId: '<ROW_ID>',
data: {},
data: {
"username": "walter.obrien",
"email": "[email protected]",
"fullName": "Walter O'Brien",
"age": 30,
"isAdmin": false
},
permissions: ["read("any")"], // optional
);
Comment on lines 20 to 21
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix invalid permissions syntax in Dart snippet.

The current string quoting will not compile. Use the SDK helpers.

Apply:

-    permissions: ["read("any")"], // optional
+    permissions: [Permission.read(Role.any())], // 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
permissions: ["read("any")"], // optional
);
permissions: [Permission.read(Role.any())], // optional
);
🤖 Prompt for AI Agents
In docs/examples/tablesdb/create-row.md around lines 20-21, the Dart permissions
string uses invalid nested quotes and won't compile; replace the string with the
SDK permission helper (use the Permission.read helper and pass "any" as the
argument) instead of the literal "read("any")" string, and ensure the Dart
snippet imports and uses the SDK Permission helper correctly so the permissions
array contains the helper call rather than an invalid quoted string.

2 changes: 1 addition & 1 deletion lib/appwrite.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// Appwrite Flutter SDK
///
/// This SDK is compatible with Appwrite server version 1.8.x.
/// This SDK is compatible with Appwrite server version 1.8.x.
/// For older versions, please check
/// [previous releases](https://github.com/appwrite/sdk-for-flutter/releases).
library appwrite;
Expand Down
2 changes: 1 addition & 1 deletion lib/client_browser.dart
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export 'src/client_browser.dart';
export 'src/client_browser.dart';
2 changes: 1 addition & 1 deletion lib/client_io.dart
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export 'src/client_io.dart';
export 'src/client_io.dart';
72 changes: 64 additions & 8 deletions lib/query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ class Query {
Map<String, dynamic> toJson() {
final map = <String, dynamic>{'method': method};

if (attribute != null) {
if(attribute != null) {
map['attribute'] = attribute;
}

if (values != null) {
if(values != null) {
map['values'] = values is List ? values : [values];
}

Expand All @@ -26,7 +26,7 @@ class Query {
String toString() => jsonEncode(toJson());

/// Filter resources where [attribute] is equal to [value].
///
///
/// [value] can be a single value or a list. If a list is used
/// the query will return resources where [attribute] is equal
/// to any of the values in the list.
Expand Down Expand Up @@ -111,6 +111,10 @@ class Query {
static String createdAfter(String value) =>
Query._('createdAfter', null, value).toString();

/// Filter resources where document was created between [start] and [end] (inclusive).
static String createdBetween(String start, String end) =>
Query._('createdBetween', null, [start, end]).toString();

Comment on lines +116 to +119
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Fix createdBetween/updatedBetween to use supported operators.

The server doesn’t expose “createdBetween”/“updatedBetween” operators. Use between() on $createdAt/$updatedAt instead to keep inclusive semantics documented in Queries. (appwrite.io)

Apply:

-  /// Filter resources where document was created between [start] and [end] (inclusive).
-  static String createdBetween(String start, String end) =>
-      Query._('createdBetween', null, [start, end]).toString();
+  /// Filter resources where document was created between [start] and [end] (inclusive).
+  static String createdBetween(String start, String end) =>
+      between(r'$createdAt', start, end);
@@
-  /// Filter resources where document was updated between [start] and [end] (inclusive).
-  static String updatedBetween(String start, String end) =>
-      Query._('updatedBetween', null, [start, end]).toString();
+  /// Filter resources where document was updated between [start] and [end] (inclusive).
+  static String updatedBetween(String start, String end) =>
+      between(r'$updatedAt', start, end);

If tests assert the JSON method name equals "createdBetween"/"updatedBetween", update them to expect method "between" and attribute "$createdAt"/"$updatedAt", respectively.

Also applies to: 126-129


🏁 Script executed:

#!/bin/bash
# Search for existing between() method and createdBetween/updatedBetween in lib/query.dart
rg -nP --type=dart 'static String between' -n lib/query.dart || true
rg -nP --type=dart 'between\(' -n lib/query.dart || true

# Locate createdBetween and updatedBetween definitions
rg -nP --type=dart 'createdBetween' -n lib/query.dart || true
rg -nP --type=dart 'updatedBetween' -n lib/query.dart || true

# Inspect Query._ constructor to see supported operators
rg -nP --type=dart 'class Query\s*{' -n lib/query.dart -A5 -B0 || true
rg -nP --type=dart 'factory Query\._' -n lib/query.dart -A3 -B3 || true

Length of output: 945


Use between operator for createdBetween/updatedBetween filters

  • lib/query.dart@115–117: replace
    Query._('createdBetween', null, [start, end]).toString();
    with
    between(r'$createdAt', start, end);
  • lib/query.dart@127–129: replace
    Query._('updatedBetween', null, [start, end]).toString();
    with
    between(r'$updatedAt', start, end);
  • Update any tests that assert method names "createdBetween"/"updatedBetween" to expect "between" with attributes "$createdAt"/"$updatedAt".
🤖 Prompt for AI Agents
In lib/query.dart around lines 114–117 and 127–129, the createdBetween and
updatedBetween helpers currently construct Query._ with operator names
"createdBetween"/"updatedBetween"; change them to call between(r'$createdAt',
start, end) and between(r'$updatedAt', start, end) respectively so the operator
used is "between" with the correct attribute; also update any tests that assert
the operator name "createdBetween"/"updatedBetween" to expect "between" and that
the attribute is "$createdAt"/"$updatedAt".

💡 Verification agent

🧩 Analysis chain

Repo-wide verification for API compatibility.

Update tests/usage to match the supported shape; remove any geometry/distance usages.

Also applies to: 126-129, 178-224


🏁 Script executed:

#!/bin/bash
# 1) Find usages of newly added helpers
rg -nP --type=dart -C2 '\b(createdBetween|updatedBetween|distance(Equal|NotEqual|GreaterThan|LessThan)|intersects|notIntersects|crosses|notCrosses|overlaps|notOverlaps|touches|notTouches)\s*\('

# 2) Show current JSON emitted by Query.createdBetween/updatedBetween
rg -nP -C3 'static\s+String\s+createdBetween|static\s+String\s+updatedBetween' lib/query.dart

# 3) Grep tests that assert method name/attribute for created/updated helpers
rg -nP -C2 'createdBetween|updatedBetween' test

Length of output: 7187


Remove unsupported geometry/distance filter methods
Delete the distance* and geometry filter helpers (distanceEqual/NotEqual/GreaterThan/LessThan and intersects/notIntersects/crosses/notCrosses/overlaps/notOverlaps/touches/notTouches) from lib/query.dart (lines 178–224).

🤖 Prompt for AI Agents
In lib/query.dart around lines 178 to 224, remove the unsupported
geometry/distance filter helper methods: all distance* methods (distanceEqual,
distanceNotEqual, distanceGreaterThan, distanceLessThan) and all geometry
intersection/relationship helpers (intersects, notIntersects, crosses,
notCrosses, overlaps, notOverlaps, touches, notTouches). Delete their method
definitions and any associated imports or references that become unused as a
result, and run a quick project build/test to ensure there are no remaining
references to these methods.

/// Filter resources where document was updated before [value].
static String updatedBefore(String value) =>
Query._('updatedBefore', null, value).toString();
Expand All @@ -119,6 +123,10 @@ class Query {
static String updatedAfter(String value) =>
Query._('updatedAfter', null, value).toString();

/// Filter resources where document was updated between [start] and [end] (inclusive).
static String updatedBetween(String start, String end) =>
Query._('updatedBetween', null, [start, end]).toString();

static String or(List<String> queries) => Query._(
'or',
null,
Expand All @@ -144,14 +152,14 @@ class Query {
Query._('orderDesc', attribute).toString();

/// Return results before [id].
///
///
/// Refer to the [Cursor Based Pagination](https://appwrite.io/docs/pagination#cursor-pagination)
/// docs for more information.
static String cursorBefore(String id) =>
Query._('cursorBefore', null, id).toString();

/// Return results after [id].
///
///
/// Refer to the [Cursor Based Pagination](https://appwrite.io/docs/pagination#cursor-pagination)
/// docs for more information.
static String cursorAfter(String id) =>
Expand All @@ -161,9 +169,57 @@ class Query {
static String limit(int limit) => Query._('limit', null, limit).toString();

/// Return results from [offset].
///
///
/// Refer to the [Offset Pagination](https://appwrite.io/docs/pagination#offset-pagination)
/// docs for more information.
static String offset(int offset) =>
Query._('offset', null, offset).toString();
}

/// Filter resources where [attribute] is at a specific distance from the given coordinates.
static String distanceEqual(String attribute, List<dynamic> values, double distance, [bool meters = true]) =>
Query._('distanceEqual', attribute, [values, distance, meters]).toString();

/// Filter resources where [attribute] is not at a specific distance from the given coordinates.
static String distanceNotEqual(String attribute, List<dynamic> values, double distance, [bool meters = true]) =>
Query._('distanceNotEqual', attribute, [values, distance, meters]).toString();

/// Filter resources where [attribute] is at a distance greater than the specified value from the given coordinates.
static String distanceGreaterThan(String attribute, List<dynamic> values, double distance, [bool meters = true]) =>
Query._('distanceGreaterThan', attribute, [values, distance, meters]).toString();

/// Filter resources where [attribute] is at a distance less than the specified value from the given coordinates.
static String distanceLessThan(String attribute, List<dynamic> values, double distance, [bool meters = true]) =>
Query._('distanceLessThan', attribute, [values, distance, meters]).toString();

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Remove distance helpers — geospatial distance queries are not supported.*

Appwrite queries don’t support distanceEqual/NotEqual/GreaterThan/LessThan operators today; recommended patterns use bounding-box comparisons on lat/long attributes client-side. Keep these out to avoid shipping unusable APIs. (appwrite.io, dev.to)

Apply:

-  /// Filter resources where [attribute] is at a specific distance from the given coordinates.
-  static String distanceEqual(String attribute, List<dynamic> values, double distance, [bool meters = true]) =>
-      Query._('distanceEqual', attribute, [values, distance, meters]).toString();
-
-  /// Filter resources where [attribute] is not at a specific distance from the given coordinates.
-  static String distanceNotEqual(String attribute, List<dynamic> values, double distance, [bool meters = true]) =>
-      Query._('distanceNotEqual', attribute, [values, distance, meters]).toString();
-
-  /// Filter resources where [attribute] is at a distance greater than the specified value from the given coordinates.
-  static String distanceGreaterThan(String attribute, List<dynamic> values, double distance, [bool meters = true]) =>
-      Query._('distanceGreaterThan', attribute, [values, distance, meters]).toString();
-
-  /// Filter resources where [attribute] is at a distance less than the specified value from the given coordinates.
-  static String distanceLessThan(String attribute, List<dynamic> values, double distance, [bool meters = true]) =>
-      Query._('distanceLessThan', attribute, [values, distance, meters]).toString();

Alternatively, gate them with @deprecated and throw UnsupportedError immediately with a link to docs.

📝 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
/// Filter resources where [attribute] is at a specific distance from the given coordinates.
static String distanceEqual(String attribute, List<dynamic> values, double distance, [bool meters = true]) =>
Query._('distanceEqual', attribute, [values, distance, meters]).toString();
/// Filter resources where [attribute] is not at a specific distance from the given coordinates.
static String distanceNotEqual(String attribute, List<dynamic> values, double distance, [bool meters = true]) =>
Query._('distanceNotEqual', attribute, [values, distance, meters]).toString();
/// Filter resources where [attribute] is at a distance greater than the specified value from the given coordinates.
static String distanceGreaterThan(String attribute, List<dynamic> values, double distance, [bool meters = true]) =>
Query._('distanceGreaterThan', attribute, [values, distance, meters]).toString();
/// Filter resources where [attribute] is at a distance less than the specified value from the given coordinates.
static String distanceLessThan(String attribute, List<dynamic> values, double distance, [bool meters = true]) =>
Query._('distanceLessThan', attribute, [values, distance, meters]).toString();
🤖 Prompt for AI Agents
In lib/query.dart around lines 178 to 193, the distance* helper methods expose
geospatial distance queries which Appwrite does not support; remove these four
methods (distanceEqual, distanceNotEqual, distanceGreaterThan, distanceLessThan)
from the public API OR mark each with @Deprecated and change their
implementation to immediately throw an UnsupportedError with a short message and
a link to the Appwrite docs explaining the limitation (include the docs URL), so
callers get a clear runtime error instead of an unusable API.

/// Filter resources where [attribute] intersects with the given geometry.
static String intersects(String attribute, List<dynamic> values) =>
Query._('intersects', attribute, values).toString();

/// Filter resources where [attribute] does not intersect with the given geometry.
static String notIntersects(String attribute, List<dynamic> values) =>
Query._('notIntersects', attribute, values).toString();

/// Filter resources where [attribute] crosses the given geometry.
static String crosses(String attribute, List<dynamic> values) =>
Query._('crosses', attribute, values).toString();

/// Filter resources where [attribute] does not cross the given geometry.
static String notCrosses(String attribute, List<dynamic> values) =>
Query._('notCrosses', attribute, values).toString();

/// Filter resources where [attribute] overlaps with the given geometry.
static String overlaps(String attribute, List<dynamic> values) =>
Query._('overlaps', attribute, values).toString();

/// Filter resources where [attribute] does not overlap with the given geometry.
static String notOverlaps(String attribute, List<dynamic> values) =>
Query._('notOverlaps', attribute, values).toString();

/// Filter resources where [attribute] touches the given geometry.
static String touches(String attribute, List<dynamic> values) =>
Query._('touches', attribute, values).toString();

/// Filter resources where [attribute] does not touch the given geometry.
static String notTouches(String attribute, List<dynamic> values) =>
Query._('notTouches', attribute, values).toString();
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Geometry relation builders: clarify geometry format; optional rename and DRY.

  • Document expected geometry (e.g., GeoJSON Polygon/LineString/Point).
  • Optional: rename values -> geometry for readability; factor a small helper.
+  // Helper for geometry relation queries.
+  static String _rel(String method, String attribute, List<dynamic> geometry) =>
+      Query._(method, attribute, geometry).toString();
+
-  /// Filter resources where [attribute] intersects with the given geometry.
-  static String intersects(String attribute, List<dynamic> values) =>
-      Query._('intersects', attribute, values).toString();
+  /// Filter resources where [attribute] intersects with the given geometry.
+  /// [geometry] should be a GeoJSON-like structure (e.g., Point, LineString, Polygon).
+  static String intersects(String attribute, List<dynamic> geometry) =>
+      _rel('intersects', attribute, geometry);
 
-  /// Filter resources where [attribute] does not intersect with the given geometry.
-  static String notIntersects(String attribute, List<dynamic> values) =>
-      Query._('notIntersects', attribute, values).toString();
+  /// Filter resources where [attribute] does not intersect with the given geometry.
+  static String notIntersects(String attribute, List<dynamic> geometry) =>
+      _rel('notIntersects', attribute, geometry);
 
-  /// Filter resources where [attribute] crosses the given geometry.
-  static String crosses(String attribute, List<dynamic> values) =>
-      Query._('crosses', attribute, values).toString();
+  /// Filter resources where [attribute] crosses the given geometry.
+  static String crosses(String attribute, List<dynamic> geometry) =>
+      _rel('crosses', attribute, geometry);
 
-  /// Filter resources where [attribute] does not cross the given geometry.
-  static String notCrosses(String attribute, List<dynamic> values) =>
-      Query._('notCrosses', attribute, values).toString();
+  /// Filter resources where [attribute] does not cross the given geometry.
+  static String notCrosses(String attribute, List<dynamic> geometry) =>
+      _rel('notCrosses', attribute, geometry);
 
-  /// Filter resources where [attribute] overlaps with the given geometry.
-  static String overlaps(String attribute, List<dynamic> values) =>
-      Query._('overlaps', attribute, values).toString();
+  /// Filter resources where [attribute] overlaps with the given geometry.
+  static String overlaps(String attribute, List<dynamic> geometry) =>
+      _rel('overlaps', attribute, geometry);
 
-  /// Filter resources where [attribute] does not overlap with the given geometry.
-  static String notOverlaps(String attribute, List<dynamic> values) =>
-      Query._('notOverlaps', attribute, values).toString();
+  /// Filter resources where [attribute] does not overlap with the given geometry.
+  static String notOverlaps(String attribute, List<dynamic> geometry) =>
+      _rel('notOverlaps', attribute, geometry);
 
-  /// Filter resources where [attribute] touches the given geometry.
-  static String touches(String attribute, List<dynamic> values) =>
-      Query._('touches', attribute, values).toString();
+  /// Filter resources where [attribute] touches the given geometry.
+  static String touches(String attribute, List<dynamic> geometry) =>
+      _rel('touches', attribute, geometry);
 
-  /// Filter resources where [attribute] does not touch the given geometry.
-  static String notTouches(String attribute, List<dynamic> values) =>
-      Query._('notTouches', attribute, values).toString();
+  /// Filter resources where [attribute] does not touch the given geometry.
+  static String notTouches(String attribute, List<dynamic> geometry) =>
+      _rel('notTouches', attribute, geometry);

To confirm API parity and naming:

Add tests similar to existing temporal tests to assert method names and payload shapes for each geometry builder.


🌐 Web query:

Appwrite v19 Query API: do geometry relation filters exist with names: intersects, notIntersects, crosses, notCrosses, overlaps, notOverlaps, touches, notTouches? What is the expected geometry payload shape?

💡 Result:

Short answer: No — Appwrite v19 (the current Query API) does not provide built‑in geometry relation filters named intersects / notIntersects / crosses / notCrosses / overlaps / notOverlaps / touches / notTouches. The official Query docs list standard comparison, string, null and array operators but do not include spatial relation operators. [1]

What exists / roadmap notes: Appwrite team discussions indicate geo queries are considered (examples like Query.geoSphere(...) and Query.geoPolygon(...) were proposed) but these are future ideas rather than implemented query operators. [2][3]

Expected payload shape: because geometry/spatial queries are not implemented in v19 there is no documented, supported geometry payload shape in the official Query API. The only available guidance is community/roadmap examples (e.g. passing a point/radius or polygon coordinates as arguments in the proposed Query.geo* APIs), but these are not official specs. If you need spatial queries today you must implement them yourself (store GeoJSON in a field and evaluate geometry relations in your application or a cloud function) or use a DB that supports spatial queries (PostGIS, MongoDB geo queries, etc.). [2][3]

Sources:

  • Appwrite Queries documentation (current Query API operator list). [1]
  • Appwrite discussions / roadmap mentioning geo query ideas (Query.geoSphere, Query.geoPolygon) and community threads. [2][3]

Remove unsupported spatial query methods
The Appwrite v19 Query API does not support spatial relation operators (intersects, notIntersects, crosses, notCrosses, overlaps, notOverlaps, touches, notTouches) (appwrite.io). Remove these methods or mark them as experimental until backend support is available.

🤖 Prompt for AI Agents
In lib/query.dart around lines 226-256 the eight spatial relation methods
(intersects, notIntersects, crosses, notCrosses, overlaps, notOverlaps, touches,
notTouches) are not supported by Appwrite v19; remove these static methods from
the Query class and delete or update any usages/tests/docs referencing them. If
you prefer to keep placeholders for API parity instead of removal, annotate each
method with a clear @Deprecated message and make them immediately throw an
UnsupportedError (or similar) with a message pointing to Appwrite v19 lack of
support; also update documentation and tests accordingly.

}
2 changes: 1 addition & 1 deletion lib/realtime_browser.dart
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export 'src/realtime_browser.dart';
export 'src/realtime_browser.dart';
2 changes: 1 addition & 1 deletion lib/realtime_io.dart
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export 'src/realtime_io.dart';
export 'src/realtime_io.dart';
2 changes: 1 addition & 1 deletion lib/role.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ class Role {
static String label(String name) {
return 'label:$name';
}
}
}
Loading