Skip to content

Commit 1bd970e

Browse files
committed
Merge branch 'firestore-pipelines-dart-api-v2' into firestore-pipelines-android
2 parents bf77d38 + 3a8ae50 commit 1bd970e

52 files changed

Lines changed: 1216 additions & 1368 deletions

File tree

Some content is hidden

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

.github/workflows/e2e_tests_pipeline.yaml

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,25 @@ concurrency:
44
group: ${{ github.workflow }}-${{ github.ref }}
55
cancel-in-progress: true
66

7-
# on:
8-
# pull_request:
9-
# paths:
10-
# - 'packages/cloud_firestore/cloud_firestore/pipeline_example/**'
11-
# - 'packages/cloud_firestore/cloud_firestore/lib/**'
12-
# - '.github/workflows/e2e_tests_pipeline.yaml'
13-
# push:
14-
# branches:
15-
# - main
16-
# - firestore-pipelines-dart-api-v2
17-
# - master
18-
# paths:
19-
# - 'packages/cloud_firestore/cloud_firestore/pipeline_example/**'
20-
# - 'packages/cloud_firestore/cloud_firestore/lib/**'
21-
# - '.github/workflows/e2e_tests_pipeline.yaml'
22-
237
on:
248
pull_request:
9+
paths:
10+
- 'packages/cloud_firestore/cloud_firestore/pipeline_example/**'
11+
- 'packages/cloud_firestore/cloud_firestore/lib/**'
12+
- '.github/workflows/e2e_tests_pipeline.yaml'
2513
push:
26-
workflow_dispatch:
14+
branches:
15+
- main
16+
- firestore-pipelines-dart-api-v2
17+
- firestore-pipelines-ios
18+
- firestore-pipelines-android
19+
- firestore-pipelines-web
20+
paths:
21+
- 'packages/cloud_firestore/cloud_firestore/pipeline_example/**'
22+
- 'packages/cloud_firestore/cloud_firestore/lib/**'
23+
- 'packages/cloud_firestore/cloud_firestore/ios/**'
24+
- 'packages/cloud_firestore/cloud_firestore/macos/**'
25+
- '.github/workflows/e2e_tests_pipeline.yaml'
2726

2827
jobs:
2928
pipeline-e2e-android:
@@ -177,6 +176,8 @@ jobs:
177176
cache: true
178177
cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:"
179178
pub-cache-key: "flutter-pub-:os:-:channel:-:version:-:arch:-:hash:"
179+
- name: Enable Swift Package Manager for iOS
180+
run: flutter config --enable-swift-package-manager
180181
- uses: bluefireteam/melos-action@c7dcb921b23cc520cace360b95d02b37bf09cdaa
181182
with:
182183
run-bootstrap: false
@@ -192,6 +193,12 @@ jobs:
192193
echo "$GOOGLE_SERVICE_INFO_PLIST" > packages/cloud_firestore/cloud_firestore/pipeline_example/ios/Runner/GoogleService-Info.plist
193194
- name: Bootstrap package
194195
run: melos bootstrap --scope "cloud_firestore*"
196+
- name: Prepare iOS project for Swift Package Manager
197+
working-directory: packages/cloud_firestore/cloud_firestore/pipeline_example/ios
198+
run: |
199+
if [ -f Podfile ]; then pod deintegrate; fi
200+
rm -f Podfile Podfile.lock
201+
rm -rf Pods
195202
- uses: futureware-tech/simulator-action@e89aa8f93d3aec35083ff49d2854d07f7186f7f5
196203
id: simulator
197204
with:

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
@@ -888,38 +888,62 @@ public void writeBatchCommit(
888888
GeneratedAndroidFirebaseFirestore.PigeonTransactionType type =
889889
Objects.requireNonNull(write.getType());
890890
String path = Objects.requireNonNull(write.getPath());
891-
Map<String, Object> data = write.getData();
892-
893891
DocumentReference documentReference = firestore.document(path);
894892

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

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
@@ -1214,13 +1214,13 @@ public void setPath(@NonNull String setterArg) {
12141214
this.path = setterArg;
12151215
}
12161216

1217-
private @Nullable Map<String, Object> data;
1217+
private @Nullable Map<Object, Object> data;
12181218

1219-
public @Nullable Map<String, Object> getData() {
1219+
public @Nullable Map<Object, Object> getData() {
12201220
return data;
12211221
}
12221222

1223-
public void setData(@Nullable Map<String, Object> setterArg) {
1223+
public void setData(@Nullable Map<Object, Object> setterArg) {
12241224
this.data = setterArg;
12251225
}
12261226

@@ -1253,9 +1253,9 @@ public static final class Builder {
12531253
return this;
12541254
}
12551255

1256-
private @Nullable Map<String, Object> data;
1256+
private @Nullable Map<Object, Object> data;
12571257

1258-
public @NonNull Builder setData(@Nullable Map<String, Object> setterArg) {
1258+
public @NonNull Builder setData(@Nullable Map<Object, Object> setterArg) {
12591259
this.data = setterArg;
12601260
return this;
12611261
}
@@ -1294,7 +1294,7 @@ public ArrayList<Object> toList() {
12941294
Object path = list.get(1);
12951295
pigeonResult.setPath((String) path);
12961296
Object data = list.get(2);
1297-
pigeonResult.setData((Map<String, Object>) data);
1297+
pigeonResult.setData((Map<Object, Object>) data);
12981298
Object option = list.get(3);
12991299
pigeonResult.setOption(
13001300
(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
@@ -463,7 +463,7 @@ - (NSArray *)toList {
463463
@implementation PigeonTransactionCommand
464464
+ (instancetype)makeWithType:(PigeonTransactionType)type
465465
path:(NSString *)path
466-
data:(nullable NSDictionary<NSString *, id> *)data
466+
data:(nullable NSDictionary<id, id> *)data
467467
option:(nullable PigeonDocumentOption *)option {
468468
PigeonTransactionCommand *pigeonResult = [[PigeonTransactionCommand alloc] init];
469469
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
@@ -264,11 +264,11 @@ typedef NS_ENUM(NSUInteger, AggregateType) {
264264
- (instancetype)init NS_UNAVAILABLE;
265265
+ (instancetype)makeWithType:(PigeonTransactionType)type
266266
path:(NSString *)path
267-
data:(nullable NSDictionary<NSString *, id> *)data
267+
data:(nullable NSDictionary<id, id> *)data
268268
option:(nullable PigeonDocumentOption *)option;
269269
@property(nonatomic, assign) PigeonTransactionType type;
270270
@property(nonatomic, copy) NSString *path;
271-
@property(nonatomic, strong, nullable) NSDictionary<NSString *, id> *data;
271+
@property(nonatomic, strong, nullable) NSDictionary<id, id> *data;
272272
@property(nonatomic, strong, nullable) PigeonDocumentOption *option;
273273
@end
274274

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
}

0 commit comments

Comments
 (0)