Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
# Change Log

## 21.4.0
## 22.0.0

* Added upsert() to DocumentChannel and RowChannel to support upsert operations on documents and rows.
* Added Query.contains, Query.containsAny, and Query.containsAll for enhanced filtering capabilities.

## 21.3.0

* Added memberships realtime channel helper
* Breaking: Channel API no longer defaults to '*'; explicit IDs required.
* Updated: Docs and README reflect 21.4.1; TTL examples added.

## 21.1.0

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite)
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord)

**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).**
**This SDK is compatible with Appwrite server version latest. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-flutter/releases).**
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 compatibility sentence wording for clarity.

The phrase “version latest” is awkward and can confuse readers.

✏️ Suggested wording fix
-**This SDK is compatible with Appwrite server version latest. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-flutter/releases).**
+**This SDK is compatible with the latest Appwrite server version. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-flutter/releases).**
📝 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
**This SDK is compatible with Appwrite server version latest. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-flutter/releases).**
**This SDK is compatible with the latest Appwrite server version. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-flutter/releases).**
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` at line 10, Update the awkward wording in the README sentence that
currently reads "**This SDK is compatible with Appwrite server version latest.
For older versions, please check [previous
releases](https://github.com/appwrite/sdk-for-flutter/releases).**" — change
"version latest" to a clearer phrase such as "the latest version" (e.g., "This
SDK is compatible with the latest Appwrite server version. For older versions,
please check previous releases.") so the compatibility statement is
grammatically correct and unambiguous.


Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Flutter SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)

Expand All @@ -19,7 +19,7 @@ Add this to your package's `pubspec.yaml` file:

```yml
dependencies:
appwrite: ^21.4.0
appwrite: ^22.0.0
```

You can install packages from the command line:
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/list-documents.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ DocumentList result = await databases.listDocuments(
queries: [], // optional
transactionId: '<TRANSACTION_ID>', // optional
total: false, // optional
ttl: 0, // optional
);
```
1 change: 1 addition & 0 deletions docs/examples/tablesdb/list-rows.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ RowList result = await tablesDB.listRows(
queries: [], // optional
transactionId: '<TRANSACTION_ID>', // optional
total: false, // optional
ttl: 0, // optional
);
```
28 changes: 17 additions & 11 deletions lib/channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ class _Membership {}
class _Resolved {}

// Helper function for normalizing ID
String _normalize(String id) => id.trim().isEmpty ? '*' : id.trim();
String _normalize(String id) {
final trimmed = id.trim();
if (trimmed.isEmpty) {
throw ArgumentError('Channel ID is required');
}
return trimmed;
}

/// Channel class with generic type parameter for type-safe method chaining
class Channel<T> {
Expand Down Expand Up @@ -58,25 +64,25 @@ class Channel<T> {
String toString() => _segments.join('.');

// --- ROOT FACTORIES ---
static Channel<_Database> database([String id = '*']) =>
static Channel<_Database> database(String id) =>
Channel<_Database>._(['databases', _normalize(id)]);

static Channel<_TablesDB> tablesdb([String id = '*']) =>
static Channel<_TablesDB> tablesdb(String id) =>
Channel<_TablesDB>._(['tablesdb', _normalize(id)]);

static Channel<_Bucket> bucket([String id = '*']) =>
static Channel<_Bucket> bucket(String id) =>
Channel<_Bucket>._(['buckets', _normalize(id)]);

static Channel<_Execution> execution([String id = '*']) =>
static Channel<_Execution> execution(String id) =>
Channel<_Execution>._(['executions', _normalize(id)]);

static Channel<_Func> function([String id = '*']) =>
static Channel<_Func> function(String id) =>
Channel<_Func>._(['functions', _normalize(id)]);

static Channel<_Team> team([String id = '*']) =>
static Channel<_Team> team(String id) =>
Channel<_Team>._(['teams', _normalize(id)]);

static Channel<_Membership> membership([String id = '*']) =>
static Channel<_Membership> membership(String id) =>
Channel<_Membership>._(['memberships', _normalize(id)]);

static String account() => 'account';
Expand All @@ -95,8 +101,8 @@ class Channel<T> {

/// Only available on Channel<_Database>
extension DatabaseChannel on Channel<_Database> {
Channel<_Collection> collection([String? id]) =>
_next<_Collection>('collections', id ?? '*');
Channel<_Collection> collection(String id) =>
_next<_Collection>('collections', id);
}

/// Only available on Channel<_Collection>
Expand All @@ -109,7 +115,7 @@ extension CollectionChannel on Channel<_Collection> {

/// Only available on Channel<_TablesDB>
extension TablesDBChannel on Channel<_TablesDB> {
Channel<_Table> table([String? id]) => _next<_Table>('tables', id ?? '*');
Channel<_Table> table(String id) => _next<_Table>('tables', id);
}

/// Only available on Channel<_Table>
Expand Down
4 changes: 3 additions & 1 deletion lib/services/databases.dart
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ class Databases extends Service {
required String collectionId,
List<String>? queries,
String? transactionId,
bool? total}) async {
bool? total,
int? ttl}) async {
final String apiPath =
'/databases/{databaseId}/collections/{collectionId}/documents'
.replaceAll('{databaseId}', databaseId)
Expand All @@ -134,6 +135,7 @@ class Databases extends Service {
if (queries != null) 'queries': queries,
if (transactionId != null) 'transactionId': transactionId,
if (total != null) 'total': total,
if (ttl != null) 'ttl': ttl,
};

final Map<String, String> apiHeaders = {};
Expand Down
4 changes: 3 additions & 1 deletion lib/services/tables_db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ class TablesDB extends Service {
required String tableId,
List<String>? queries,
String? transactionId,
bool? total}) async {
bool? total,
int? ttl}) async {
final String apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows'
.replaceAll('{databaseId}', databaseId)
.replaceAll('{tableId}', tableId);
Expand All @@ -129,6 +130,7 @@ class TablesDB extends Service {
if (queries != null) 'queries': queries,
if (transactionId != null) 'transactionId': transactionId,
if (total != null) 'total': total,
if (ttl != null) 'ttl': ttl,
};

final Map<String, String> apiHeaders = {};
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': '21.4.0',
'x-sdk-version': '22.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': '21.4.0',
'x-sdk-version': '22.0.0',
'X-Appwrite-Response-Format': '1.8.0',
};

Expand Down
2 changes: 1 addition & 1 deletion lib/src/models/document.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Document implements Model {
/// Document ID.
final String $id;

/// Document automatically incrementing ID.
/// Document sequence ID.
final int $sequence;

/// Collection ID.
Expand Down
2 changes: 1 addition & 1 deletion lib/src/models/row.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Row implements Model {
/// Row ID.
final String $id;

/// Row automatically incrementing ID.
/// Row sequence ID.
final int $sequence;

/// Table ID.
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: 21.4.0
version: 22.0.0
description: Appwrite is an open-source self-hosted backend server that abstracts and simplifies 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
46 changes: 20 additions & 26 deletions test/channel_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,13 @@ import 'package:flutter_test/flutter_test.dart';

void main() {
group('database()', () {
test('returns database channel with defaults', () {
expect(Channel.database().collection().document().toString(),
'databases.*.collections.*.documents');
test('throws when database id is missing', () {
expect(() => Channel.database(''), throwsArgumentError);
});

test('returns database channel with specific IDs', () {
expect(
Channel.database('db1')
.collection('col1')
.document('doc1')
.toString(),
'databases.db1.collections.col1.documents.doc1');
expect(Channel.database('db1').collection('col1').document().toString(),
'databases.db1.collections.col1.documents');
});

test('returns database channel with action', () {
Expand All @@ -39,14 +34,13 @@ void main() {
});

group('tablesdb()', () {
test('returns tablesdb channel with defaults', () {
expect(Channel.tablesdb().table().row().toString(),
'tablesdb.*.tables.*.rows');
test('throws when tablesdb id is missing', () {
expect(() => Channel.tablesdb(''), throwsArgumentError);
});

test('returns tablesdb channel with specific IDs', () {
expect(Channel.tablesdb('db1').table('table1').row('row1').toString(),
'tablesdb.db1.tables.table1.rows.row1');
expect(Channel.tablesdb('db1').table('table1').row().toString(),
'tablesdb.db1.tables.table1.rows');
});

test('returns tablesdb channel with action', () {
Expand All @@ -67,13 +61,13 @@ void main() {
});

group('bucket()', () {
test('returns buckets channel with defaults', () {
expect(Channel.bucket().file().toString(), 'buckets.*.files');
test('throws when bucket id is missing', () {
expect(() => Channel.bucket(''), throwsArgumentError);
});

test('returns buckets channel with specific IDs', () {
expect(Channel.bucket('bucket1').file('file1').toString(),
'buckets.bucket1.files.file1');
expect(
Channel.bucket('bucket1').file().toString(), 'buckets.bucket1.files');
});

test('returns buckets channel with action', () {
Expand All @@ -83,8 +77,8 @@ void main() {
});

group('functions()', () {
test('returns functions channel with defaults', () {
expect(Channel.function().toString(), 'functions.*');
test('throws when function id is missing', () {
expect(() => Channel.function(''), throwsArgumentError);
});

test('returns functions channel with specific IDs', () {
Expand All @@ -93,8 +87,8 @@ void main() {
});

group('executions()', () {
test('returns executions channel with defaults', () {
expect(Channel.execution().toString(), 'executions.*');
test('throws when execution id is missing', () {
expect(() => Channel.execution(''), throwsArgumentError);
});

test('returns executions channel with specific IDs', () {
Expand All @@ -103,8 +97,8 @@ void main() {
});

group('teams()', () {
test('returns teams channel with default', () {
expect(Channel.team().toString(), 'teams.*');
test('throws when team id is missing', () {
expect(() => Channel.team(''), throwsArgumentError);
});

test('returns teams channel with specific team ID', () {
Expand All @@ -117,8 +111,8 @@ void main() {
});

group('memberships()', () {
test('returns memberships channel with default', () {
expect(Channel.membership().toString(), 'memberships.*');
test('throws when membership id is missing', () {
expect(() => Channel.membership(''), throwsArgumentError);
});

test('returns memberships channel with specific membership ID', () {
Expand Down