Skip to content

Commit 963bf5d

Browse files
authored
Merge 8a58ed2 into 95bbf92
2 parents 95bbf92 + 8a58ed2 commit 963bf5d

38 files changed

+10313
-765
lines changed

firebase-firestore/CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Unreleased
2-
2+
* [feature] Pipelines
33

44
# 25.1.2
55
* [fixed] Fixed a server and sdk mismatch in unicode string sorting. [#6615](//github.com/firebase/firebase-android-sdk/pull/6615)

firebase-firestore/api.txt

+1,020-1
Large diffs are not rendered by default.

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java

+899
Large diffs are not rendered by default.

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java

+964
Large diffs are not rendered by default.

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java

+41-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
import com.google.firebase.firestore.FirebaseFirestoreSettings;
3939
import com.google.firebase.firestore.ListenerRegistration;
4040
import com.google.firebase.firestore.MetadataChanges;
41+
import com.google.firebase.firestore.PipelineResult;
42+
import com.google.firebase.firestore.PipelineSnapshot;
4143
import com.google.firebase.firestore.Query;
4244
import com.google.firebase.firestore.QuerySnapshot;
4345
import com.google.firebase.firestore.Source;
@@ -98,7 +100,7 @@ public enum TargetBackend {
98100

99101
// Set this to the desired enum value to change the target backend when running tests locally.
100102
// Note: DO NOT change this variable except for local testing.
101-
private static final TargetBackend backendForLocalTesting = null;
103+
private static final TargetBackend backendForLocalTesting = TargetBackend.NIGHTLY;
102104

103105
private static final TargetBackend backend = getTargetBackend();
104106
private static final String EMULATOR_HOST = "10.0.2.2";
@@ -465,6 +467,15 @@ public static List<Map<String, Object>> querySnapshotToValues(QuerySnapshot quer
465467
return res;
466468
}
467469

470+
public static List<Map<String, Object>> pipelineSnapshotToValues(
471+
PipelineSnapshot pipelineSnapshot) {
472+
List<Map<String, Object>> res = new ArrayList<>();
473+
for (PipelineResult result : pipelineSnapshot) {
474+
res.add(result.getData());
475+
}
476+
return res;
477+
}
478+
468479
public static List<String> querySnapshotToIds(QuerySnapshot querySnapshot) {
469480
List<String> res = new ArrayList<>();
470481
for (DocumentSnapshot doc : querySnapshot) {
@@ -473,6 +484,15 @@ public static List<String> querySnapshotToIds(QuerySnapshot querySnapshot) {
473484
return res;
474485
}
475486

487+
public static List<String> pipelineSnapshotToIds(PipelineSnapshot pipelineResults) {
488+
List<String> res = new ArrayList<>();
489+
for (PipelineResult result : pipelineResults) {
490+
DocumentReference ref = result.getRef();
491+
res.add(ref == null ? null : ref.getId());
492+
}
493+
return res;
494+
}
495+
476496
public static void disableNetwork(FirebaseFirestore firestore) {
477497
if (firestoreStatus.get(firestore)) {
478498
waitFor(firestore.disableNetwork());
@@ -537,4 +557,24 @@ public static void checkOnlineAndOfflineResultsMatch(Query query, String... expe
537557
assertEquals(expected, querySnapshotToIds(docsFromCache));
538558
}
539559
}
560+
561+
/**
562+
* Checks that running the query while online (against the backend/emulator) results in the same
563+
* documents as running the query while offline. If `expectedDocs` is provided, it also checks
564+
* that both online and offline query result is equal to the expected documents.
565+
*
566+
* @param query The query to check
567+
* @param expectedDocs Ordered list of document keys that are expected to match the query
568+
*/
569+
public static void checkQueryAndPipelineResultsMatch(Query query, String... expectedDocs) {
570+
QuerySnapshot docsFromQuery = waitFor(query.get(Source.SERVER));
571+
PipelineSnapshot docsFromPipeline =
572+
waitFor(query.getFirestore().pipeline().convertFrom(query).execute());
573+
574+
assertEquals(querySnapshotToIds(docsFromQuery), pipelineSnapshotToIds(docsFromPipeline));
575+
List<String> expected = asList(expectedDocs);
576+
if (!expected.isEmpty()) {
577+
assertEquals(expected, querySnapshotToIds(docsFromQuery));
578+
}
579+
}
540580
}

firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java

+25
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@
1414

1515
package com.google.firebase.firestore;
1616

17+
import static com.google.firebase.firestore.pipeline.Expr.field;
18+
1719
import androidx.annotation.NonNull;
1820
import androidx.annotation.Nullable;
1921
import androidx.annotation.RestrictTo;
22+
import com.google.firebase.firestore.pipeline.AggregateFunction;
23+
import com.google.firebase.firestore.pipeline.AggregateWithAlias;
2024
import java.util.Objects;
2125

2226
/** Represents an aggregation that can be performed by Firestore. */
@@ -61,6 +65,9 @@ public String getOperator() {
6165
return operator;
6266
}
6367

68+
@NonNull
69+
abstract AggregateWithAlias toPipeline();
70+
6471
/**
6572
* Returns true if the given object is equal to this object. Two `AggregateField` objects are
6673
* considered equal if they have the same operator and operate on the same field.
@@ -195,19 +202,37 @@ public static class CountAggregateField extends AggregateField {
195202
private CountAggregateField() {
196203
super(null, "count");
197204
}
205+
206+
@NonNull
207+
@Override
208+
AggregateWithAlias toPipeline() {
209+
return AggregateFunction.countAll().alias(getAlias());
210+
}
198211
}
199212

200213
/** Represents a "sum" aggregation that can be performed by Firestore. */
201214
public static class SumAggregateField extends AggregateField {
202215
private SumAggregateField(@NonNull FieldPath fieldPath) {
203216
super(fieldPath, "sum");
204217
}
218+
219+
@NonNull
220+
@Override
221+
AggregateWithAlias toPipeline() {
222+
return field(getFieldPath()).sum().alias(getAlias());
223+
}
205224
}
206225

207226
/** Represents an "average" aggregation that can be performed by Firestore. */
208227
public static class AverageAggregateField extends AggregateField {
209228
private AverageAggregateField(@NonNull FieldPath fieldPath) {
210229
super(fieldPath, "average");
211230
}
231+
232+
@NonNull
233+
@Override
234+
AggregateWithAlias toPipeline() {
235+
return field(getFieldPath()).avg().alias(getAlias());
236+
}
212237
}
213238
}

firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentReference.java

+19-4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import android.app.Activity;
2323
import androidx.annotation.NonNull;
2424
import androidx.annotation.Nullable;
25+
import androidx.annotation.RestrictTo;
2526
import com.google.android.gms.tasks.Task;
2627
import com.google.android.gms.tasks.TaskCompletionSource;
2728
import com.google.android.gms.tasks.Tasks;
@@ -33,6 +34,7 @@
3334
import com.google.firebase.firestore.core.UserData.ParsedSetData;
3435
import com.google.firebase.firestore.core.UserData.ParsedUpdateData;
3536
import com.google.firebase.firestore.core.ViewSnapshot;
37+
import com.google.firebase.firestore.model.DatabaseId;
3638
import com.google.firebase.firestore.model.Document;
3739
import com.google.firebase.firestore.model.DocumentKey;
3840
import com.google.firebase.firestore.model.ResourcePath;
@@ -57,17 +59,15 @@
5759
* in test mocks. Subclassing is not supported in production code and new SDK releases may break
5860
* code that does so.
5961
*/
60-
public class DocumentReference {
62+
public final class DocumentReference {
6163

6264
private final DocumentKey key;
6365

6466
private final FirebaseFirestore firestore;
6567

6668
DocumentReference(DocumentKey key, FirebaseFirestore firestore) {
6769
this.key = checkNotNull(key);
68-
// TODO: We should checkNotNull(firestore), but tests are currently cheating
69-
// and setting it to null.
70-
this.firestore = firestore;
70+
this.firestore = checkNotNull(firestore);
7171
}
7272

7373
/** @hide */
@@ -120,6 +120,15 @@ public String getPath() {
120120
return key.getPath().canonicalString();
121121
}
122122

123+
@RestrictTo(RestrictTo.Scope.LIBRARY)
124+
@NonNull
125+
public String getFullPath() {
126+
DatabaseId databaseId = firestore.getDatabaseId();
127+
return String.format(
128+
"projects/%s/databases/%s/documents/%s",
129+
databaseId.getProjectId(), databaseId.getDatabaseId(), getPath());
130+
}
131+
123132
/**
124133
* Gets a {@code CollectionReference} instance that refers to the subcollection at the specified
125134
* path relative to this document.
@@ -564,6 +573,12 @@ public int hashCode() {
564573
return result;
565574
}
566575

576+
@NonNull
577+
@Override
578+
public String toString() {
579+
return "DocumentReference{" + "key=" + key + ", firestore=" + firestore + '}';
580+
}
581+
567582
private com.google.firebase.firestore.core.Query asQuery() {
568583
return com.google.firebase.firestore.core.Query.atPath(key.getPath());
569584
}

firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentSnapshot.java

+1
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ public int hashCode() {
555555
return hash;
556556
}
557557

558+
@NonNull
558559
@Override
559560
public String toString() {
560561
return "DocumentSnapshot{" + "key=" + key + ", metadata=" + metadata + ", doc=" + doc + '}';

firebase-firestore/src/main/java/com/google/firebase/firestore/FieldPath.java

+10-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static com.google.firebase.firestore.util.Preconditions.checkNotNull;
1919

2020
import androidx.annotation.NonNull;
21+
import androidx.annotation.RestrictTo;
2122
import java.util.Arrays;
2223
import java.util.List;
2324
import java.util.regex.Pattern;
@@ -33,15 +34,18 @@ public final class FieldPath {
3334

3435
private final com.google.firebase.firestore.model.FieldPath internalPath;
3536

36-
private FieldPath(List<String> segments) {
37+
private FieldPath(@NonNull List<String> segments) {
3738
this.internalPath = com.google.firebase.firestore.model.FieldPath.fromSegments(segments);
3839
}
3940

40-
private FieldPath(com.google.firebase.firestore.model.FieldPath internalPath) {
41+
private FieldPath(@NonNull com.google.firebase.firestore.model.FieldPath internalPath) {
4142
this.internalPath = internalPath;
4243
}
4344

44-
com.google.firebase.firestore.model.FieldPath getInternalPath() {
45+
/** @hide */
46+
@RestrictTo(RestrictTo.Scope.LIBRARY)
47+
@NonNull
48+
public com.google.firebase.firestore.model.FieldPath getInternalPath() {
4549
return internalPath;
4650
}
4751

@@ -78,7 +82,9 @@ public static FieldPath documentId() {
7882
}
7983

8084
/** Parses a field path string into a {@code FieldPath}, treating dots as separators. */
81-
static FieldPath fromDotSeparatedPath(@NonNull String path) {
85+
@RestrictTo(RestrictTo.Scope.LIBRARY)
86+
@NonNull
87+
public static FieldPath fromDotSeparatedPath(@NonNull String path) {
8288
checkNotNull(path, "Provided field path must not be null.");
8389
checkArgument(
8490
!RESERVED.matcher(path).find(), "Use FieldPath.of() for field names containing '~*/[]'.");

firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java

+13
Original file line numberDiff line numberDiff line change
@@ -850,10 +850,12 @@ <T> T callClient(Function<FirestoreClient, T> call) {
850850
return clientProvider.call(call);
851851
}
852852

853+
@NonNull
853854
DatabaseId getDatabaseId() {
854855
return databaseId;
855856
}
856857

858+
@NonNull
857859
UserDataReader getUserDataReader() {
858860
return userDataReader;
859861
}
@@ -881,4 +883,15 @@ void validateReference(DocumentReference docRef) {
881883
static void setClientLanguage(@NonNull String languageToken) {
882884
FirestoreChannel.setClientLanguage(languageToken);
883885
}
886+
887+
/**
888+
* Build a new Pipeline
889+
*
890+
* @return {@code PipelineSource} for this Firestore instance.
891+
*/
892+
@NonNull
893+
public PipelineSource pipeline() {
894+
clientProvider.ensureConfigured();
895+
return new PipelineSource(this);
896+
}
884897
}

firebase-firestore/src/main/java/com/google/firebase/firestore/Firestore.kt

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import com.google.firebase.Firebase
2121
import com.google.firebase.FirebaseApp
2222
import com.google.firebase.components.Component
2323
import com.google.firebase.components.ComponentRegistrar
24-
import com.google.firebase.firestore.*
2524
import com.google.firebase.firestore.util.Executors.BACKGROUND_EXECUTOR
2625
import kotlinx.coroutines.cancel
2726
import kotlinx.coroutines.channels.awaitClose

0 commit comments

Comments
 (0)