diff --git a/packages/cloud_firestore/CHANGELOG.md b/packages/cloud_firestore/CHANGELOG.md index 0dd48a7d10c7..b078cfd0a41d 100644 --- a/packages/cloud_firestore/CHANGELOG.md +++ b/packages/cloud_firestore/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.12.7 + +* Methods of `Transaction` no longer require `await`. +* Added documentation to methods of `Transaction`. +* Removed an unnecessary log on Android. +* Added an integration test for rapidly incrementing field value. + ## 0.12.6 * Support for `orderBy` on map fields (e.g. `orderBy('cake.flavor')`) for diff --git a/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java b/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java index d0606a262ec3..5254b8b1493d 100644 --- a/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java +++ b/packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java @@ -398,7 +398,7 @@ public void error( String errorMessage, Object errorDetails) { transactionTCS.trySetException( - new Exception("Do transaction failed.")); + new Exception("DoTransaction failed: " + errorMessage)); } @Override @@ -528,7 +528,6 @@ protected Void doInBackground(Void... voids) { new Runnable() { @Override public void run() { - Log.d(TAG, "sending set success"); result.success(null); } }); diff --git a/packages/cloud_firestore/example/test_driver/cloud_firestore.dart b/packages/cloud_firestore/example/test_driver/cloud_firestore.dart index 8926dcd0dcc4..d7d85db5b000 100644 --- a/packages/cloud_firestore/example/test_driver/cloud_firestore.dart +++ b/packages/cloud_firestore/example/test_driver/cloud_firestore.dart @@ -90,6 +90,16 @@ void main() { }); snapshot = await ref.get(); expect(snapshot.data['message'], 42.1); + + // Call several times without awaiting the result + await Future.wait(List>.generate( + 3, + (int i) => ref.updateData({ + 'message': FieldValue.increment(i), + }), + )); + snapshot = await ref.get(); + expect(snapshot.data['message'], 45.1); await ref.delete(); }); @@ -107,11 +117,12 @@ void main() { final Map updatedData = Map.from(snapshot.data); updatedData['message'] = 'testing2'; - await tx.update(ref, updatedData); + tx.update(ref, updatedData); // calling await here is optional return updatedData; }, ); expect(result['message'], 'testing2'); + await ref.delete(); final DocumentSnapshot nonexistentSnapshot = await ref.get(); expect(nonexistentSnapshot.data, null); diff --git a/packages/cloud_firestore/lib/src/firestore.dart b/packages/cloud_firestore/lib/src/firestore.dart index e91bc47261ef..c2fa17720995 100644 --- a/packages/cloud_firestore/lib/src/firestore.dart +++ b/packages/cloud_firestore/lib/src/firestore.dart @@ -25,9 +25,11 @@ class Firestore { _documentObservers[call.arguments['handle']].add(snapshot); } else if (call.method == 'DoTransaction') { final int transactionId = call.arguments['transactionId']; - return _transactionHandlers[transactionId]( - Transaction(transactionId, this), - ); + final Transaction transaction = Transaction(transactionId, this); + final dynamic result = + await _transactionHandlers[transactionId](transaction); + await transaction._finish(); + return result; } }); _initialized = true; diff --git a/packages/cloud_firestore/lib/src/transaction.dart b/packages/cloud_firestore/lib/src/transaction.dart index d42c89d9d59e..d13e3f19f9b2 100644 --- a/packages/cloud_firestore/lib/src/transaction.dart +++ b/packages/cloud_firestore/lib/src/transaction.dart @@ -12,8 +12,17 @@ class Transaction { int _transactionId; Firestore _firestore; + List> _pendingResults = >[]; + Future _finish() => Future.wait(_pendingResults); - Future get(DocumentReference documentReference) async { + /// Reads the document referenced by the provided DocumentReference. + Future get(DocumentReference documentReference) { + final Future result = _get(documentReference); + _pendingResults.add(result); + return result; + } + + Future _get(DocumentReference documentReference) async { final Map result = await Firestore.channel .invokeMapMethod('Transaction#get', { 'app': _firestore.app.name, @@ -32,7 +41,17 @@ class Transaction { } } - Future delete(DocumentReference documentReference) async { + /// Deletes the document referred to by the provided [documentReference]. + /// + /// Awaiting the returned [Future] is optional and will be done automatically + /// when the transaction handler completes. + Future delete(DocumentReference documentReference) { + final Future result = _delete(documentReference); + _pendingResults.add(result); + return result; + } + + Future _delete(DocumentReference documentReference) async { return Firestore.channel .invokeMethod('Transaction#delete', { 'app': _firestore.app.name, @@ -41,8 +60,20 @@ class Transaction { }); } + /// Updates fields in the document referred to by [documentReference]. + /// The update will fail if applied to a document that does not exist. + /// + /// Awaiting the returned [Future] is optional and will be done automatically + /// when the transaction handler completes. Future update( DocumentReference documentReference, Map data) async { + final Future result = _update(documentReference, data); + _pendingResults.add(result); + return result; + } + + Future _update( + DocumentReference documentReference, Map data) async { return Firestore.channel .invokeMethod('Transaction#update', { 'app': _firestore.app.name, @@ -52,7 +83,20 @@ class Transaction { }); } + /// Writes to the document referred to by the provided [DocumentReference]. + /// If the document does not exist yet, it will be created. If you pass + /// SetOptions, the provided data can be merged into the existing document. + /// + /// Awaiting the returned [Future] is optional and will be done automatically + /// when the transaction handler completes. Future set( + DocumentReference documentReference, Map data) { + final Future result = _set(documentReference, data); + _pendingResults.add(result); + return result; + } + + Future _set( DocumentReference documentReference, Map data) async { return Firestore.channel .invokeMethod('Transaction#set', { diff --git a/packages/cloud_firestore/pubspec.yaml b/packages/cloud_firestore/pubspec.yaml index 9c70101f356f..b488e30ccff8 100755 --- a/packages/cloud_firestore/pubspec.yaml +++ b/packages/cloud_firestore/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for Cloud Firestore, a cloud-hosted, noSQL database live synchronization and offline support on Android and iOS. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/cloud_firestore -version: 0.12.6 +version: 0.12.7 flutter: plugin: diff --git a/packages/firebase_database/CHANGELOG.md b/packages/firebase_database/CHANGELOG.md index c08e59b44483..3f8772587402 100644 --- a/packages/firebase_database/CHANGELOG.md +++ b/packages/firebase_database/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.0.4 + +* Fix transactions on + ## 3.0.3 * Automatically use version from pubspec.yaml when reporting usage to Firebase.