Skip to content

Commit e0ce705

Browse files
committed
Merge branch 'firestore-pipelines-dart-api-v2' into firestore-pipelines-ios
2 parents 0aaf46c + 485f145 commit e0ce705

26 files changed

Lines changed: 238 additions & 77 deletions

File tree

packages/cloud_firestore/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/firestore/FlutterFirebaseFirestorePlugin.java

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -885,38 +885,62 @@ public void writeBatchCommit(
885885
GeneratedAndroidFirebaseFirestore.PigeonTransactionType type =
886886
Objects.requireNonNull(write.getType());
887887
String path = Objects.requireNonNull(write.getPath());
888-
Map<String, Object> data = write.getData();
889-
890888
DocumentReference documentReference = firestore.document(path);
891889

892890
switch (type) {
893891
case DELETE_TYPE:
894892
batch = batch.delete(documentReference);
895893
break;
896894
case UPDATE:
897-
batch = batch.update(documentReference, Objects.requireNonNull(data));
898-
break;
899-
case SET:
900-
GeneratedAndroidFirebaseFirestore.PigeonDocumentOption options =
901-
Objects.requireNonNull(write.getOption());
902-
903-
if (options.getMerge() != null && options.getMerge()) {
895+
{
896+
Map<Object, Object> rawData = Objects.requireNonNull(write.getData());
897+
Map<FieldPath, Object> updateData = new HashMap<>();
898+
for (Object key : rawData.keySet()) {
899+
if (key instanceof String) {
900+
updateData.put(FieldPath.of((String) key), rawData.get(key));
901+
} else if (key instanceof FieldPath) {
902+
updateData.put((FieldPath) key, rawData.get(key));
903+
}
904+
}
905+
FieldPath firstFieldPath = updateData.keySet().iterator().next();
906+
Object firstObject = updateData.get(firstFieldPath);
907+
ArrayList<Object> flattenData = new ArrayList<>();
908+
for (FieldPath fieldPath : updateData.keySet()) {
909+
if (fieldPath.equals(firstFieldPath)) {
910+
continue;
911+
}
912+
flattenData.add(fieldPath);
913+
flattenData.add(updateData.get(fieldPath));
914+
}
904915
batch =
905-
batch.set(
906-
documentReference, Objects.requireNonNull(data), SetOptions.merge());
907-
} else if (options.getMergeFields() != null) {
908-
List<FieldPath> fieldPathList =
909-
PigeonParser.parseFieldPath(
910-
Objects.requireNonNull(options.getMergeFields()));
911-
batch =
912-
batch.set(
913-
documentReference,
914-
Objects.requireNonNull(data),
915-
SetOptions.mergeFieldPaths(fieldPathList));
916-
} else {
917-
batch = batch.set(documentReference, Objects.requireNonNull(data));
916+
batch.update(
917+
documentReference, firstFieldPath, firstObject, flattenData.toArray());
918+
break;
919+
}
920+
case SET:
921+
{
922+
@SuppressWarnings("unchecked")
923+
Map<String, Object> setData =
924+
(Map<String, Object>) (Map<?, ?>) Objects.requireNonNull(write.getData());
925+
GeneratedAndroidFirebaseFirestore.PigeonDocumentOption options =
926+
Objects.requireNonNull(write.getOption());
927+
928+
if (options.getMerge() != null && options.getMerge()) {
929+
batch = batch.set(documentReference, setData, SetOptions.merge());
930+
} else if (options.getMergeFields() != null) {
931+
List<FieldPath> fieldPathList =
932+
PigeonParser.parseFieldPath(
933+
Objects.requireNonNull(options.getMergeFields()));
934+
batch =
935+
batch.set(
936+
documentReference,
937+
setData,
938+
SetOptions.mergeFieldPaths(fieldPathList));
939+
} else {
940+
batch = batch.set(documentReference, setData);
941+
}
942+
break;
918943
}
919-
break;
920944
}
921945
}
922946

packages/cloud_firestore/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/firestore/GeneratedAndroidFirebaseFirestore.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,13 +1023,13 @@ public void setPath(@NonNull String setterArg) {
10231023
this.path = setterArg;
10241024
}
10251025

1026-
private @Nullable Map<String, Object> data;
1026+
private @Nullable Map<Object, Object> data;
10271027

1028-
public @Nullable Map<String, Object> getData() {
1028+
public @Nullable Map<Object, Object> getData() {
10291029
return data;
10301030
}
10311031

1032-
public void setData(@Nullable Map<String, Object> setterArg) {
1032+
public void setData(@Nullable Map<Object, Object> setterArg) {
10331033
this.data = setterArg;
10341034
}
10351035

@@ -1062,9 +1062,9 @@ public static final class Builder {
10621062
return this;
10631063
}
10641064

1065-
private @Nullable Map<String, Object> data;
1065+
private @Nullable Map<Object, Object> data;
10661066

1067-
public @NonNull Builder setData(@Nullable Map<String, Object> setterArg) {
1067+
public @NonNull Builder setData(@Nullable Map<Object, Object> setterArg) {
10681068
this.data = setterArg;
10691069
return this;
10701070
}
@@ -1103,7 +1103,7 @@ public ArrayList<Object> toList() {
11031103
Object path = list.get(1);
11041104
pigeonResult.setPath((String) path);
11051105
Object data = list.get(2);
1106-
pigeonResult.setData((Map<String, Object>) data);
1106+
pigeonResult.setData((Map<Object, Object>) data);
11071107
Object option = list.get(3);
11081108
pigeonResult.setOption(
11091109
(option == null) ? null : PigeonDocumentOption.fromList((ArrayList<Object>) option));

packages/cloud_firestore/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/firestore/streamhandler/TransactionStreamHandler.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import io.flutter.plugins.firebase.firestore.GeneratedAndroidFirebaseFirestore;
2424
import io.flutter.plugins.firebase.firestore.utils.ExceptionConverter;
2525
import io.flutter.plugins.firebase.firestore.utils.PigeonParser;
26+
import java.util.ArrayList;
2627
import java.util.HashMap;
2728
import java.util.List;
2829
import java.util.Map;
@@ -102,9 +103,30 @@ public void onListen(Object arguments, EventSink events) {
102103
transaction.delete(documentReference);
103104
break;
104105
case UPDATE:
105-
transaction.update(
106-
documentReference, Objects.requireNonNull(command.getData()));
107-
break;
106+
{
107+
Map<Object, Object> rawData = Objects.requireNonNull(command.getData());
108+
Map<FieldPath, Object> updateData = new HashMap<>();
109+
for (Object key : rawData.keySet()) {
110+
if (key instanceof String) {
111+
updateData.put(FieldPath.of((String) key), rawData.get(key));
112+
} else if (key instanceof FieldPath) {
113+
updateData.put((FieldPath) key, rawData.get(key));
114+
}
115+
}
116+
FieldPath firstFieldPath = updateData.keySet().iterator().next();
117+
Object firstObject = updateData.get(firstFieldPath);
118+
ArrayList<Object> flattenData = new ArrayList<>();
119+
for (FieldPath fieldPath : updateData.keySet()) {
120+
if (fieldPath.equals(firstFieldPath)) {
121+
continue;
122+
}
123+
flattenData.add(fieldPath);
124+
flattenData.add(updateData.get(fieldPath));
125+
}
126+
transaction.update(
127+
documentReference, firstFieldPath, firstObject, flattenData.toArray());
128+
break;
129+
}
108130
case SET:
109131
{
110132
GeneratedAndroidFirebaseFirestore.PigeonDocumentOption options =
@@ -121,7 +143,10 @@ public void onListen(Object arguments, EventSink events) {
121143
setOptions = SetOptions.mergeFieldPaths(fieldPathList);
122144
}
123145

124-
Map<String, Object> data = Objects.requireNonNull(command.getData());
146+
@SuppressWarnings("unchecked")
147+
Map<String, Object> data =
148+
(Map<String, Object>)
149+
(Map<?, ?>) Objects.requireNonNull(command.getData());
125150

126151
if (setOptions == null) {
127152
transaction.set(documentReference, data);

packages/cloud_firestore/cloud_firestore/example/integration_test/transaction_e2e.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,29 @@ void runTransactionTests() {
326326
expect(snapshot.data()!['bar'], equals(2));
327327
expect(snapshot.data()!['foo'], equals('bar'));
328328
});
329+
330+
test('should update a document using FieldPath keys', () async {
331+
DocumentReference<Map<String, dynamic>> documentReference =
332+
await initializeTest('transaction-update-field-path');
333+
334+
await documentReference.set({
335+
'nested': {'field': 'old_value'},
336+
'top': 'value',
337+
});
338+
339+
await firestore.runTransaction((Transaction transaction) async {
340+
await transaction.get(documentReference);
341+
transaction.update(documentReference, {
342+
FieldPath(const ['nested', 'field']): 'new_value',
343+
});
344+
});
345+
346+
DocumentSnapshot<Map<String, dynamic>> snapshot =
347+
await documentReference.get();
348+
expect(snapshot.exists, isTrue);
349+
expect(snapshot.data()!['nested']['field'], equals('new_value'));
350+
expect(snapshot.data()!['top'], equals('value'));
351+
});
329352
});
330353

331354
group('Transaction.set()', () {

packages/cloud_firestore/cloud_firestore/example/integration_test/write_batch_e2e.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,28 @@ void runWriteBatchTests() {
7070
expect(snapshot.exists, false);
7171
});
7272

73+
test('should update a document using FieldPath keys', () async {
74+
CollectionReference<Map<String, dynamic>> collection =
75+
await initializeTest('write-batch-field-path');
76+
DocumentReference<Map<String, dynamic>> doc = collection.doc('doc1');
77+
78+
await doc.set({
79+
'nested': {'field': 'old_value'},
80+
'top': 'value',
81+
});
82+
83+
WriteBatch batch = firestore.batch();
84+
batch.update(doc, {
85+
FieldPath(const ['nested', 'field']): 'new_value',
86+
});
87+
await batch.commit();
88+
89+
DocumentSnapshot<Map<String, dynamic>> snapshot = await doc.get();
90+
expect(snapshot.exists, isTrue);
91+
expect(snapshot.data()!['nested']['field'], equals('new_value'));
92+
expect(snapshot.data()!['top'], equals('value'));
93+
});
94+
7395
test('performs batch operations', () async {
7496
CollectionReference<Map<String, dynamic>> collection =
7597
await initializeTest('write-batch-ops');

packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ - (NSArray *)toList {
535535
@implementation PigeonTransactionCommand
536536
+ (instancetype)makeWithType:(PigeonTransactionType)type
537537
path:(NSString *)path
538-
data:(nullable NSDictionary<NSString *, id> *)data
538+
data:(nullable NSDictionary<id, id> *)data
539539
option:(nullable PigeonDocumentOption *)option {
540540
PigeonTransactionCommand *pigeonResult = [[PigeonTransactionCommand alloc] init];
541541
pigeonResult.type = type;

packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FirestoreMessages.g.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,11 @@ typedef NS_ENUM(NSUInteger, AggregateType) {
287287
- (instancetype)init NS_UNAVAILABLE;
288288
+ (instancetype)makeWithType:(PigeonTransactionType)type
289289
path:(NSString *)path
290-
data:(nullable NSDictionary<NSString *, id> *)data
290+
data:(nullable NSDictionary<id, id> *)data
291291
option:(nullable PigeonDocumentOption *)option;
292292
@property(nonatomic, assign) PigeonTransactionType type;
293293
@property(nonatomic, copy) NSString *path;
294-
@property(nonatomic, strong, nullable) NSDictionary<NSString *, id> *data;
294+
@property(nonatomic, strong, nullable) NSDictionary<id, id> *data;
295295
@property(nonatomic, strong, nullable) PigeonDocumentOption *option;
296296
@end
297297

packages/cloud_firestore/cloud_firestore/lib/src/transaction.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,11 @@ class Transaction {
5959

6060
/// Updates fields in the document referred to by [documentReference].
6161
/// The update will fail if applied to a document that does not exist.
62+
///
63+
/// Objects key can be a String or a FieldPath.
6264
Transaction update(
6365
DocumentReference documentReference,
64-
Map<String, dynamic> data,
66+
Map<Object, Object?> data,
6567
) {
6668
assert(
6769
documentReference.firestore == _firestore,
@@ -72,7 +74,7 @@ class Transaction {
7274
_firestore,
7375
_delegate.update(
7476
documentReference.path,
75-
_CodecUtility.replaceValueWithDelegatesInMap(data)!,
77+
_CodecUtility.replaceValueWithDelegatesInMapFieldPath(data)!,
7678
),
7779
);
7880
}

packages/cloud_firestore/cloud_firestore/lib/src/write_batch.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,16 @@ class WriteBatch {
6666
/// Updates a given [document].
6767
///
6868
/// If the document does not yet exist, an exception will be thrown.
69-
void update(DocumentReference document, Map<String, dynamic> data) {
69+
///
70+
/// Objects key can be a String or a FieldPath.
71+
void update(DocumentReference document, Map<Object, Object?> data) {
7072
assert(
7173
document.firestore == _firestore,
7274
'the document provided is from a different Firestore instance',
7375
);
7476
return _delegate.update(
7577
document.path,
76-
_CodecUtility.replaceValueWithDelegatesInMap(data)!,
78+
_CodecUtility.replaceValueWithDelegatesInMapFieldPath(data)!,
7779
);
7880
}
7981
}

packages/cloud_firestore/cloud_firestore/pipeline_example/integration_test/pipeline/pipeline_expressions_e2e.dart

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,8 @@ void runPipelineExpressionsTests() {
9494
.limit(5)
9595
.execute();
9696
expectResultCount(snapshot, 5);
97-
final withTags = snapshot.result
98-
.where((r) => r.data()!['tags_len'] == 2)
99-
.toList();
97+
final withTags =
98+
snapshot.result.where((r) => r.data()!['tags_len'] == 2).toList();
10099
expect(withTags.length, 1);
101100
expect(withTags.first.data()!['score'], 50);
102101
});
@@ -539,8 +538,7 @@ void runPipelineExpressionsTests() {
539538
expect(e.message!, contains('Unsupported expression'));
540539
}
541540
},
542-
skip:
543-
defaultTargetPlatform != TargetPlatform.iOS &&
541+
skip: defaultTargetPlatform != TargetPlatform.iOS &&
544542
defaultTargetPlatform != TargetPlatform.macOS,
545543
);
546544
});

0 commit comments

Comments
 (0)