diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Pipeline.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Pipeline.java index c0f4c1c46..16c0e2215 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Pipeline.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Pipeline.java @@ -41,9 +41,13 @@ import com.google.cloud.firestore.pipeline.stages.AddFields; import com.google.cloud.firestore.pipeline.stages.Aggregate; import com.google.cloud.firestore.pipeline.stages.AggregateOptions; +import com.google.cloud.firestore.pipeline.stages.Delete; +import com.google.cloud.firestore.pipeline.stages.DeleteOptions; import com.google.cloud.firestore.pipeline.stages.Distinct; import com.google.cloud.firestore.pipeline.stages.FindNearest; import com.google.cloud.firestore.pipeline.stages.FindNearestOptions; +import com.google.cloud.firestore.pipeline.stages.Insert; +import com.google.cloud.firestore.pipeline.stages.InsertOptions; import com.google.cloud.firestore.pipeline.stages.Limit; import com.google.cloud.firestore.pipeline.stages.Offset; import com.google.cloud.firestore.pipeline.stages.PipelineExecuteOptions; @@ -58,6 +62,8 @@ import com.google.cloud.firestore.pipeline.stages.Union; import com.google.cloud.firestore.pipeline.stages.Unnest; import com.google.cloud.firestore.pipeline.stages.UnnestOptions; +import com.google.cloud.firestore.pipeline.stages.Upsert; +import com.google.cloud.firestore.pipeline.stages.UpsertOptions; import com.google.cloud.firestore.pipeline.stages.Where; import com.google.cloud.firestore.telemetry.MetricsUtil.MetricsContext; import com.google.cloud.firestore.telemetry.TelemetryConstants; @@ -995,6 +1001,105 @@ public Pipeline unnest(Selectable field, UnnestOptions options) { return append(new Unnest(field, options)); } + /** + * Performs a delete operation on documents from previous stages. + * + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + @BetaApi + public Pipeline delete() { + return append(new Delete()); + } + + /** + * Performs a delete operation on documents from previous stages. + * + * @param target The collection to delete from. + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + @BetaApi + public Pipeline delete(CollectionReference target) { + return append(Delete.withCollection(target)); + } + + /** + * Performs a delete operation on documents from previous stages. + * + * @param deleteStage The {@code Delete} stage to append. + * @param options The {@code DeleteOptions} to apply to the stage. + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + @BetaApi + public Pipeline delete(Delete deleteStage, DeleteOptions options) { + return append(deleteStage.withOptions(options)); + } + + /** + * Performs an upsert operation using documents from previous stages. + * + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + @BetaApi + public Pipeline upsert() { + return append(new Upsert()); + } + + /** + * Performs an upsert operation using documents from previous stages. + * + * @param target The collection to upsert to. + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + @BetaApi + public Pipeline upsert(CollectionReference target) { + return append(Upsert.withCollection(target)); + } + + /** + * Performs an upsert operation using documents from previous stages. + * + * @param upsertStage The {@code Upsert} stage to append. + * @param options The {@code UpsertOptions} to apply to the stage. + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + @BetaApi + public Pipeline upsert(Upsert upsertStage, UpsertOptions options) { + return append(upsertStage.withOptions(options)); + } + + /** + * Performs an insert operation using documents from previous stages. + * + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + @BetaApi + public Pipeline insert() { + return append(new Insert()); + } + + /** + * Performs an insert operation using documents from previous stages. + * + * @param target The collection to insert to. + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + @BetaApi + public Pipeline insert(CollectionReference target) { + return append(Insert.withCollection(target)); + } + + /** + * Performs an insert operation using documents from previous stages. + * + * @param insertStage The {@code Insert} stage to append. + * @param options The {@code InsertOptions} to apply to the stage. + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + @BetaApi + public Pipeline insert(Insert insertStage, InsertOptions options) { + return append(insertStage.withOptions(options)); + } + /** * Adds a generic stage to the pipeline. * diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/ConflictResolution.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/ConflictResolution.java new file mode 100644 index 000000000..8766b7c05 --- /dev/null +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/ConflictResolution.java @@ -0,0 +1,35 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.firestore.pipeline.stages; + +/** Defines the conflict resolution options for an Upsert pipeline stage. */ +public enum ConflictResolution { + OVERWRITE("OVERWRITE"), + MERGE("MERGE"), + FAIL("FAIL"), + KEEP("KEEP"); + + private final String value; + + ConflictResolution(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/Delete.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/Delete.java new file mode 100644 index 000000000..60dbeabac --- /dev/null +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/Delete.java @@ -0,0 +1,68 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.firestore.pipeline.stages; + +import com.google.api.core.BetaApi; +import com.google.api.core.InternalApi; +import com.google.cloud.firestore.CollectionReference; +import com.google.cloud.firestore.PipelineUtils; +import com.google.firestore.v1.Value; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; + +@InternalApi +public final class Delete extends Stage { + + @Nullable private final String path; + + private Delete(@Nullable String path, InternalOptions options) { + super("delete", options); + this.path = path; + } + + @BetaApi + public Delete() { + this(null, InternalOptions.EMPTY); + } + + @BetaApi + public static Delete withCollection(CollectionReference target) { + String path = target.getPath(); + return new Delete(path.startsWith("/") ? path : "/" + path, InternalOptions.EMPTY); + } + + @BetaApi + public Delete withOptions(DeleteOptions options) { + return new Delete(path, this.options.adding(options)); + } + + @BetaApi + public Delete withReturns(DeleteReturn returns) { + return new Delete( + path, this.options.with("returns", PipelineUtils.encodeValue(returns.getValue()))); + } + + @Override + Iterable toStageArgs() { + List args = new ArrayList<>(); + if (path != null) { + args.add(Value.newBuilder().setReferenceValue(path).build()); + } + return args; + } +} diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/DeleteOptions.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/DeleteOptions.java new file mode 100644 index 000000000..649e575b9 --- /dev/null +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/DeleteOptions.java @@ -0,0 +1,38 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.firestore.pipeline.stages; + +import com.google.api.core.BetaApi; + +/** Options for a Delete pipeline stage. */ +@BetaApi +public class DeleteOptions extends WriteOptions { + + /** Creates a new, empty `DeleteOptions` object. */ + public DeleteOptions() { + super(InternalOptions.EMPTY); + } + + DeleteOptions(InternalOptions options) { + super(options); + } + + @Override + DeleteOptions self(InternalOptions options) { + return new DeleteOptions(options); + } +} diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/DeleteReturn.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/DeleteReturn.java new file mode 100644 index 000000000..d0fefbbd6 --- /dev/null +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/DeleteReturn.java @@ -0,0 +1,33 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.firestore.pipeline.stages; + +/** Defines the return value options for a Delete pipeline stage. */ +public enum DeleteReturn { + EMPTY("EMPTY"), + DOCUMENT_ID("DOCUMENT_ID"); + + private final String value; + + DeleteReturn(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/Insert.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/Insert.java new file mode 100644 index 000000000..04555740a --- /dev/null +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/Insert.java @@ -0,0 +1,78 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.firestore.pipeline.stages; + +import com.google.api.core.BetaApi; +import com.google.api.core.InternalApi; +import com.google.cloud.firestore.CollectionReference; +import com.google.cloud.firestore.PipelineUtils; +import com.google.cloud.firestore.pipeline.expressions.Selectable; +import com.google.firestore.v1.Value; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; + +@InternalApi +public final class Insert extends Stage { + + @Nullable private final String path; + + private Insert(@Nullable String path, InternalOptions options) { + super("insert", options); + this.path = path; + } + + @BetaApi + public Insert() { + this(null, InternalOptions.EMPTY); + } + + @BetaApi + public static Insert withCollection(CollectionReference target) { + String path = target.getPath(); + return new Insert(path.startsWith("/") ? path : "/" + path, InternalOptions.EMPTY); + } + + @BetaApi + public Insert withOptions(InsertOptions options) { + return new Insert(path, this.options.adding(options)); + } + + @BetaApi + public Insert withReturns(InsertReturn returns) { + return new Insert( + path, this.options.with("returns", PipelineUtils.encodeValue(returns.getValue()))); + } + + @BetaApi + public Insert withTransformations(Selectable... transformations) { + return new Insert( + path, + this.options.with( + "transformations", + PipelineUtils.encodeValue(PipelineUtils.selectablesToMap(transformations)))); + } + + @Override + Iterable toStageArgs() { + List args = new ArrayList<>(); + if (path != null) { + args.add(Value.newBuilder().setReferenceValue(path).build()); + } + return args; + } +} diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/InsertOptions.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/InsertOptions.java new file mode 100644 index 000000000..ee5c3f65e --- /dev/null +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/InsertOptions.java @@ -0,0 +1,38 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.firestore.pipeline.stages; + +import com.google.api.core.BetaApi; + +/** Options for an Insert pipeline stage. */ +@BetaApi +public class InsertOptions extends WriteOptions { + + /** Creates a new, empty `InsertOptions` object. */ + public InsertOptions() { + super(InternalOptions.EMPTY); + } + + InsertOptions(InternalOptions options) { + super(options); + } + + @Override + InsertOptions self(InternalOptions options) { + return new InsertOptions(options); + } +} diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/InsertReturn.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/InsertReturn.java new file mode 100644 index 000000000..bd44ec2f7 --- /dev/null +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/InsertReturn.java @@ -0,0 +1,33 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.firestore.pipeline.stages; + +/** Defines the return value options for an Insert pipeline stage. */ +public enum InsertReturn { + EMPTY("EMPTY"), + DOCUMENT_ID("DOCUMENT_ID"); + + private final String value; + + InsertReturn(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/Upsert.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/Upsert.java new file mode 100644 index 000000000..8dd9c1763 --- /dev/null +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/Upsert.java @@ -0,0 +1,78 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.firestore.pipeline.stages; + +import com.google.api.core.BetaApi; +import com.google.api.core.InternalApi; +import com.google.cloud.firestore.CollectionReference; +import com.google.cloud.firestore.PipelineUtils; +import com.google.cloud.firestore.pipeline.expressions.Selectable; +import com.google.firestore.v1.Value; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; + +@InternalApi +public final class Upsert extends Stage { + + @Nullable private final String path; + + private Upsert(@Nullable String path, InternalOptions options) { + super("upsert", options); + this.path = path; + } + + @BetaApi + public Upsert() { + this(null, InternalOptions.EMPTY); + } + + @BetaApi + public static Upsert withCollection(CollectionReference target) { + String path = target.getPath(); + return new Upsert(path.startsWith("/") ? path : "/" + path, InternalOptions.EMPTY); + } + + @BetaApi + public Upsert withOptions(UpsertOptions options) { + return new Upsert(path, this.options.adding(options)); + } + + @BetaApi + public Upsert withReturns(UpsertReturn returns) { + return new Upsert( + path, this.options.with("returns", PipelineUtils.encodeValue(returns.getValue()))); + } + + @BetaApi + public Upsert withTransformations(Selectable... transformations) { + return new Upsert( + path, + this.options.with( + "transformations", + PipelineUtils.encodeValue(PipelineUtils.selectablesToMap(transformations)))); + } + + @Override + Iterable toStageArgs() { + List args = new ArrayList<>(); + if (path != null) { + args.add(Value.newBuilder().setReferenceValue(path).build()); + } + return args; + } +} diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/UpsertOptions.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/UpsertOptions.java new file mode 100644 index 000000000..98844e23e --- /dev/null +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/UpsertOptions.java @@ -0,0 +1,49 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.firestore.pipeline.stages; + +import com.google.api.core.BetaApi; + +/** Options for an Upsert pipeline stage. */ +@BetaApi +public class UpsertOptions extends WriteOptions { + + /** Creates a new, empty `UpsertOptions` object. */ + public UpsertOptions() { + super(InternalOptions.EMPTY); + } + + UpsertOptions(InternalOptions options) { + super(options); + } + + @Override + UpsertOptions self(InternalOptions options) { + return new UpsertOptions(options); + } + + /** + * Sets the conflict resolution strategy. + * + * @param conflictResolution The conflict resolution strategy. + * @return A new options object with the conflict resolution set. + */ + @BetaApi + public UpsertOptions withConflictResolution(ConflictResolution conflictResolution) { + return with("conflict_resolution", conflictResolution.getValue()); + } +} diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/UpsertReturn.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/UpsertReturn.java new file mode 100644 index 000000000..4f7ee7089 --- /dev/null +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/UpsertReturn.java @@ -0,0 +1,33 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.firestore.pipeline.stages; + +/** Defines the return value options for an Upsert pipeline stage. */ +public enum UpsertReturn { + EMPTY("EMPTY"), + DOCUMENT_ID("DOCUMENT_ID"); + + private final String value; + + UpsertReturn(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/WriteOptions.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/WriteOptions.java new file mode 100644 index 000000000..ac4dd92c1 --- /dev/null +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/stages/WriteOptions.java @@ -0,0 +1,39 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.firestore.pipeline.stages; + +import com.google.api.core.BetaApi; + +/** Options for write stages in a pipeline. */ +@BetaApi +public abstract class WriteOptions> extends AbstractOptions { + + WriteOptions(InternalOptions options) { + super(options); + } + + /** + * Sets the transactional option. + * + * @param transactional Whether the operation should be transactional. + * @return A new options object with the transactional option set. + */ + @BetaApi + public T withTransactional(boolean transactional) { + return with("transactional", transactional); + } +} diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java index 6fd9075b7..f3cf66232 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java @@ -95,14 +95,24 @@ import com.google.cloud.firestore.pipeline.stages.AggregateOptions; import com.google.cloud.firestore.pipeline.stages.CollectionHints; import com.google.cloud.firestore.pipeline.stages.CollectionOptions; +import com.google.cloud.firestore.pipeline.stages.ConflictResolution; +import com.google.cloud.firestore.pipeline.stages.Delete; +import com.google.cloud.firestore.pipeline.stages.DeleteOptions; +import com.google.cloud.firestore.pipeline.stages.DeleteReturn; import com.google.cloud.firestore.pipeline.stages.ExplainOptions; import com.google.cloud.firestore.pipeline.stages.FindNearest; import com.google.cloud.firestore.pipeline.stages.FindNearestOptions; +import com.google.cloud.firestore.pipeline.stages.Insert; +import com.google.cloud.firestore.pipeline.stages.InsertOptions; +import com.google.cloud.firestore.pipeline.stages.InsertReturn; import com.google.cloud.firestore.pipeline.stages.PipelineExecuteOptions; import com.google.cloud.firestore.pipeline.stages.RawOptions; import com.google.cloud.firestore.pipeline.stages.RawStage; import com.google.cloud.firestore.pipeline.stages.Sample; import com.google.cloud.firestore.pipeline.stages.UnnestOptions; +import com.google.cloud.firestore.pipeline.stages.Upsert; +import com.google.cloud.firestore.pipeline.stages.UpsertOptions; +import com.google.cloud.firestore.pipeline.stages.UpsertReturn; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; @@ -2317,6 +2327,79 @@ public void testUnion() throws Exception { assertThat(results).hasSize(22); } + @Test + public void testDelete() throws Exception { + firestore + .pipeline() + .collection(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .delete() + .execute() + .get(); + + firestore + .pipeline() + .collection(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .delete( + new Delete().withReturns(DeleteReturn.DOCUMENT_ID), + new DeleteOptions().withTransactional(true)) + .execute() + .get(); + } + + @Test + public void testUpsert() throws Exception { + firestore + .pipeline() + .collection(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .upsert() + .execute() + .get(); + + firestore + .pipeline() + .collection(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .upsert(collection) + .execute() + .get(); + + firestore + .pipeline() + .collection(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .upsert( + new Upsert().withReturns(UpsertReturn.DOCUMENT_ID), + new UpsertOptions() + .withConflictResolution(ConflictResolution.MERGE) + .withTransactional(true)) + .execute() + .get(); + } + + @Test + public void testInsert() throws Exception { + firestore + .pipeline() + .collection(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .insert(collection) + .execute() + .get(); + + firestore + .pipeline() + .collection(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .insert( + new Insert().withReturns(InsertReturn.DOCUMENT_ID), + new InsertOptions().withTransactional(true)) + .execute() + .get(); + } + @Test public void testUnnest() throws Exception { List results =