diff --git a/packages/cloud_firestore/CHANGELOG.md b/packages/cloud_firestore/CHANGELOG.md index aa90bc057294..46f12dee2ad7 100644 --- a/packages/cloud_firestore/CHANGELOG.md +++ b/packages/cloud_firestore/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.2.8 +* Support for Query.getDocuments + ## 0.2.7 * Add transaction support. 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 4c41d5412ff2..050f3700088f 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 @@ -69,6 +69,45 @@ private DocumentReference getDocumentReference(Map arguments) { return FirebaseFirestore.getInstance().document(path); } + private Map parseQuerySnapshot(QuerySnapshot querySnapshot) { + if (querySnapshot == null) return new HashMap<>(); + Map data = new HashMap<>(); + List paths = new ArrayList<>(); + List> documents = new ArrayList<>(); + for (DocumentSnapshot document : querySnapshot.getDocuments()) { + paths.add(document.getReference().getPath()); + documents.add(document.getData()); + } + data.put("paths", paths); + data.put("documents", documents); + + List> documentChanges = new ArrayList<>(); + for (DocumentChange documentChange : querySnapshot.getDocumentChanges()) { + Map change = new HashMap<>(); + String type = null; + switch (documentChange.getType()) { + case ADDED: + type = "DocumentChangeType.added"; + break; + case MODIFIED: + type = "DocumentChangeType.modified"; + break; + case REMOVED: + type = "DocumentChangeType.removed"; + break; + } + change.put("type", type); + change.put("oldIndex", documentChange.getOldIndex()); + change.put("newIndex", documentChange.getNewIndex()); + change.put("document", documentChange.getDocument().getData()); + change.put("path", documentChange.getDocument().getReference().getPath()); + documentChanges.add(change); + } + data.put("documentChanges", documentChanges); + + return data; + } + private Transaction getTransaction(Map arguments) { return transactions.get((Integer) arguments.get("transactionId")); } @@ -161,41 +200,9 @@ public void onEvent(QuerySnapshot querySnapshot, FirebaseFirestoreException e) { // TODO: send error System.out.println(e); } - Map arguments = new HashMap<>(); - arguments.put("handle", handle); - - List paths = new ArrayList<>(); - List> documents = new ArrayList<>(); - for (DocumentSnapshot document : querySnapshot.getDocuments()) { - paths.add(document.getReference().getPath()); - documents.add(document.getData()); - } - arguments.put("paths", paths); - arguments.put("documents", documents); - List> documentChanges = new ArrayList<>(); - for (DocumentChange documentChange : querySnapshot.getDocumentChanges()) { - Map change = new HashMap<>(); - String type = null; - switch (documentChange.getType()) { - case ADDED: - type = "DocumentChangeType.added"; - break; - case MODIFIED: - type = "DocumentChangeType.modified"; - break; - case REMOVED: - type = "DocumentChangeType.removed"; - break; - } - change.put("type", type); - change.put("oldIndex", documentChange.getOldIndex()); - change.put("newIndex", documentChange.getNewIndex()); - change.put("document", documentChange.getDocument().getData()); - change.put("path", documentChange.getDocument().getReference().getPath()); - documentChanges.add(change); - } - arguments.put("documentChanges", documentChanges); + Map arguments = parseQuerySnapshot(querySnapshot); + arguments.put("handle", handle); channel.invokeMethod("QuerySnapshot", arguments); } @@ -387,6 +394,27 @@ protected Void doInBackground(Void... voids) { result.success(null); break; } + case "Query#getDocuments": + { + Map arguments = call.arguments(); + Query query = getQuery(arguments); + Task task = query.get(); + task.addOnSuccessListener( + new OnSuccessListener() { + @Override + public void onSuccess(QuerySnapshot querySnapshot) { + result.success(parseQuerySnapshot(querySnapshot)); + } + }) + .addOnFailureListener( + new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + result.error("Error performing getDocuments", e.getMessage(), null); + } + }); + break; + } case "DocumentReference#setData": { Map arguments = call.arguments(); diff --git a/packages/cloud_firestore/ios/Classes/CloudFirestorePlugin.m b/packages/cloud_firestore/ios/Classes/CloudFirestorePlugin.m index f77bd12c025e..6518d67af6f1 100644 --- a/packages/cloud_firestore/ios/Classes/CloudFirestorePlugin.m +++ b/packages/cloud_firestore/ios/Classes/CloudFirestorePlugin.m @@ -78,6 +78,42 @@ - (FlutterError *)flutterError { return query; } +NSDictionary *parseQuerySnapshot(FIRQuerySnapshot *snapshot) { + NSMutableArray *paths = [NSMutableArray array]; + NSMutableArray *documents = [NSMutableArray array]; + for (FIRDocumentSnapshot *document in snapshot.documents) { + [paths addObject:document.reference.path]; + [documents addObject:document.data]; + } + NSMutableArray *documentChanges = [NSMutableArray array]; + for (FIRDocumentChange *documentChange in snapshot.documentChanges) { + NSString *type; + switch (documentChange.type) { + case FIRDocumentChangeTypeAdded: + type = @"DocumentChangeType.added"; + break; + case FIRDocumentChangeTypeModified: + type = @"DocumentChangeType.modified"; + break; + case FIRDocumentChangeTypeRemoved: + type = @"DocumentChangeType.removed"; + break; + } + [documentChanges addObject:@{ + @"type" : type, + @"document" : documentChange.document.data, + @"path" : documentChange.document.reference.path, + @"oldIndex" : [NSNumber numberWithInt:documentChange.oldIndex], + @"newIndex" : [NSNumber numberWithInt:documentChange.newIndex], + }]; + } + return @{ + @"paths" : paths, + @"documentChanges" : documentChanges, + @"documents" : documents, + }; +} + @interface FLTCloudFirestorePlugin () @property(nonatomic, retain) FlutterMethodChannel *channel; @end @@ -248,41 +284,9 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result id listener = [query addSnapshotListener:^(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error) { if (error) result(error.flutterError); - NSMutableArray *paths = [NSMutableArray array]; - NSMutableArray *documents = [NSMutableArray array]; - for (FIRDocumentSnapshot *document in snapshot.documents) { - [paths addObject:document.reference.path]; - [documents addObject:document.data]; - } - NSMutableArray *documentChanges = [NSMutableArray array]; - for (FIRDocumentChange *documentChange in snapshot.documentChanges) { - NSString *type; - switch (documentChange.type) { - case FIRDocumentChangeTypeAdded: - type = @"DocumentChangeType.added"; - break; - case FIRDocumentChangeTypeModified: - type = @"DocumentChangeType.modified"; - break; - case FIRDocumentChangeTypeRemoved: - type = @"DocumentChangeType.removed"; - break; - } - [documentChanges addObject:@{ - @"type" : type, - @"document" : documentChange.document.data, - @"path" : documentChange.document.reference.path, - @"oldIndex" : [NSNumber numberWithInt:documentChange.oldIndex], - @"newIndex" : [NSNumber numberWithInt:documentChange.newIndex], - }]; - } - [self.channel invokeMethod:@"QuerySnapshot" - arguments:@{ - @"handle" : handle, - @"paths" : paths, - @"documents" : documents, - @"documentChanges" : documentChanges - }]; + NSMutableDictionary *arguments = [parseQuerySnapshot(snapshot) mutableCopy]; + [arguments setObject:handle forKey:@"handle"]; + [self.channel invokeMethod:@"QuerySnapshot" arguments:arguments]; }]; _listeners[handle] = listener; result(handle); @@ -302,6 +306,20 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result }]; _listeners[handle] = listener; result(handle); + } else if ([@"Query#getDocuments" isEqualToString:call.method]) { + FIRQuery *query; + @try { + query = getQuery(call.arguments); + } @catch (NSException *exception) { + result([FlutterError errorWithCode:@"invalid_query" + message:[exception name] + details:[exception reason]]); + } + [query getDocumentsWithCompletion:^(FIRQuerySnapshot *_Nullable snapshot, + NSError *_Nullable error) { + if (error) result(error.flutterError); + result(parseQuerySnapshot(snapshot)); + }]; } else if ([@"Query#removeListener" isEqualToString:call.method]) { NSNumber *handle = call.arguments[@"handle"]; [[_listeners objectForKey:handle] remove]; diff --git a/packages/cloud_firestore/lib/src/query.dart b/packages/cloud_firestore/lib/src/query.dart index 9a02c041551a..07e7b98798e6 100644 --- a/packages/cloud_firestore/lib/src/query.dart +++ b/packages/cloud_firestore/lib/src/query.dart @@ -79,6 +79,18 @@ class Query { return controller.stream; } + /// Fetch the documents for this query + Future getDocuments() async { + final Map data = await Firestore.channel.invokeMethod( + 'Query#getDocuments', + { + 'path': path, + 'parameters': _parameters, + }, + ); + return new QuerySnapshot._(data, _firestore); + } + /// Obtains a CollectionReference corresponding to this query's location. CollectionReference reference() => new CollectionReference._(_firestore, _pathComponents); diff --git a/packages/cloud_firestore/test/cloud_firestore_test.dart b/packages/cloud_firestore/test/cloud_firestore_test.dart index 59f2b7a94aa0..7068c02ddbfa 100755 --- a/packages/cloud_firestore/test/cloud_firestore_test.dart +++ b/packages/cloud_firestore/test/cloud_firestore_test.dart @@ -63,6 +63,19 @@ void main() { (_) {}, ); return handle; + case 'Query#getDocuments': + return { + 'paths': ["${methodCall.arguments['path']}/0"], + 'documents': [kMockDocumentSnapshotData], + 'documentChanges': [ + { + 'oldIndex': -1, + 'newIndex': 0, + 'type': 'DocumentChangeType.added', + 'document': kMockDocumentSnapshotData, + }, + ], + }; case 'DocumentReference#setData': return true; case 'DocumentReference#get': @@ -407,5 +420,32 @@ void main() { expect(colRef.path, 'foo/bar/baz'); }); }); + + group('Query', () { + test('getDocuments', () async { + final QuerySnapshot snapshot = await collectionReference.getDocuments(); + final DocumentSnapshot document = snapshot.documents.first; + expect( + log, + equals( + [ + isMethodCall( + 'Query#getDocuments', + arguments: { + 'path': 'foo', + 'parameters': { + 'where': >[], + 'orderBy': >[], + }, + }, + ), + ], + ), + ); + expect(document.documentID, equals('0')); + expect(document.reference.path, equals('foo/0')); + expect(document.data, equals(kMockDocumentSnapshotData)); + }); + }); }); }