Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9981b50
[cloud_firestore] add support for MetadataChanges
long1eu Jul 27, 2019
8f4835a
Merge branch 'master' of https://github.com/flutter/plugins
long1eu Jul 27, 2019
f2a76ff
fix: formatting issue
long1eu Jul 27, 2019
55302f9
Revert file that shouldn't be changed
collinjackson Jul 27, 2019
095ea23
Revert change to example that would result in dead code
collinjackson Jul 27, 2019
15b8862
Update to includeMetadataChanges
collinjackson Jul 27, 2019
4a246b0
Revert "Revert change to example that would result in dead code"
collinjackson Jul 27, 2019
dab7bd2
fix tests
collinjackson Jul 27, 2019
b0abf2f
Update tests
collinjackson Jul 27, 2019
77ea54f
Fix Java
collinjackson Jul 27, 2019
37388cb
Fix compile error
collinjackson Jul 27, 2019
718081f
Merge remote-tracking branch 'origin/master' into MetadataChanges
collinjackson Jul 28, 2019
5caddd5
Fix iOS compile
collinjackson Jul 28, 2019
0967909
fix: use the string values of the message when it's not null
long1eu Jul 28, 2019
532ab99
test: add integration test for metadata changes
long1eu Jul 28, 2019
2221d75
fix: remove unused import
long1eu Jul 28, 2019
6de4b7f
Merge remote-tracking branch 'origin/master' into MetadataChanges
collinjackson Jul 28, 2019
245e2f4
Revert project.pbxproj
collinjackson Jul 28, 2019
29a20eb
Added integration test
collinjackson Jul 28, 2019
b35d86e
Fix metadata test and lints
collinjackson Jul 28, 2019
90fdbce
Update cloud_firestore.dart
collinjackson Jul 28, 2019
4c942a2
Fix test + reformat
collinjackson Jul 29, 2019
f04610e
Merge remote-tracking branch 'origin/master'
long1eu Jul 29, 2019
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
7 changes: 7 additions & 0 deletions packages/cloud_firestore/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 0.12.9

* New optional `includeMetadataChanges` parameter added to `DocumentReference.snapshots()`
and `Query.snapshots()`
* Fix example app crash when the `message` field was not a string
* Internal renaming of method names.

## 0.12.8+1

* Add `metadata` to `QuerySnapshot`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.google.firebase.firestore.FirebaseFirestoreSettings;
import com.google.firebase.firestore.GeoPoint;
import com.google.firebase.firestore.ListenerRegistration;
import com.google.firebase.firestore.MetadataChanges;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QuerySnapshot;
import com.google.firebase.firestore.SetOptions;
Expand Down Expand Up @@ -624,22 +625,32 @@ public void run() {
int handle = nextListenerHandle++;
EventObserver observer = new EventObserver(handle);
observers.put(handle, observer);
listenerRegistrations.put(handle, getQuery(arguments).addSnapshotListener(observer));
MetadataChanges metadataChanges =
(Boolean) arguments.get("includeMetadataChanges")
? MetadataChanges.INCLUDE
: MetadataChanges.EXCLUDE;
listenerRegistrations.put(
handle, getQuery(arguments).addSnapshotListener(metadataChanges, observer));
result.success(handle);
break;
}
case "Query#addDocumentListener":
case "DocumentReference#addSnapshotListener":
{
Map<String, Object> arguments = call.arguments();
int handle = nextListenerHandle++;
DocumentObserver observer = new DocumentObserver(handle);
documentObservers.put(handle, observer);
MetadataChanges metadataChanges =
(Boolean) arguments.get("includeMetadataChanges")
? MetadataChanges.INCLUDE
: MetadataChanges.EXCLUDE;
listenerRegistrations.put(
handle, getDocumentReference(arguments).addSnapshotListener(observer));
handle,
getDocumentReference(arguments).addSnapshotListener(metadataChanges, observer));
result.success(handle);
break;
}
case "Query#removeListener":
case "removeListener":
{
Map<String, Object> arguments = call.arguments();
int handle = (Integer) arguments.get("handle");
Expand Down
7 changes: 6 additions & 1 deletion packages/cloud_firestore/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ class MessageList extends StatelessWidget {
itemCount: messageCount,
itemBuilder: (_, int index) {
final DocumentSnapshot document = snapshot.data.documents[index];
final dynamic message = document['message'];
return ListTile(
title: Text(document['message'] ?? '<No message retrieved>'),
title: Text(
message != null ? message.toString() : '<No message retrieved>',
),
subtitle: Text('Message ${index + 1} of $messageCount'),
);
},
Expand All @@ -54,7 +57,9 @@ class MessageList extends StatelessWidget {

class MyHomePage extends StatelessWidget {
MyHomePage({this.firestore});

final Firestore firestore;

CollectionReference get messages => firestore.collection('messages');

Future<void> _addMessage() async {
Expand Down
35 changes: 33 additions & 2 deletions packages/cloud_firestore/example/test_driver/cloud_firestore.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import 'dart:async';
import 'package:flutter_driver/driver_extension.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_driver/driver_extension.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
final Completer<String> completer = Completer<String>();
Expand Down Expand Up @@ -105,6 +106,36 @@ void main() {
await ref.delete();
});

test('includeMetadataChanges', () async {
final DocumentReference ref = firestore.collection('messages').document();
final Stream<DocumentSnapshot> snapshotWithoutMetadataChanges =
ref.snapshots(includeMetadataChanges: false).take(1);
final Stream<DocumentSnapshot> snapshotsWithMetadataChanges =
ref.snapshots(includeMetadataChanges: true).take(3);

ref.setData(<String, dynamic>{'hello': 'world'});

final DocumentSnapshot snapshot =
await snapshotWithoutMetadataChanges.first;
expect(snapshot.metadata.hasPendingWrites, true);
expect(snapshot.metadata.isFromCache, true);
expect(snapshot.data['hello'], 'world');

final List<DocumentSnapshot> snapshots =
await snapshotsWithMetadataChanges.toList();
expect(snapshots[0].metadata.hasPendingWrites, true);
expect(snapshots[0].metadata.isFromCache, true);
expect(snapshots[0].data['hello'], 'world');
expect(snapshots[1].metadata.hasPendingWrites, true);
expect(snapshots[1].metadata.isFromCache, false);
expect(snapshots[1].data['hello'], 'world');
expect(snapshots[2].metadata.hasPendingWrites, false);
expect(snapshots[2].metadata.isFromCache, false);
expect(snapshots[2].data['hello'], 'world');

await ref.delete();
});

test('runTransaction', () async {
final DocumentReference ref = firestore.collection('messages').document();
await ref.setData(<String, dynamic>{
Expand Down
71 changes: 42 additions & 29 deletions packages/cloud_firestore/ios/Classes/CloudFirestorePlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -526,39 +526,52 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
message:[exception name]
details:[exception reason]]);
}
NSNumber *includeMetadataChanges = call.arguments[@"includeMetadataChanges"];
id<FIRListenerRegistration> listener = [query
addSnapshotListener:^(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error) {
if (snapshot == nil) {
result(getFlutterError(error));
return;
}
NSMutableDictionary *arguments = [parseQuerySnapshot(snapshot) mutableCopy];
[arguments setObject:handle forKey:@"handle"];
[weakSelf.channel invokeMethod:@"QuerySnapshot" arguments:arguments];
}];
addSnapshotListenerWithIncludeMetadataChanges:includeMetadataChanges.boolValue
listener:^(FIRQuerySnapshot *_Nullable snapshot,
NSError *_Nullable error) {
if (snapshot == nil) {
result(getFlutterError(error));
return;
}
NSMutableDictionary *arguments =
[parseQuerySnapshot(snapshot) mutableCopy];
[arguments setObject:handle forKey:@"handle"];
[weakSelf.channel invokeMethod:@"QuerySnapshot"
arguments:arguments];
}];
_listeners[handle] = listener;
result(handle);
} else if ([@"Query#addDocumentListener" isEqualToString:call.method]) {
} else if ([@"DocumentReference#addSnapshotListener" isEqualToString:call.method]) {
__block NSNumber *handle = [NSNumber numberWithInt:_nextListenerHandle++];
FIRDocumentReference *document = getDocumentReference(call.arguments);
id<FIRListenerRegistration> listener =
[document addSnapshotListener:^(FIRDocumentSnapshot *snapshot, NSError *_Nullable error) {
if (snapshot == nil) {
result(getFlutterError(error));
return;
}
[weakSelf.channel invokeMethod:@"DocumentSnapshot"
arguments:@{
@"handle" : handle,
@"path" : snapshot ? snapshot.reference.path : [NSNull null],
@"data" : snapshot.exists ? snapshot.data : [NSNull null],
@"metadata" : snapshot ? @{
@"hasPendingWrites" : @(snapshot.metadata.hasPendingWrites),
@"isFromCache" : @(snapshot.metadata.isFromCache),
}
: [NSNull null],
}];
}];
NSNumber *includeMetadataChanges = call.arguments[@"includeMetadataChanges"];
id<FIRListenerRegistration> listener = [document
addSnapshotListenerWithIncludeMetadataChanges:includeMetadataChanges.boolValue
listener:^(FIRDocumentSnapshot *snapshot,
NSError *_Nullable error) {
if (snapshot == nil) {
result(getFlutterError(error));
return;
}
[weakSelf.channel
invokeMethod:@"DocumentSnapshot"
arguments:@{
@"handle" : handle,
@"path" : snapshot ? snapshot.reference.path
: [NSNull null],
@"data" : snapshot.exists ? snapshot.data
: [NSNull null],
@"metadata" : snapshot ? @{
@"hasPendingWrites" :
@(snapshot.metadata.hasPendingWrites),
@"isFromCache" :
@(snapshot.metadata.isFromCache),
}
: [NSNull null],
}];
}];
_listeners[handle] = listener;
result(handle);
} else if ([@"Query#getDocuments" isEqualToString:call.method]) {
Expand All @@ -581,7 +594,7 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
}
result(parseQuerySnapshot(snapshot));
}];
} else if ([@"Query#removeListener" isEqualToString:call.method]) {
} else if ([@"removeListener" isEqualToString:call.method]) {
NSNumber *handle = call.arguments[@"handle"];
[[_listeners objectForKey:handle] remove];
[_listeners removeObjectForKey:handle];
Expand Down
8 changes: 5 additions & 3 deletions packages/cloud_firestore/lib/src/document_reference.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,18 +116,20 @@ class DocumentReference {

/// Notifies of documents at this location
// TODO(jackson): Reduce code duplication with [Query]
Stream<DocumentSnapshot> snapshots() {
Stream<DocumentSnapshot> snapshots({bool includeMetadataChanges = false}) {
assert(includeMetadataChanges != null);
Future<int> _handle;
// It's fine to let the StreamController be garbage collected once all the
// subscribers have cancelled; this analyzer warning is safe to ignore.
StreamController<DocumentSnapshot> controller; // ignore: close_sinks
controller = StreamController<DocumentSnapshot>.broadcast(
onListen: () {
_handle = Firestore.channel.invokeMethod<int>(
'Query#addDocumentListener',
'DocumentReference#addSnapshotListener',
<String, dynamic>{
'app': firestore.app.name,
'path': path,
'includeMetadataChanges': includeMetadataChanges,
},
).then<int>((dynamic result) => result);
_handle.then((int handle) {
Expand All @@ -137,7 +139,7 @@ class DocumentReference {
onCancel: () {
_handle.then((int handle) async {
await Firestore.channel.invokeMethod<void>(
'Query#removeListener',
'removeListener',
<String, dynamic>{'handle': handle},
);
Firestore._documentObservers.remove(handle);
Expand Down
6 changes: 4 additions & 2 deletions packages/cloud_firestore/lib/src/query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ class Query {

/// Notifies of query results at this location
// TODO(jackson): Reduce code duplication with [DocumentReference]
Stream<QuerySnapshot> snapshots() {
Stream<QuerySnapshot> snapshots({bool includeMetadataChanges = false}) {
assert(includeMetadataChanges != null);
Future<int> _handle;
// It's fine to let the StreamController be garbage collected once all the
// subscribers have cancelled; this analyzer warning is safe to ignore.
Expand All @@ -64,6 +65,7 @@ class Query {
'path': _path,
'isCollectionGroup': _isCollectionGroup,
'parameters': _parameters,
'includeMetadataChanges': includeMetadataChanges,
},
).then<int>((dynamic result) => result);
_handle.then((int handle) {
Expand All @@ -73,7 +75,7 @@ class Query {
onCancel: () {
_handle.then((int handle) async {
await Firestore.channel.invokeMethod<void>(
'Query#removeListener',
'removeListener',
<String, dynamic>{'handle': handle},
);
Firestore._queryObservers.remove(handle);
Expand Down
2 changes: 1 addition & 1 deletion packages/cloud_firestore/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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 <[email protected]>
homepage: https://github.com/flutter/plugins/tree/master/packages/cloud_firestore
version: 0.12.8+1
version: 0.12.9

flutter:
plugin:
Expand Down
38 changes: 23 additions & 15 deletions packages/cloud_firestore/test/cloud_firestore_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ void main() {
);
});
return handle;
case 'Query#addDocumentListener':
case 'DocumentReference#addSnapshotListener':
final int handle = mockHandleId++;
// Wait before sending a message back.
// Otherwise the first request didn't have the time to finish.
Expand Down Expand Up @@ -330,8 +330,9 @@ void main() {
expect(collectionReference.path, equals('foo'));
});
test('listen', () async {
final QuerySnapshot snapshot =
await collectionReference.snapshots().first;
final QuerySnapshot snapshot = await collectionReference
.snapshots(includeMetadataChanges: true)
.first;
final DocumentSnapshot document = snapshot.documents[0];
expect(document.documentID, equals('0'));
expect(document.reference.path, equals('foo/0'));
Expand All @@ -348,11 +349,12 @@ void main() {
'parameters': <String, dynamic>{
'where': <List<dynamic>>[],
'orderBy': <List<dynamic>>[],
}
},
'includeMetadataChanges': true,
},
),
isMethodCall(
'Query#removeListener',
'removeListener',
arguments: <String, dynamic>{'handle': 0},
),
]);
Expand All @@ -379,11 +381,12 @@ void main() {
<dynamic>['createdAt', '<', 100],
],
'orderBy': <List<dynamic>>[],
}
},
'includeMetadataChanges': false,
},
),
isMethodCall(
'Query#removeListener',
'removeListener',
arguments: <String, dynamic>{'handle': 0},
),
]),
Expand Down Expand Up @@ -411,11 +414,12 @@ void main() {
<dynamic>['profile', '==', null],
],
'orderBy': <List<dynamic>>[],
}
},
'includeMetadataChanges': false,
},
),
isMethodCall(
'Query#removeListener',
'removeListener',
arguments: <String, dynamic>{'handle': 0},
),
]),
Expand Down Expand Up @@ -443,11 +447,12 @@ void main() {
'orderBy': <List<dynamic>>[
<dynamic>['createdAt', false]
],
}
},
'includeMetadataChanges': false,
},
),
isMethodCall(
'Query#removeListener',
'removeListener',
arguments: <String, dynamic>{'handle': 0},
),
]),
Expand All @@ -457,8 +462,10 @@ void main() {

group('DocumentReference', () {
test('listen', () async {
final DocumentSnapshot snapshot =
await firestore.document('path/to/foo').snapshots().first;
final DocumentSnapshot snapshot = await firestore
.document('path/to/foo')
.snapshots(includeMetadataChanges: true)
.first;
expect(snapshot.documentID, equals('foo'));
expect(snapshot.reference.path, equals('path/to/foo'));
expect(snapshot.data, equals(kMockDocumentSnapshotData));
Expand All @@ -468,14 +475,15 @@ void main() {
log,
<Matcher>[
isMethodCall(
'Query#addDocumentListener',
'DocumentReference#addSnapshotListener',
arguments: <String, dynamic>{
'app': app.name,
'path': 'path/to/foo',
'includeMetadataChanges': true,
},
),
isMethodCall(
'Query#removeListener',
'removeListener',
arguments: <String, dynamic>{'handle': 0},
),
],
Expand Down