Skip to content

Commit cfaf7ea

Browse files
authored
Merge pull request #2 from FirebaseExtended/master
Update from master
2 parents b8ecdf7 + 33e0586 commit cfaf7ea

File tree

55 files changed

+660
-106
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+660
-106
lines changed

packages/cloud_firestore/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## 0.12.10
2+
3+
* Added `FieldPath` class and `FieldPath.documentId` to refer to the document id in queries.
4+
* Added assertions and exceptions that help you building correct queries.
5+
6+
## 0.12.9+8
7+
8+
* Updated README instructions for contributing for consistency with other Flutterfire plugins.
9+
110
## 0.12.9+7
211

312
* Remove AndroidX warning.

packages/cloud_firestore/README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ A Flutter plugin to use the [Cloud Firestore API](https://firebase.google.com/do
66

77
For Flutter plugins for other Firebase products, see [README.md](https://github.com/FirebaseExtended/flutterfire/blob/master/README.md).
88

9-
*Note*: This plugin is still under development, and some APIs might not be available yet. [Feedback](https://github.com/FirebaseExtended/flutterfire/issues) and [Pull Requests](https://github.com/FirebaseExtended/flutterfire/pulls) are most welcome!
10-
119
## Setup
1210

1311
To use this plugin:
@@ -102,3 +100,13 @@ Firestore.instance.runTransaction((Transaction tx) async {
102100
## Getting Started
103101

104102
See the `example` directory for a complete sample app using Cloud Firestore.
103+
104+
## Issues and feedback
105+
106+
Please file Flutterfire specific issues, bugs, or feature requests in our [issue tracker](https://github.com/FirebaseExtended/flutterfire/issues/new).
107+
108+
Plugin issues that are not specific to Flutterfire can be filed in the [Flutter issue tracker](https://github.com/flutter/flutter/issues/new).
109+
110+
To contribute a change to this plugin,
111+
please review our [contribution guide](https://github.com/FirebaseExtended/flutterfire/blob/master/CONTRIBUTING.md),
112+
and send a [pull request](https://github.com/FirebaseExtended/flutterfire/pulls).

packages/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/cloudfirestore/CloudFirestorePlugin.java

Lines changed: 104 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -129,16 +129,32 @@ private Object[] getDocumentValues(
129129
List<Object> data = new ArrayList<>();
130130
if (orderBy != null) {
131131
for (List<Object> order : orderBy) {
132-
String orderByFieldName = (String) order.get(0);
133-
if (orderByFieldName.contains(".")) {
134-
String[] fieldNameParts = orderByFieldName.split("\\.");
135-
Map<String, Object> current = (Map<String, Object>) documentData.get(fieldNameParts[0]);
136-
for (int i = 1; i < fieldNameParts.length - 1; i++) {
137-
current = (Map<String, Object>) current.get(fieldNameParts[i]);
132+
final Object field = order.get(0);
133+
134+
if (field instanceof FieldPath) {
135+
if (field == FieldPath.documentId()) {
136+
// This is also checked by an assertion on the Dart side.
137+
throw new IllegalArgumentException(
138+
"You cannot order by the document id when using"
139+
+ "{start/end}{At/After/Before}Document as the library will order by the document"
140+
+ " id implicitly in order to to add other fields to the order clause.");
141+
} else {
142+
// Unsupported type.
143+
}
144+
} else if (field instanceof String) {
145+
String orderByFieldName = (String) field;
146+
if (orderByFieldName.contains(".")) {
147+
String[] fieldNameParts = orderByFieldName.split("\\.");
148+
Map<String, Object> current = (Map<String, Object>) documentData.get(fieldNameParts[0]);
149+
for (int i = 1; i < fieldNameParts.length - 1; i++) {
150+
current = (Map<String, Object>) current.get(fieldNameParts[i]);
151+
}
152+
data.add(current.get(fieldNameParts[fieldNameParts.length - 1]));
153+
} else {
154+
data.add(documentData.get(orderByFieldName));
138155
}
139-
data.add(current.get(fieldNameParts[fieldNameParts.length - 1]));
140156
} else {
141-
data.add(documentData.get(orderByFieldName));
157+
// Invalid type.
142158
}
143159
}
144160
}
@@ -213,21 +229,67 @@ private Query getQuery(Map<String, Object> arguments) {
213229
@SuppressWarnings("unchecked")
214230
List<List<Object>> whereConditions = (List<List<Object>>) parameters.get("where");
215231
for (List<Object> condition : whereConditions) {
216-
String fieldName = (String) condition.get(0);
232+
String fieldName = null;
233+
FieldPath fieldPath = null;
234+
final Object field = condition.get(0);
235+
if (field instanceof String) {
236+
fieldName = (String) field;
237+
} else if (field instanceof FieldPath) {
238+
fieldPath = (FieldPath) field;
239+
} else {
240+
// Invalid type.
241+
}
242+
217243
String operator = (String) condition.get(1);
218244
Object value = condition.get(2);
219245
if ("==".equals(operator)) {
220-
query = query.whereEqualTo(fieldName, value);
246+
if (fieldName != null) {
247+
query = query.whereEqualTo(fieldName, value);
248+
} else if (fieldPath != null) {
249+
query = query.whereEqualTo(fieldPath, value);
250+
} else {
251+
// Invalid type.
252+
}
221253
} else if ("<".equals(operator)) {
222-
query = query.whereLessThan(fieldName, value);
254+
if (fieldName != null) {
255+
query = query.whereLessThan(fieldName, value);
256+
} else if (fieldPath != null) {
257+
query = query.whereLessThan(fieldPath, value);
258+
} else {
259+
// Invalid type.
260+
}
223261
} else if ("<=".equals(operator)) {
224-
query = query.whereLessThanOrEqualTo(fieldName, value);
262+
if (fieldName != null) {
263+
query = query.whereLessThanOrEqualTo(fieldName, value);
264+
} else if (fieldPath != null) {
265+
query = query.whereLessThanOrEqualTo(fieldPath, value);
266+
} else {
267+
// Invalid type.
268+
}
225269
} else if (">".equals(operator)) {
226-
query = query.whereGreaterThan(fieldName, value);
270+
if (fieldName != null) {
271+
query = query.whereGreaterThan(fieldName, value);
272+
} else if (fieldPath != null) {
273+
query = query.whereGreaterThan(fieldPath, value);
274+
} else {
275+
// Invalid type.
276+
}
227277
} else if (">=".equals(operator)) {
228-
query = query.whereGreaterThanOrEqualTo(fieldName, value);
278+
if (fieldName != null) {
279+
query = query.whereGreaterThanOrEqualTo(fieldName, value);
280+
} else if (fieldPath != null) {
281+
query = query.whereGreaterThanOrEqualTo(fieldPath, value);
282+
} else {
283+
// Invalid type.
284+
}
229285
} else if ("array-contains".equals(operator)) {
230-
query = query.whereArrayContains(fieldName, value);
286+
if (fieldName != null) {
287+
query = query.whereArrayContains(fieldName, value);
288+
} else if (fieldPath != null) {
289+
query = query.whereArrayContains(fieldPath, value);
290+
} else {
291+
// Invalid type.
292+
}
231293
} else {
232294
// Invalid operator.
233295
}
@@ -239,11 +301,28 @@ private Query getQuery(Map<String, Object> arguments) {
239301
List<List<Object>> orderBy = (List<List<Object>>) parameters.get("orderBy");
240302
if (orderBy == null) return query;
241303
for (List<Object> order : orderBy) {
242-
String orderByFieldName = (String) order.get(0);
304+
String fieldName = null;
305+
FieldPath fieldPath = null;
306+
final Object field = order.get(0);
307+
if (field instanceof String) {
308+
fieldName = (String) field;
309+
} else if (field instanceof FieldPath) {
310+
fieldPath = (FieldPath) field;
311+
} else {
312+
// Invalid type.
313+
}
314+
243315
boolean descending = (boolean) order.get(1);
244316
Query.Direction direction =
245317
descending ? Query.Direction.DESCENDING : Query.Direction.ASCENDING;
246-
query = query.orderBy(orderByFieldName, direction);
318+
319+
if (fieldName != null) {
320+
query = query.orderBy(fieldName, direction);
321+
} else if (fieldPath != null) {
322+
query = query.orderBy(fieldPath, direction);
323+
} else {
324+
// Invalid type.
325+
}
247326
}
248327
@SuppressWarnings("unchecked")
249328
Map<String, Object> startAtDocument = (Map<String, Object>) parameters.get("startAtDocument");
@@ -259,6 +338,11 @@ private Query getQuery(Map<String, Object> arguments) {
259338
|| startAfterDocument != null
260339
|| endAtDocument != null
261340
|| endBeforeDocument != null) {
341+
if (orderBy.isEmpty()) {
342+
throw new IllegalStateException(
343+
"You need to order by at least one field when using "
344+
+ "{start/end}{At/After/Before}Document as you need some value to e.g. start after.");
345+
}
262346
boolean descending = (boolean) orderBy.get(orderBy.size() - 1).get(1);
263347
Query.Direction direction =
264348
descending ? Query.Direction.DESCENDING : Query.Direction.ASCENDING;
@@ -859,6 +943,7 @@ final class FirestoreMessageCodec extends StandardMessageCodec {
859943
private static final byte TIMESTAMP = (byte) 136;
860944
private static final byte INCREMENT_DOUBLE = (byte) 137;
861945
private static final byte INCREMENT_INTEGER = (byte) 138;
946+
private static final byte DOCUMENT_ID = (byte) 139;
862947

863948
@Override
864949
protected void writeValue(ByteArrayOutputStream stream, Object value) {
@@ -922,6 +1007,8 @@ protected Object readValueOfType(byte type, ByteBuffer buffer) {
9221007
case INCREMENT_DOUBLE:
9231008
final Number doubleIncrementValue = (Number) readValue(buffer);
9241009
return FieldValue.increment(doubleIncrementValue.doubleValue());
1010+
case DOCUMENT_ID:
1011+
return FieldPath.documentId();
9251012
default:
9261013
return super.readValueOfType(type, buffer);
9271014
}

packages/cloud_firestore/example/test_driver/cloud_firestore.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,5 +294,39 @@ void main() {
294294
await doc1.delete();
295295
await doc2.delete();
296296
});
297+
298+
test('FieldPath.documentId', () async {
299+
// Populate the database with two test documents.
300+
final CollectionReference messages = firestore.collection('messages');
301+
302+
// Use document ID as a unique identifier to ensure that we don't
303+
// collide with other tests running against this database.
304+
final DocumentReference doc = messages.document();
305+
final String documentId = doc.documentID;
306+
307+
await doc.setData(<String, dynamic>{
308+
'message': 'testing field path',
309+
'created_at': FieldValue.serverTimestamp(),
310+
});
311+
312+
// This tests the native implementations of the where and
313+
// orderBy methods handling FieldPath.documentId.
314+
// There is also an error thrown when ordering by document id
315+
// natively, however, that is also covered by assertion
316+
// on the Dart side, which is tested with a unit test.
317+
final QuerySnapshot querySnapshot = await messages
318+
.orderBy(FieldPath.documentId)
319+
.where(FieldPath.documentId, isEqualTo: documentId)
320+
.getDocuments();
321+
322+
await doc.delete();
323+
324+
final List<DocumentSnapshot> results = querySnapshot.documents;
325+
final DocumentSnapshot result = results[0];
326+
327+
expect(results.length, 1);
328+
expect(result.data['message'], 'testing field path');
329+
expect(result.documentID, documentId);
330+
});
297331
});
298332
}

0 commit comments

Comments
 (0)