diff --git a/CHANGELOG.md b/CHANGELOG.md index db327d3..1f9d9d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index 6018da1..7d3a782 100644 --- a/README.md +++ b/README.md @@ -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).** 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) @@ -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: diff --git a/docs/examples/databases/list-documents.md b/docs/examples/databases/list-documents.md index ca690a5..531be6a 100644 --- a/docs/examples/databases/list-documents.md +++ b/docs/examples/databases/list-documents.md @@ -13,5 +13,6 @@ DocumentList result = await databases.listDocuments( queries: [], // optional transactionId: '', // optional total: false, // optional + ttl: 0, // optional ); ``` diff --git a/docs/examples/tablesdb/list-rows.md b/docs/examples/tablesdb/list-rows.md index 1d535f8..a2637a9 100644 --- a/docs/examples/tablesdb/list-rows.md +++ b/docs/examples/tablesdb/list-rows.md @@ -13,5 +13,6 @@ RowList result = await tablesDB.listRows( queries: [], // optional transactionId: '', // optional total: false, // optional + ttl: 0, // optional ); ``` diff --git a/lib/channel.dart b/lib/channel.dart index c38833c..064c44d 100644 --- a/lib/channel.dart +++ b/lib/channel.dart @@ -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 { @@ -58,25 +64,25 @@ class Channel { 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'; @@ -95,8 +101,8 @@ class Channel { /// 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> @@ -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> diff --git a/lib/services/databases.dart b/lib/services/databases.dart index e7db8c2..21c2866 100644 --- a/lib/services/databases.dart +++ b/lib/services/databases.dart @@ -124,7 +124,8 @@ class Databases extends Service { required String collectionId, List? queries, String? transactionId, - bool? total}) async { + bool? total, + int? ttl}) async { final String apiPath = '/databases/{databaseId}/collections/{collectionId}/documents' .replaceAll('{databaseId}', databaseId) @@ -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 apiHeaders = {}; diff --git a/lib/services/tables_db.dart b/lib/services/tables_db.dart index 1d9c398..c3478b9 100644 --- a/lib/services/tables_db.dart +++ b/lib/services/tables_db.dart @@ -120,7 +120,8 @@ class TablesDB extends Service { required String tableId, List? 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); @@ -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 apiHeaders = {}; diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 17828b8..148608b 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -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', }; diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 2b01050..6870129 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -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', }; diff --git a/lib/src/models/document.dart b/lib/src/models/document.dart index 84790f5..e3b9f3c 100644 --- a/lib/src/models/document.dart +++ b/lib/src/models/document.dart @@ -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. diff --git a/lib/src/models/row.dart b/lib/src/models/row.dart index 28a8896..32d8a38 100644 --- a/lib/src/models/row.dart +++ b/lib/src/models/row.dart @@ -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. diff --git a/pubspec.yaml b/pubspec.yaml index e699240..939c4b9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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 diff --git a/test/channel_test.dart b/test/channel_test.dart index 07a265a..84b1112 100644 --- a/test/channel_test.dart +++ b/test/channel_test.dart @@ -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', () { @@ -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', () { @@ -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', () { @@ -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', () { @@ -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', () { @@ -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', () { @@ -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', () {