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
88 changes: 88 additions & 0 deletions lib/query.dart
Original file line number Diff line number Diff line change
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 Down Expand Up @@ -166,4 +174,84 @@ class Query {
/// 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();

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

}
8 changes: 6 additions & 2 deletions lib/services/account.dart
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,9 @@ class Account extends Service {
/// Use this endpoint to create a session from token. Provide the **userId**
/// and **secret** parameters from the successful response of authentication
/// flows initiated by token creation. For example, magic URL and phone login.
@Deprecated('This API has been deprecated.')
@Deprecated(
'This API has been deprecated since 1.6.0. Please use `Account.createSession` instead.',
)
Future<models.Session> updateMagicURLSession({
required String userId,
required String secret,
Expand Down Expand Up @@ -975,7 +977,9 @@ class Account extends Service {
/// Use this endpoint to create a session from token. Provide the **userId**
/// and **secret** parameters from the successful response of authentication
/// flows initiated by token creation. For example, magic URL and phone login.
@Deprecated('This API has been deprecated.')
@Deprecated(
'This API has been deprecated since 1.6.0. Please use `Account.createSession` instead.',
)
Future<models.Session> updatePhoneSession({
required String userId,
required String secret,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/client_browser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ClientBrowser extends ClientBase with ClientMixin {
'x-sdk-name': 'Flutter',
'x-sdk-platform': 'client',
'x-sdk-language': 'flutter',
'x-sdk-version': '18.0.0',
'x-sdk-version': '19.0.0',
'X-Appwrite-Response-Format': '1.8.0',
};

Expand Down
2 changes: 1 addition & 1 deletion lib/src/client_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class ClientIO extends ClientBase with ClientMixin {
'x-sdk-name': 'Flutter',
'x-sdk-platform': 'client',
'x-sdk-language': 'flutter',
'x-sdk-version': '18.0.0',
'x-sdk-version': '19.0.0',
'X-Appwrite-Response-Format': '1.8.0',
};

Expand Down
2 changes: 1 addition & 1 deletion lib/src/enums/credit_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ enum CreditCard {
mastercard(value: 'mastercard'),
naranja(value: 'naranja'),
tarjetaShopping(value: 'targeta-shopping'),
unionChinaPay(value: 'union-china-pay'),
unionPay(value: 'unionpay'),
visa(value: 'visa'),
mIR(value: 'mir'),
maestro(value: 'maestro'),
Expand Down
3 changes: 2 additions & 1 deletion lib/src/enums/execution_method.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ enum ExecutionMethod {
pUT(value: 'PUT'),
pATCH(value: 'PATCH'),
dELETE(value: 'DELETE'),
oPTIONS(value: 'OPTIONS');
oPTIONS(value: 'OPTIONS'),
hEAD(value: 'HEAD');

const ExecutionMethod({required this.value});

Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: appwrite
version: 18.0.0
version: 19.0.0
description: Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API
homepage: https://appwrite.io
repository: https://github.com/appwrite/sdk-for-flutter
Expand Down
14 changes: 14 additions & 0 deletions test/query_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,13 @@ void main() {
expect(query['method'], 'createdAfter');
});

test('returns createdBetween', () {
final query = jsonDecode(Query.createdBetween('2023-01-01', '2023-12-31'));
expect(query['attribute'], null);
expect(query['values'], ['2023-01-01', '2023-12-31']);
expect(query['method'], 'createdBetween');
});

test('returns updatedBefore', () {
final query = jsonDecode(Query.updatedBefore('2023-01-01'));
expect(query['attribute'], null);
Expand All @@ -292,5 +299,12 @@ void main() {
expect(query['values'], ['2023-01-01']);
expect(query['method'], 'updatedAfter');
});

test('returns updatedBetween', () {
final query = jsonDecode(Query.updatedBetween('2023-01-01', '2023-12-31'));
expect(query['attribute'], null);
expect(query['values'], ['2023-01-01', '2023-12-31']);
expect(query['method'], 'updatedBetween');
});
}