Skip to content

Commit 1586a54

Browse files
committed
🎉 Add Partial Updates
1 parent ca94771 commit 1586a54

File tree

4 files changed

+50
-8
lines changed

4 files changed

+50
-8
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## [0.0.5] - 2024-12-10
2+
3+
### Improvements
4+
- Add `updatedFields` save param to facilitate partial updates (PATCH).
5+
- Updated the documentation to showcase the usage of this param.
6+
17
## [0.0.4] - 2024-12-08
28

39
### Improvements

README.md

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ A Flutter Data adapter for Appwrite that provides offline support, real-time upd
88
- 📱 **Offline Support**: Work with your data even when offline
99
-**Real-time Updates**: Listen to changes in your Appwrite collections in real-time
1010
- 🔍 **Advanced Querying**: Supported operators: '==', '!=', '>', '>=', '<', '<=', 'startsWith', 'endsWith', 'contains', 'search', 'between', 'in', 'isNull', 'isNotNull'.
11-
- 🎯 **Type-safe**: Fully typed models and queries
11+
- 🎯 **Type-safe**: Fully typed models, queries, & partial updates
1212
- 🪄 **Easy Integration**: Simple setup process with minimal configuration
1313

1414
## Prerequisites
@@ -27,7 +27,7 @@ Add this to your package's pubspec.yaml file:
2727

2828
```yaml
2929
dependencies:
30-
appwrite_offline: ^0.0.3
30+
appwrite_offline: ^0.0.5
3131
```
3232
3333
## Setup
@@ -92,6 +92,12 @@ class Product extends DataModel<Product> {
9292
dart run build_runner build -d
9393
```
9494

95+
OR
96+
97+
```bash
98+
dart run build_runner watch
99+
```
100+
95101
## Usage
96102

97103
### Basic Operations
@@ -100,7 +106,7 @@ dart run build_runner build -d
100106
class ProductsScreen extends ConsumerWidget {
101107
@override
102108
Widget build(BuildContext context, WidgetRef ref) {
103-
// Watch all products with offline support
109+
// Watch all products with offline sync support
104110
final productsState = ref.products.watchAll(
105111
syncLocal: true,
106112
);
@@ -141,12 +147,23 @@ class ProductFormScreen extends ConsumerWidget {
141147
name: 'New Product',
142148
price: 99.99,
143149
).save();
144-
150+
145151
// Update existing product
146152
final updatedProduct = await Product(
147153
name: 'Updated Product',
148154
price: 149.99,
149155
).withKeyOf(existingProduct).save();
156+
157+
// Partially update existing product
158+
final updatedProduct = await Product(
159+
name: 'Product Name',
160+
price: 239.99,
161+
).withKeyOf(existingProduct).save(
162+
params: {
163+
"updatedFields": jsonEncode(['price']),
164+
// This informs the adapter to only send these fields, hence improving performance
165+
},
166+
);
150167
},
151168
child: Text('Save Product'),
152169
);

lib/adapters/appwrite.dart

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'dart:convert';
66
import 'package:appwrite_offline/config.dart';
77
import 'package:appwrite_offline/extensions/framework.dart';
88
import 'package:appwrite_offline/models.dart';
9+
import 'package:flutter/foundation.dart' show debugPrint;
910
import 'package:flutter_data/flutter_data.dart';
1011
import 'package:appwrite/appwrite.dart';
1112

@@ -179,7 +180,6 @@ mixin AppwriteAdapter<T extends DataModel<T>> on RemoteAdapter<T> {
179180
uri.pathSegments.length > 2 ? uri.pathSegments[2] : null;
180181

181182
dynamic response;
182-
183183
Map? bodyData = body != null ? json.decode(body as String) : null;
184184
Set<String> keysToRemove = {'id', 'createdAt', 'updatedAt'};
185185
bodyData?.removeWhere(
@@ -263,14 +263,16 @@ mixin AppwriteAdapter<T extends DataModel<T>> on RemoteAdapter<T> {
263263
break;
264264
case DataRequestMethod.PUT:
265265
case DataRequestMethod.PATCH:
266-
if (documentId == null) {
266+
if (documentId == null || bodyData == null) {
267267
throw Exception('Document ID is required for PATCH operations');
268268
}
269+
final updateData = _parsePartialUpdate(
270+
queryParams: uri.queryParameters, body: bodyData);
269271
final updatedDoc = await _databases.updateDocument(
270272
databaseId: databaseId,
271273
collectionId: collectionId,
272274
documentId: documentId,
273-
data: bodyData,
275+
data: updateData,
274276
);
275277
updatedDoc.data.addAll({
276278
"id": updatedDoc.$id,
@@ -361,6 +363,23 @@ mixin AppwriteAdapter<T extends DataModel<T>> on RemoteAdapter<T> {
361363
return commonExceptions.any(err.contains);
362364
}
363365

366+
/// Parses updatedFields from query parameters
367+
///
368+
/// And Returns only a new request body with only updated fields
369+
Map _parsePartialUpdate(
370+
{required Map<String, String> queryParams, required Map body}) {
371+
if (!queryParams.containsKey('updatedFields')) {
372+
return body;
373+
}
374+
375+
List updatedFields = json.decode(queryParams['updatedFields']!);
376+
Set keysToRemove =
377+
body.keys.where((key) => !updatedFields.contains(key)).toSet();
378+
body.removeWhere(
379+
(key, value) => value == null || keysToRemove.contains(key));
380+
return body;
381+
}
382+
364383
/// Parses permission rules from query parameters
365384
///
366385
/// Supported permission types:

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: appwrite_offline
22
description: "A Flutter Data adapter for Appwrite that provides offline support, real-time updates, and seamless integration with Flutter Data's powerful features."
3-
version: 0.0.4
3+
version: 0.0.5
44
homepage: https://github.com/cybroidtech/appwrite_offline
55
repository: https://github.com/cybroidtech/appwrite_offline
66
issue_tracker: https://github.com/cybroidtech/appwrite_offline/issues

0 commit comments

Comments
 (0)