Skip to content
This repository was archived by the owner on May 8, 2026. It is now read-only.

Commit dca7f0f

Browse files
authored
Merge branch 'main' into mila/arraySlice-arrayFilter
2 parents b52ebd8 + cbf87ac commit dca7f0f

12 files changed

Lines changed: 821 additions & 174 deletions

File tree

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
name: Verify Local Changes
3+
description: Verifies local Java SDK changes.
4+
---
5+
6+
# Verify Local Changes
7+
8+
This skill documents how to verify local code changes for the Java Firestore SDK. This should be run **every time** you complete a fix or feature and are prepared to push a pull request.
9+
10+
## Prerequisites
11+
12+
Ensure you have Maven installed and are in the `java-firestore` directory before running commands.
13+
14+
---
15+
16+
## Step 0: Format the Code
17+
18+
Run the formatter to ensure formatting checks pass:
19+
20+
```bash
21+
mvn com.spotify.fmt:fmt-maven-plugin:format
22+
```
23+
24+
---
25+
26+
## Step 1: Unit Testing (Isolated then Suite)
27+
28+
1. **Identify modified unit tests** in your changes.
29+
2. **Run specific units only** to test isolated logic regressions:
30+
```bash
31+
mvn test -Dtest=MyUnitTest#testMethod
32+
```
33+
3. **Run the entire unit test suite** that contains those modified tests if the isolated unit tests pass:
34+
```bash
35+
mvn test -Dtest=MyUnitTest
36+
```
37+
38+
---
39+
40+
## Step 2: Integration Testing (Isolated then Suite)
41+
42+
### 💡 Integration Test Nuances (from `ITBaseTest.java`)
43+
44+
When running integration tests, configure your execution using properties or environment variables:
45+
46+
- **`FIRESTORE_EDITION`**:
47+
- `standard` (Default)
48+
- `enterprise`
49+
- *Note*: **Pipelines can only be run against `enterprise` editions**, while standard Queries run on both.
50+
- **`FIRESTORE_NAMED_DATABASE`**:
51+
- Enterprise editions usually require a named database (often `enterprise`). Adjust this flag if pointing to specific instances.
52+
- **`FIRESTORE_TARGET_BACKEND`**:
53+
- `PROD` (Default)
54+
- `QA` (points to standard sandboxes)
55+
- `NIGHTLY` (points to `test-firestore.sandbox.googleapis.com:443`)
56+
- `EMULATOR` (points to `localhost:8080`)
57+
58+
1. **Identify modified integration tests** (usually Starting in `IT`).
59+
2. **Run specific integration tests only** (isolated checks run quicker):
60+
```bash
61+
mvn verify -Penable-integration-tests -DFIRESTORE_EDITION=enterprise -DFIRESTORE_NAMED_DATABASE=enterprise -Dtest=ITTest#testMethod -Dclirr.skip=true -Denforcer.skip=true -fae
62+
```
63+
3. **Run the entire integration test suite** for the modified class if isolation tests pass:
64+
```bash
65+
mvn verify -Penable-integration-tests -DFIRESTORE_EDITION=enterprise -DFIRESTORE_NAMED_DATABASE=enterprise -Dtest=ITTest -Dclirr.skip=true -Denforcer.skip=true -fae
66+
```
67+
68+
69+
70+
---
71+
72+
## Step 3: Full Suite Regressions
73+
74+
Run the full integration regression suite once you are confident subsets pass:
75+
76+
```bash
77+
mvn verify -Penable-integration-tests -DFIRESTORE_EDITION=enterprise -DFIRESTORE_NAMED_DATABASE=enterprise -Dclirr.skip=true -Denforcer.skip=true -fae
78+
```
79+
80+
---
81+
82+
> [!TIP]
83+
> Use `-Dclirr.skip=true -Denforcer.skip=true` to speed up iterations where appropriate without leaking compliance checks.
84+
85+
---
86+
87+
## 🛠️ Troubleshooting & Source of Truth
88+
89+
If you run into issues executing tests with the commands above, **consult the Kokoro configuration files** as the ultimate source of truth:
90+
91+
- **Presubmit configurations**: See `.kokoro/presubmit/integration.cfg` (or `integration-named-db.cfg`)
92+
- **Nightly configurations**: See `.kokoro/nightly/integration.cfg`
93+
- **Build shell scripts**: See `.kokoro/build.sh`
94+
95+
These files define the exact environment variables (e.g., specific endpoints or endpoints overrides) the CI server uses!

google-cloud-firestore/src/main/java/com/google/cloud/firestore/Pipeline.java

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.google.cloud.firestore.pipeline.stages.Aggregate;
4444
import com.google.cloud.firestore.pipeline.stages.AggregateOptions;
4545
import com.google.cloud.firestore.pipeline.stages.Define;
46+
import com.google.cloud.firestore.pipeline.stages.Delete;
4647
import com.google.cloud.firestore.pipeline.stages.Distinct;
4748
import com.google.cloud.firestore.pipeline.stages.FindNearest;
4849
import com.google.cloud.firestore.pipeline.stages.FindNearestOptions;
@@ -60,6 +61,7 @@
6061
import com.google.cloud.firestore.pipeline.stages.Union;
6162
import com.google.cloud.firestore.pipeline.stages.Unnest;
6263
import com.google.cloud.firestore.pipeline.stages.UnnestOptions;
64+
import com.google.cloud.firestore.pipeline.stages.Update;
6365
import com.google.cloud.firestore.pipeline.stages.Where;
6466
import com.google.cloud.firestore.telemetry.MetricsUtil.MetricsContext;
6567
import com.google.cloud.firestore.telemetry.TelemetryConstants;
@@ -1055,7 +1057,6 @@ public Pipeline sample(Sample sample) {
10551057
* @param other The other {@code Pipeline} that is part of union.
10561058
* @return A new {@code Pipeline} object with this stage appended to the stage list.
10571059
*/
1058-
@BetaApi
10591060
public Pipeline union(Pipeline other) {
10601061
if (other.rpcContext == null) {
10611062
throw new IllegalArgumentException(
@@ -1213,7 +1214,119 @@ public Pipeline unnest(Selectable field, UnnestOptions options) {
12131214
}
12141215

12151216
/**
1216-
* Adds a generic stage to the pipeline.
1217+
* Performs a delete operation on documents from previous stages.
1218+
*
1219+
* <p>Example:
1220+
*
1221+
* <pre>{@code
1222+
* // Delete all documents in the "logs" collection where "status" is "archived"
1223+
* firestore.pipeline()
1224+
* .collection("logs")
1225+
* .where(field("status").equal("archived"))
1226+
* .delete()
1227+
* .execute()
1228+
* .get();
1229+
* }</pre>
1230+
*
1231+
* @return A new {@code Pipeline} object with this stage appended to the stage list.
1232+
*/
1233+
@BetaApi
1234+
public Pipeline delete() {
1235+
return append(new Delete());
1236+
}
1237+
1238+
/**
1239+
* Performs an update operation using documents from previous stages.
1240+
*
1241+
* <p>This method updates the documents in place based on the data flowing through the pipeline.
1242+
* To specify transformations, use {@link #update(Selectable...)}.
1243+
*
1244+
* <p>Example 1: Update a collection's schema by adding a new field and removing an old one.
1245+
*
1246+
* <pre>{@code
1247+
* firestore.pipeline()
1248+
* .collection("books")
1249+
* .addFields(constant("Fiction").as("genre"))
1250+
* .removeFields("old_genre")
1251+
* .update()
1252+
* .execute()
1253+
* .get();
1254+
* }</pre>
1255+
*
1256+
* <p>Example 2: Update documents in place with data from literals.
1257+
*
1258+
* <pre>{@code
1259+
* Map<String, Object> updateData = new HashMap<>();
1260+
* updateData.put("__name__", firestore.collection("books").document("book1"));
1261+
* updateData.put("status", "Updated");
1262+
*
1263+
* firestore.pipeline()
1264+
* .literals(updateData)
1265+
* .update()
1266+
* .execute()
1267+
* .get();
1268+
* }</pre>
1269+
*
1270+
* @return A new {@code Pipeline} object with this stage appended to the stage list.
1271+
*/
1272+
@BetaApi
1273+
public Pipeline update() {
1274+
return append(new Update());
1275+
}
1276+
1277+
/**
1278+
* Performs an update operation using documents from previous stages with specified
1279+
* transformations.
1280+
*
1281+
* <p>Example:
1282+
*
1283+
* <pre>{@code
1284+
* // Update the "status" field to "Discounted" for all books where price > 50
1285+
* firestore.pipeline()
1286+
* .collection("books")
1287+
* .where(field("price").greaterThan(50))
1288+
* .update(constant("Discounted").as("status"))
1289+
* .execute()
1290+
* .get();
1291+
* }</pre>
1292+
*
1293+
* @param transformedFields The transformations to apply.
1294+
* @return A new {@code Pipeline} object with this stage appended to the stage list.
1295+
*/
1296+
@BetaApi
1297+
public Pipeline update(Selectable... transformedFields) {
1298+
return append(new Update().withTransformedFields(transformedFields));
1299+
}
1300+
1301+
/**
1302+
* Performs an update operation using an {@link Update} stage.
1303+
*
1304+
* <p>This method allows you to use a pre-configured {@link Update} stage.
1305+
*
1306+
* <p>Example:
1307+
*
1308+
* <pre>{@code
1309+
* Update updateStage = new Update().withTransformedFields(constant("Updated").as("status"));
1310+
*
1311+
* firestore.pipeline()
1312+
* .collection("books")
1313+
* .where(field("title").equal("The Hitchhiker's Guide to the Galaxy"))
1314+
* .update(updateStage)
1315+
* .execute()
1316+
* .get();
1317+
* }</pre>
1318+
*
1319+
* @param update The {@code Update} stage to append.
1320+
* @return A new {@code Pipeline} object with this stage appended to the stage list.
1321+
*/
1322+
@BetaApi
1323+
public Pipeline update(Update update) {
1324+
return append(update);
1325+
}
1326+
1327+
/**
1328+
* Performs an insert operation using documents from previous stages. Adds a generic stage to the
1329+
* pipeline.
12171330
*
12181331
* <p>This method provides a flexible way to extend the pipeline's functionality by adding custom
12191332
* stages. Each generic stage is defined by a unique `name` and a set of `params` that control its

google-cloud-firestore/src/main/java/com/google/cloud/firestore/PipelineSource.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.google.cloud.firestore.pipeline.stages.CollectionOptions;
2525
import com.google.cloud.firestore.pipeline.stages.Database;
2626
import com.google.cloud.firestore.pipeline.stages.Documents;
27+
import com.google.cloud.firestore.pipeline.stages.Literals;
2728
import com.google.cloud.firestore.pipeline.stages.Subcollection;
2829
import com.google.common.base.Preconditions;
2930
import java.util.Arrays;
@@ -158,6 +159,32 @@ public Pipeline documents(String... docs) {
158159
.toArray(DocumentReference[]::new)));
159160
}
160161

162+
/**
163+
* Creates a new {@link Pipeline} that operates on a static set of documents represented as Maps.
164+
*
165+
* <p>Example:
166+
*
167+
* <pre>{@code
168+
* Map<String, Object> doc1 = new HashMap<>();
169+
* doc1.put("title", "Book 1");
170+
* Map<String, Object> doc2 = new HashMap<>();
171+
* doc2.put("title", "Book 2");
172+
*
173+
* Snapshot snapshot = firestore.pipeline()
174+
* .literals(doc1, doc2)
175+
* .execute()
176+
* .get();
177+
* }</pre>
178+
*
179+
* @param data The Maps representing documents to include in the pipeline.
180+
* @return A new {@code Pipeline} instance with a literals source.
181+
*/
182+
@Nonnull
183+
@BetaApi
184+
public final Pipeline literals(java.util.Map<String, Object>... data) {
185+
return new Pipeline(this.rpcContext, new Literals(data));
186+
}
187+
161188
/**
162189
* Creates a new {@link Pipeline} from the given {@link Query}. Under the hood, this will
163190
* translate the query semantics (order by document ID, etc.) to an equivalent pipeline.

0 commit comments

Comments
 (0)