Skip to content

[cloud_firestore] Add FieldPath #1296

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 30 commits into from
Nov 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3c23650
initial
creativecreatorormaybenot Oct 22, 2019
df77698
format
creativecreatorormaybenot Oct 22, 2019
c2d8386
Update gradle.properties
creativecreatorormaybenot Oct 23, 2019
a4aaa69
Merge branch 'master' into firestore-field-path
creativecreatorormaybenot Oct 23, 2019
0549029
resolve conflicts
creativecreatorormaybenot Oct 23, 2019
30e24d5
codec implementation
creativecreatorormaybenot Oct 23, 2019
52910ef
java implementation, tests
creativecreatorormaybenot Oct 23, 2019
77a7fe9
Merge branch 'firestore-field-path' of github.com:creativecreatororma…
creativecreatorormaybenot Oct 23, 2019
97d41a9
revert java formatting
creativecreatorormaybenot Oct 23, 2019
20196b2
revert java formatting
creativecreatorormaybenot Oct 23, 2019
ce25aa0
java implementation
creativecreatorormaybenot Oct 23, 2019
0ab69f3
exception
creativecreatorormaybenot Oct 23, 2019
0f1142d
pre format
creativecreatorormaybenot Oct 23, 2019
88f60cc
assertions
creativecreatorormaybenot Oct 23, 2019
af85c95
Fix tests, add exceptions for debugging help
creativecreatorormaybenot Oct 23, 2019
0a61fcc
fix tests
creativecreatorormaybenot Oct 23, 2019
f28d4d6
iOS implementation
creativecreatorormaybenot Oct 23, 2019
ac9a0d2
format
creativecreatorormaybenot Oct 23, 2019
595b92a
exceptions
creativecreatorormaybenot Oct 23, 2019
0ca445e
format
creativecreatorormaybenot Oct 23, 2019
48dd4ad
remove gradle properties
creativecreatorormaybenot Oct 23, 2019
01818df
remove example gradle properties
creativecreatorormaybenot Oct 23, 2019
8fd37e7
remove gradle collisions
creativecreatorormaybenot Oct 23, 2019
2e3dbf5
i meant to say resolve
creativecreatorormaybenot Oct 23, 2019
4d9ff62
format
creativecreatorormaybenot Oct 23, 2019
61719d5
fix iOS
creativecreatorormaybenot Oct 23, 2019
6073c9c
Update CloudFirestorePlugin.m
creativecreatorormaybenot Oct 24, 2019
fec2965
typo
creativecreatorormaybenot Oct 30, 2019
22edeb7
Merge branch 'firestore-field-path' of github.com:creativecreatororma…
creativecreatorormaybenot Oct 30, 2019
9eade1d
Merge remote-tracking branch 'origin/master' into firestore-field-path
collinjackson Nov 7, 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
5 changes: 5 additions & 0 deletions packages/cloud_firestore/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.12.10

* Added `FieldPath` class and `FieldPath.documentId` to refer to the document id in queries.
* Added assertions and exceptions that help you building correct queries.

## 0.12.9+8

* Updated README instructions for contributing for consistency with other Flutterfire plugins.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,32 @@ private Object[] getDocumentValues(
List<Object> data = new ArrayList<>();
if (orderBy != null) {
for (List<Object> order : orderBy) {
String orderByFieldName = (String) order.get(0);
if (orderByFieldName.contains(".")) {
String[] fieldNameParts = orderByFieldName.split("\\.");
Map<String, Object> current = (Map<String, Object>) documentData.get(fieldNameParts[0]);
for (int i = 1; i < fieldNameParts.length - 1; i++) {
current = (Map<String, Object>) current.get(fieldNameParts[i]);
final Object field = order.get(0);

if (field instanceof FieldPath) {
if (field == FieldPath.documentId()) {
// This is also checked by an assertion on the Dart side.
throw new IllegalArgumentException(
"You cannot order by the document id when using"
+ "{start/end}{At/After/Before}Document as the library will order by the document"
+ " id implicitly in order to to add other fields to the order clause.");
} else {
// Unsupported type.
}
} else if (field instanceof String) {
String orderByFieldName = (String) field;
if (orderByFieldName.contains(".")) {
String[] fieldNameParts = orderByFieldName.split("\\.");
Map<String, Object> current = (Map<String, Object>) documentData.get(fieldNameParts[0]);
for (int i = 1; i < fieldNameParts.length - 1; i++) {
current = (Map<String, Object>) current.get(fieldNameParts[i]);
}
data.add(current.get(fieldNameParts[fieldNameParts.length - 1]));
} else {
data.add(documentData.get(orderByFieldName));
}
data.add(current.get(fieldNameParts[fieldNameParts.length - 1]));
} else {
data.add(documentData.get(orderByFieldName));
// Invalid type.
}
}
}
Expand Down Expand Up @@ -213,21 +229,67 @@ private Query getQuery(Map<String, Object> arguments) {
@SuppressWarnings("unchecked")
List<List<Object>> whereConditions = (List<List<Object>>) parameters.get("where");
for (List<Object> condition : whereConditions) {
String fieldName = (String) condition.get(0);
String fieldName = null;
FieldPath fieldPath = null;
final Object field = condition.get(0);
if (field instanceof String) {
fieldName = (String) field;
} else if (field instanceof FieldPath) {
fieldPath = (FieldPath) field;
} else {
// Invalid type.
}

String operator = (String) condition.get(1);
Object value = condition.get(2);
if ("==".equals(operator)) {
query = query.whereEqualTo(fieldName, value);
if (fieldName != null) {
query = query.whereEqualTo(fieldName, value);
} else if (fieldPath != null) {
query = query.whereEqualTo(fieldPath, value);
} else {
// Invalid type.
}
} else if ("<".equals(operator)) {
query = query.whereLessThan(fieldName, value);
if (fieldName != null) {
query = query.whereLessThan(fieldName, value);
} else if (fieldPath != null) {
query = query.whereLessThan(fieldPath, value);
} else {
// Invalid type.
}
} else if ("<=".equals(operator)) {
query = query.whereLessThanOrEqualTo(fieldName, value);
if (fieldName != null) {
query = query.whereLessThanOrEqualTo(fieldName, value);
} else if (fieldPath != null) {
query = query.whereLessThanOrEqualTo(fieldPath, value);
} else {
// Invalid type.
}
} else if (">".equals(operator)) {
query = query.whereGreaterThan(fieldName, value);
if (fieldName != null) {
query = query.whereGreaterThan(fieldName, value);
} else if (fieldPath != null) {
query = query.whereGreaterThan(fieldPath, value);
} else {
// Invalid type.
}
} else if (">=".equals(operator)) {
query = query.whereGreaterThanOrEqualTo(fieldName, value);
if (fieldName != null) {
query = query.whereGreaterThanOrEqualTo(fieldName, value);
} else if (fieldPath != null) {
query = query.whereGreaterThanOrEqualTo(fieldPath, value);
} else {
// Invalid type.
}
} else if ("array-contains".equals(operator)) {
query = query.whereArrayContains(fieldName, value);
if (fieldName != null) {
query = query.whereArrayContains(fieldName, value);
} else if (fieldPath != null) {
query = query.whereArrayContains(fieldPath, value);
} else {
// Invalid type.
}
} else {
// Invalid operator.
}
Expand All @@ -239,11 +301,28 @@ private Query getQuery(Map<String, Object> arguments) {
List<List<Object>> orderBy = (List<List<Object>>) parameters.get("orderBy");
if (orderBy == null) return query;
for (List<Object> order : orderBy) {
String orderByFieldName = (String) order.get(0);
String fieldName = null;
FieldPath fieldPath = null;
final Object field = order.get(0);
if (field instanceof String) {
fieldName = (String) field;
} else if (field instanceof FieldPath) {
fieldPath = (FieldPath) field;
} else {
// Invalid type.
}

boolean descending = (boolean) order.get(1);
Query.Direction direction =
descending ? Query.Direction.DESCENDING : Query.Direction.ASCENDING;
query = query.orderBy(orderByFieldName, direction);

if (fieldName != null) {
query = query.orderBy(fieldName, direction);
} else if (fieldPath != null) {
query = query.orderBy(fieldPath, direction);
} else {
// Invalid type.
}
}
@SuppressWarnings("unchecked")
Map<String, Object> startAtDocument = (Map<String, Object>) parameters.get("startAtDocument");
Expand All @@ -259,6 +338,11 @@ private Query getQuery(Map<String, Object> arguments) {
|| startAfterDocument != null
|| endAtDocument != null
|| endBeforeDocument != null) {
if (orderBy.isEmpty()) {
throw new IllegalStateException(
"You need to order by at least one field when using "
+ "{start/end}{At/After/Before}Document as you need some value to e.g. start after.");
}
boolean descending = (boolean) orderBy.get(orderBy.size() - 1).get(1);
Query.Direction direction =
descending ? Query.Direction.DESCENDING : Query.Direction.ASCENDING;
Expand Down Expand Up @@ -859,6 +943,7 @@ final class FirestoreMessageCodec extends StandardMessageCodec {
private static final byte TIMESTAMP = (byte) 136;
private static final byte INCREMENT_DOUBLE = (byte) 137;
private static final byte INCREMENT_INTEGER = (byte) 138;
private static final byte DOCUMENT_ID = (byte) 139;

@Override
protected void writeValue(ByteArrayOutputStream stream, Object value) {
Expand Down Expand Up @@ -922,6 +1007,8 @@ protected Object readValueOfType(byte type, ByteBuffer buffer) {
case INCREMENT_DOUBLE:
final Number doubleIncrementValue = (Number) readValue(buffer);
return FieldValue.increment(doubleIncrementValue.doubleValue());
case DOCUMENT_ID:
return FieldPath.documentId();
default:
return super.readValueOfType(type, buffer);
}
Expand Down
34 changes: 34 additions & 0 deletions packages/cloud_firestore/example/test_driver/cloud_firestore.dart
Original file line number Diff line number Diff line change
Expand Up @@ -294,5 +294,39 @@ void main() {
await doc1.delete();
await doc2.delete();
});

test('FieldPath.documentId', () async {
// Populate the database with two test documents.
final CollectionReference messages = firestore.collection('messages');

// Use document ID as a unique identifier to ensure that we don't
// collide with other tests running against this database.
final DocumentReference doc = messages.document();
final String documentId = doc.documentID;

await doc.setData(<String, dynamic>{
'message': 'testing field path',
'created_at': FieldValue.serverTimestamp(),
});

// This tests the native implementations of the where and
// orderBy methods handling FieldPath.documentId.
// There is also an error thrown when ordering by document id
// natively, however, that is also covered by assertion
// on the Dart side, which is tested with a unit test.
final QuerySnapshot querySnapshot = await messages
.orderBy(FieldPath.documentId)
.where(FieldPath.documentId, isEqualTo: documentId)
.getDocuments();

await doc.delete();

final List<DocumentSnapshot> results = querySnapshot.documents;
final DocumentSnapshot result = results[0];

expect(results.length, 1);
expect(result.data['message'], 'testing field path');
expect(result.documentID, documentId);
});
});
}
Loading