Additional Firestore Query methods (#369)
* Extend orderBy to be used multiple times.
* Implement startAt/After and endAt/Before
* Implement `limit` method
* Formatting fix
* Fix missing parameter list and related tests
* Formatting fixes
* Pass start/end methods an array, not a list
* Update CHANGELOG.md
* Update pubspec.yaml
diff --git a/packages/cloud_firestore/CHANGELOG.md b/packages/cloud_firestore/CHANGELOG.md
index 7c86cf0..da47363 100644
--- a/packages/cloud_firestore/CHANGELOG.md
+++ b/packages/cloud_firestore/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.2.5
+
+* Query can now have more than one orderBy field.
+* startAt, startAfter, endAt, and endBefore support
+* limit support
+
## 0.2.4
* Support for DocumentReference.documentID
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 072c1ef..9057362 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
@@ -86,12 +86,31 @@
}
}
@SuppressWarnings("unchecked")
- List<Object> orderBy = (List<Object>) parameters.get("orderBy");
+ Number limit = (Number) parameters.get("limit");
+ if (limit != null) query = query.limit(limit.longValue());
+ @SuppressWarnings("unchecked")
+ List<List<Object>> orderBy = (List<List<Object>>) parameters.get("orderBy");
if (orderBy == null) return query;
- String orderByFieldName = (String) orderBy.get(0);
- Boolean descending = (Boolean) orderBy.get(1);
- Query.Direction direction = descending ? Query.Direction.DESCENDING : Query.Direction.ASCENDING;
- return query.orderBy(orderByFieldName, direction);
+ for (List<Object> order : orderBy) {
+ String orderByFieldName = (String) order.get(0);
+ Boolean descending = (Boolean) order.get(1);
+ Query.Direction direction =
+ descending ? Query.Direction.DESCENDING : Query.Direction.ASCENDING;
+ query = query.orderBy(orderByFieldName, direction);
+ }
+ @SuppressWarnings("unchecked")
+ List<Object> startAt = (List<Object>) parameters.get("startAt");
+ if (startAt != null) query = query.startAt(startAt.toArray());
+ @SuppressWarnings("unchecked")
+ List<Object> startAfter = (List<Object>) parameters.get("startAfter");
+ if (startAfter != null) query = query.startAfter(startAfter.toArray());
+ @SuppressWarnings("unchecked")
+ List<Object> endAt = (List<Object>) parameters.get("endAt");
+ if (endAt != null) query = query.endAt(endAt.toArray());
+ @SuppressWarnings("unchecked")
+ List<Object> endBefore = (List<Object>) parameters.get("endBefore");
+ if (endBefore != null) query = query.endBefore(endBefore.toArray());
+ return query;
}
private class DocumentObserver implements EventListener<DocumentSnapshot> {
diff --git a/packages/cloud_firestore/ios/Classes/CloudFirestorePlugin.m b/packages/cloud_firestore/ios/Classes/CloudFirestorePlugin.m
index bf7d356..f6e289f 100644
--- a/packages/cloud_firestore/ios/Classes/CloudFirestorePlugin.m
+++ b/packages/cloud_firestore/ios/Classes/CloudFirestorePlugin.m
@@ -41,13 +41,38 @@
// Unsupported operator
}
}
- id orderBy = parameters[@"orderBy"];
- if (orderBy) {
+ id limit = parameters[@"limit"];
+ if (limit) {
+ NSNumber *length = limit;
+ query = [query queryLimitedTo:[length intValue]];
+ }
+ NSArray orderBy = parameters[@"orderBy"];
+ for (id item in orderBy) {
NSArray *orderByParameters = orderBy;
NSString *fieldName = orderByParameters[0];
NSNumber *descending = orderByParameters[1];
query = [query queryOrderedByField:fieldName descending:[descending boolValue]];
}
+ id startAt = parameters[@"startAt"];
+ if (startAt) {
+ NSArray *startAtValues = startAt;
+ query = [query queryStartingAtValues:startAtValues];
+ }
+ id startAfter = parameters[@"startAfter"];
+ if (startAfter) {
+ NSArray *startAfterValues = startAfter;
+ query = [query queryStartingAfterValues:startAfterValues];
+ }
+ id startAt = parameters[@"endAt"];
+ if (endAt) {
+ NSArray *endAtValues = endAt;
+ query = [query queryEndingAtValues:endAtValues];
+ }
+ id endBefore = parameters[@"endBefore"];
+ if (endBefore) {
+ NSArray *endBeforeValues = endBefore;
+ query = [query queryEndingBeforeValues:endBeforeValues];
+ }
return query;
}
diff --git a/packages/cloud_firestore/lib/src/query.dart b/packages/cloud_firestore/lib/src/query.dart
index 017940d..128a432 100644
--- a/packages/cloud_firestore/lib/src/query.dart
+++ b/packages/cloud_firestore/lib/src/query.dart
@@ -15,6 +15,8 @@
_parameters = parameters ??
new Map<String, dynamic>.unmodifiable(<String, dynamic>{
'where': new List<List<dynamic>>.unmodifiable(<List<dynamic>>[]),
+ 'orderBy':
+ new List<List<dynamic>>.unmodifiable(<List<dynamic>>[]),
}),
assert(firestore != null),
assert(pathComponents != null);
@@ -130,9 +132,68 @@
/// Creates and returns a new [Query] that's additionally sorted by the specified
/// [field].
Query orderBy(String field, {bool descending: false}) {
- assert(!_parameters.containsKey('orderBy'));
- return _copyWithParameters(<String, dynamic>{
- 'orderBy': <dynamic>[field, descending]
- });
+ final List<List<dynamic>> orders =
+ new List<List<dynamic>>.from(_parameters['orderBy']);
+
+ final List<dynamic> order = <dynamic>[field, descending];
+ assert(orders.where((List<dynamic> item) => field == item[0]).isEmpty,
+ 'OrderBy $field already exists in this query');
+ orders.add(order);
+ return _copyWithParameters(<String, dynamic>{'orderBy': orders});
+ }
+
+ /// Takes a list of [values], creates and returns a new [Query] that starts after
+ /// the provided fields relative to the order of the query.
+ ///
+ /// The [values] must be in order of [orderBy] filters.
+ ///
+ /// Cannot be used in combination with [startAt].
+ Query startAfter(List<dynamic> values) {
+ assert(!_parameters.containsKey('startAfter'));
+ assert(!_parameters.containsKey('startAt'));
+ return _copyWithParameters(<String, dynamic>{'startAfter': values});
+ }
+
+ /// Takes a list of [values], creates and returns a new [Query] that starts at
+ /// the provided fields relative to the order of the query.
+ ///
+ /// The [values] must be in order of [orderBy] filters.
+ ///
+ /// Cannot be used in combination with [startAfter].
+ Query startAt(List<dynamic> values) {
+ assert(!_parameters.containsKey('startAfter'));
+ assert(!_parameters.containsKey('startAt'));
+ return _copyWithParameters(<String, dynamic>{'startAt': values});
+ }
+
+ /// Takes a list of [values], creates and returns a new [Query] that ends at the
+ /// provided fields relative to the order of the query.
+ ///
+ /// The [values] must be in order of [orderBy] filters.
+ ///
+ /// Cannot be used in combination with [endBefore].
+ Query endAt(List<dynamic> values) {
+ assert(!_parameters.containsKey('endBefore'));
+ assert(!_parameters.containsKey('endAt'));
+ return _copyWithParameters(<String, dynamic>{'endAt': values});
+ }
+
+ /// Takes a list of [values], creates and returns a new [Query] that ends before
+ /// the provided fields relative to the order of the query.
+ ///
+ /// The [values] must be in order of [orderBy] filters.
+ ///
+ /// Cannot be used in combination with [endAt].
+ Query endBefore(List<dynamic> values) {
+ assert(!_parameters.containsKey('endBefore'));
+ assert(!_parameters.containsKey('endAt'));
+ return _copyWithParameters(<String, dynamic>{'endBefore': values});
+ }
+
+ /// Creates and returns a new Query that's additionally limited to only return up
+ /// to the specified number of documents.
+ Query limit(int length) {
+ assert(!_parameters.containsKey('limit'));
+ return _copyWithParameters(<String, dynamic>{'limit': length});
}
}
diff --git a/packages/cloud_firestore/pubspec.yaml b/packages/cloud_firestore/pubspec.yaml
index f5abe0d..69f883b 100755
--- a/packages/cloud_firestore/pubspec.yaml
+++ b/packages/cloud_firestore/pubspec.yaml
@@ -3,7 +3,7 @@
live synchronization and offline support on Android and iOS.
author: Flutter Team <flutter-dev@googlegroups.com>
homepage: https://github.com/flutter/plugins/tree/master/packages/cloud_firestore
-version: 0.2.4
+version: 0.2.5
flutter:
plugin:
diff --git a/packages/cloud_firestore/test/cloud_firestore_test.dart b/packages/cloud_firestore/test/cloud_firestore_test.dart
index 1d906b2..cfd2856 100755
--- a/packages/cloud_firestore/test/cloud_firestore_test.dart
+++ b/packages/cloud_firestore/test/cloud_firestore_test.dart
@@ -96,6 +96,7 @@
'path': 'foo',
'parameters': <String, dynamic>{
'where': <List<dynamic>>[],
+ 'orderBy': <List<dynamic>>[],
}
},
),
@@ -124,6 +125,7 @@
'where': <List<dynamic>>[
<dynamic>['createdAt', '<', 100],
],
+ 'orderBy': <List<dynamic>>[],
}
},
),
@@ -153,6 +155,7 @@
'where': <List<dynamic>>[
<dynamic>['profile', '==', null],
],
+ 'orderBy': <List<dynamic>>[],
}
},
),
@@ -180,7 +183,9 @@
'path': 'foo',
'parameters': <String, dynamic>{
'where': <List<dynamic>>[],
- 'orderBy': <dynamic>['createdAt', false],
+ 'orderBy': <List<dynamic>>[
+ <dynamic>['createdAt', false]
+ ],
}
},
),