diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index d304652e1c..dc05a72762 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -1,4 +1,4 @@ -# Copyright 2023 Google LLC +# 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. @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-java:latest - digest: sha256:6f431774e11cc46619cf093fd1481193c4024031073697fa18f0099b943aab88 -# created: 2023-12-01T19:50:20.444857406Z + digest: sha256:a6aa751984f1e905c3ae5a3aac78fc7b68210626ce91487dc7ff4f0a06f010cc +# created: 2024-01-22T14:14:20.913785597Z diff --git a/.github/workflows/renovate_config_check.yaml b/.github/workflows/renovate_config_check.yaml new file mode 100644 index 0000000000..87d8eb2be8 --- /dev/null +++ b/.github/workflows/renovate_config_check.yaml @@ -0,0 +1,25 @@ +name: Renovate Bot Config Validation + +on: + pull_request: + paths: + - 'renovate.json' + +jobs: + renovate_bot_config_validation: + runs-on: ubuntu-22.04 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' + + - name: Install Renovate and Config Validator + run: | + npm install -g npm@latest + npm install --global renovate + renovate-config-validator diff --git a/.github/workflows/unmanaged-dependency-check.yaml b/.github/workflows/unmanaged-dependency-check.yaml new file mode 100644 index 0000000000..ef0f492d2f --- /dev/null +++ b/.github/workflows/unmanaged-dependency-check.yaml @@ -0,0 +1,19 @@ +on: + pull_request: +name: Unmanaged dependency check +jobs: + unmanaged_dependency_check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 11 + - name: Install modules + shell: bash + run: .kokoro/build.sh + - name: Unmanaged dependency check + uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@unmanaged-dependencies-check-latest + with: + bom-path: google-cloud-firestore-bom/pom.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 4279169666..f47fb6be37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## [3.16.1](https://github.com/googleapis/java-firestore/compare/v3.16.0...v3.16.1) (2024-01-25) + + +### Bug Fixes + +* `internalStream` should handle duplicate `onComplete`s. ([#1523](https://github.com/googleapis/java-firestore/issues/1523)) ([b3067d7](https://github.com/googleapis/java-firestore/commit/b3067d7b382ea5c4c9124a12a701abe2f7289503)) +* Allow an explicit MustExist precondition for update ([#1542](https://github.com/googleapis/java-firestore/issues/1542)) ([46e09aa](https://github.com/googleapis/java-firestore/commit/46e09aad7f6689d4dfe82bd284905d52edda4364)) +* **deps:** Update the Java code generator (gapic-generator-java) to 2.32.0 ([#1534](https://github.com/googleapis/java-firestore/issues/1534)) ([2281320](https://github.com/googleapis/java-firestore/commit/2281320fd924a1d6c259a493ce703a51f0cd8a03)) +* Make rollback best effort. ([#1515](https://github.com/googleapis/java-firestore/issues/1515)) ([4c39af5](https://github.com/googleapis/java-firestore/commit/4c39af50d6d416440164fc5d5360f3912cd8f01b)) +* Thread safe UpdateBuilder ([#1537](https://github.com/googleapis/java-firestore/issues/1537)) ([f9cdab5](https://github.com/googleapis/java-firestore/commit/f9cdab5885bd1d500c6fc412eb3090cea9347d0e)) + + +### Dependencies + +* Update dependency com.google.cloud:google-cloud-shared-dependencies to v3.22.0 ([#1535](https://github.com/googleapis/java-firestore/issues/1535)) ([04c0e07](https://github.com/googleapis/java-firestore/commit/04c0e0736ddcd49eb42aacb31e2fc087b2a39754)) +* Update dependency com.google.cloud:google-cloud-shared-dependencies to v3.23.0 ([#1544](https://github.com/googleapis/java-firestore/issues/1544)) ([79713bf](https://github.com/googleapis/java-firestore/commit/79713bf0fa376a4d22518ae2f5da9660795d9f89)) + + +### Documentation + +* Fix formatting due to unclosed backtick ([#1529](https://github.com/googleapis/java-firestore/issues/1529)) ([3c78fe3](https://github.com/googleapis/java-firestore/commit/3c78fe3c248cb212c6e4f91a5bb7aeb8b9b003b0)) +* Rring BulkWriter out of BetaApi status. ([#1513](https://github.com/googleapis/java-firestore/issues/1513)) ([c2812f7](https://github.com/googleapis/java-firestore/commit/c2812f7cb72257512ffecc98ec1bdb1109d7d044)) + ## [3.16.0](https://github.com/googleapis/java-firestore/compare/v3.15.7...v3.16.0) (2024-01-10) diff --git a/README.md b/README.md index 1422de48aa..95c3790509 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file: com.google.cloud libraries-bom - 26.29.0 + 26.30.0 pom import @@ -42,7 +42,7 @@ If you are using Maven without the BOM, add this to your dependencies: com.google.cloud google-cloud-firestore - 3.15.7 + 3.16.0 ``` @@ -50,20 +50,20 @@ If you are using Maven without the BOM, add this to your dependencies: If you are using Gradle 5.x or later, add this to your dependencies: ```Groovy -implementation platform('com.google.cloud:libraries-bom:26.29.0') +implementation platform('com.google.cloud:libraries-bom:26.30.0') implementation 'com.google.cloud:google-cloud-firestore' ``` If you are using Gradle without BOM, add this to your dependencies: ```Groovy -implementation 'com.google.cloud:google-cloud-firestore:3.15.7' +implementation 'com.google.cloud:google-cloud-firestore:3.16.0' ``` If you are using SBT, add this to your dependencies: ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-firestore" % "3.15.7" +libraryDependencies += "com.google.cloud" % "google-cloud-firestore" % "3.16.0" ``` @@ -222,7 +222,7 @@ Java is a registered trademark of Oracle and/or its affiliates. [kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-firestore/java11.html [stability-image]: https://img.shields.io/badge/stability-stable-green [maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-firestore.svg -[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-firestore/3.15.7 +[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-firestore/3.16.0 [authentication]: https://github.com/googleapis/google-cloud-java#authentication [auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes [predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles diff --git a/google-cloud-firestore-admin/pom.xml b/google-cloud-firestore-admin/pom.xml index 19d1d29730..273951aaa2 100644 --- a/google-cloud-firestore-admin/pom.xml +++ b/google-cloud-firestore-admin/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 google-cloud-firestore-admin - 3.16.0 + 3.16.1 jar Google Cloud Firestore Admin Client https://github.com/googleapis/java-firestore @@ -14,7 +14,7 @@ com.google.cloud google-cloud-firestore-parent - 3.16.0 + 3.16.1 diff --git a/google-cloud-firestore-admin/src/main/java/com/google/cloud/firestore/v1/FirestoreAdminClient.java b/google-cloud-firestore-admin/src/main/java/com/google/cloud/firestore/v1/FirestoreAdminClient.java index 0ff74e0d53..49ceb63c44 100644 --- a/google-cloud-firestore-admin/src/main/java/com/google/cloud/firestore/v1/FirestoreAdminClient.java +++ b/google-cloud-firestore-admin/src/main/java/com/google/cloud/firestore/v1/FirestoreAdminClient.java @@ -125,280 +125,281 @@ * Method * Description * Method Variants + * * - * CreateIndex + *

CreateIndex *

Creates a composite index. This returns a [google.longrunning.Operation][google.longrunning.Operation] which may be used to track the status of the creation. The metadata for the operation will be the type [IndexOperationMetadata][google.firestore.admin.v1.IndexOperationMetadata]. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

Methods that return long-running operations have "Async" method variants that return `OperationFuture`, which is used to track polling of the service.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * ListIndexes + *

ListIndexes *

Lists composite indexes. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * GetIndex + *

GetIndex *

Gets a composite index. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * DeleteIndex + *

DeleteIndex *

Deletes a composite index. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * GetField + *

GetField *

Gets the metadata and configuration for a Field. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * UpdateField + *

UpdateField *

Updates a field configuration. Currently, field updates apply only to single field index configuration. However, calls to [FirestoreAdmin.UpdateField][google.firestore.admin.v1.FirestoreAdmin.UpdateField] should provide a field mask to avoid changing any configuration that the caller isn't aware of. The field mask should be specified as: `{ paths: "index_config" }`. *

This call returns a [google.longrunning.Operation][google.longrunning.Operation] which may be used to track the status of the field update. The metadata for the operation will be the type [FieldOperationMetadata][google.firestore.admin.v1.FieldOperationMetadata]. *

To configure the default field settings for the database, use the special `Field` with resource name: `projects/{project_id}/databases/{database_id}/collectionGroups/__default__/fields/*`. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

Methods that return long-running operations have "Async" method variants that return `OperationFuture`, which is used to track polling of the service.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * ListFields + *

ListFields *

Lists the field configuration and metadata for this database. - *

Currently, [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] only supports listing fields that have been explicitly overridden. To issue this query, call [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] with the filter set to `indexConfig.usesAncestorConfig:false or `ttlConfig:*`. + *

Currently, [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] only supports listing fields that have been explicitly overridden. To issue this query, call [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] with the filter set to `indexConfig.usesAncestorConfig:false` or `ttlConfig:*`. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * ExportDocuments + *

ExportDocuments *

Exports a copy of all or a subset of documents from Google Cloud Firestore to another storage system, such as Google Cloud Storage. Recent updates to documents may not be reflected in the export. The export occurs in the background and its progress can be monitored and managed via the Operation resource that is created. The output of an export may only be used once the associated operation is done. If an export operation is cancelled before completion it may leave partial data behind in Google Cloud Storage. *

For more details on export behavior and output format, refer to: https://cloud.google.com/firestore/docs/manage-data/export-import * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

Methods that return long-running operations have "Async" method variants that return `OperationFuture`, which is used to track polling of the service.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * ImportDocuments + *

ImportDocuments *

Imports documents into Google Cloud Firestore. Existing documents with the same name are overwritten. The import occurs in the background and its progress can be monitored and managed via the Operation resource that is created. If an ImportDocuments operation is cancelled, it is possible that a subset of the data has already been imported to Cloud Firestore. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

Methods that return long-running operations have "Async" method variants that return `OperationFuture`, which is used to track polling of the service.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * CreateDatabase + *

CreateDatabase *

Create a database. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

Methods that return long-running operations have "Async" method variants that return `OperationFuture`, which is used to track polling of the service.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * GetDatabase + *

GetDatabase *

Gets information about a database. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * ListDatabases + *

ListDatabases *

List all the databases in the project. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * UpdateDatabase + *

UpdateDatabase *

Updates a database. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

Methods that return long-running operations have "Async" method variants that return `OperationFuture`, which is used to track polling of the service.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * * - * DeleteDatabase + *

DeleteDatabase *

Deletes a database. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

* *

Methods that return long-running operations have "Async" method variants that return `OperationFuture`, which is used to track polling of the service.

* *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

* * * @@ -1379,7 +1380,7 @@ public final UnaryCallable updateFieldCallable() *

Currently, [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] * only supports listing fields that have been explicitly overridden. To issue this query, call * [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] with the - * filter set to `indexConfig.usesAncestorConfig:false or `ttlConfig:*`. + * filter set to `indexConfig.usesAncestorConfig:false` or `ttlConfig:*`. * *

Sample code: * @@ -1415,7 +1416,7 @@ public final ListFieldsPagedResponse listFields(CollectionGroupName parent) { *

Currently, [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] * only supports listing fields that have been explicitly overridden. To issue this query, call * [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] with the - * filter set to `indexConfig.usesAncestorConfig:false or `ttlConfig:*`. + * filter set to `indexConfig.usesAncestorConfig:false` or `ttlConfig:*`. * *

Sample code: * @@ -1449,7 +1450,7 @@ public final ListFieldsPagedResponse listFields(String parent) { *

Currently, [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] * only supports listing fields that have been explicitly overridden. To issue this query, call * [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] with the - * filter set to `indexConfig.usesAncestorConfig:false or `ttlConfig:*`. + * filter set to `indexConfig.usesAncestorConfig:false` or `ttlConfig:*`. * *

Sample code: * @@ -1488,7 +1489,7 @@ public final ListFieldsPagedResponse listFields(ListFieldsRequest request) { *

Currently, [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] * only supports listing fields that have been explicitly overridden. To issue this query, call * [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] with the - * filter set to `indexConfig.usesAncestorConfig:false or `ttlConfig:*`. + * filter set to `indexConfig.usesAncestorConfig:false` or `ttlConfig:*`. * *

Sample code: * @@ -1526,7 +1527,7 @@ public final UnaryCallable listField *

Currently, [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] * only supports listing fields that have been explicitly overridden. To issue this query, call * [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] with the - * filter set to `indexConfig.usesAncestorConfig:false or `ttlConfig:*`. + * filter set to `indexConfig.usesAncestorConfig:false` or `ttlConfig:*`. * *

Sample code: * diff --git a/google-cloud-firestore-admin/src/main/java/com/google/cloud/firestore/v1/stub/FirestoreAdminStubSettings.java b/google-cloud-firestore-admin/src/main/java/com/google/cloud/firestore/v1/stub/FirestoreAdminStubSettings.java index 2be7176acd..e7416e878c 100644 --- a/google-cloud-firestore-admin/src/main/java/com/google/cloud/firestore/v1/stub/FirestoreAdminStubSettings.java +++ b/google-cloud-firestore-admin/src/main/java/com/google/cloud/firestore/v1/stub/FirestoreAdminStubSettings.java @@ -403,6 +403,15 @@ public FirestoreAdminStub createStub() throws IOException { "Transport not supported: %s", getTransportChannelProvider().getTransportName())); } + /** Returns the endpoint set by the user or the the service's default endpoint. */ + @Override + public String getEndpoint() { + if (super.getEndpoint() != null) { + return super.getEndpoint(); + } + return getDefaultEndpoint(); + } + /** Returns the default service name. */ @Override public String getServiceName() { @@ -713,7 +722,6 @@ private static Builder createDefault() { builder.setTransportChannelProvider(defaultTransportChannelProvider()); builder.setCredentialsProvider(defaultCredentialsProviderBuilder().build()); builder.setInternalHeaderProvider(defaultApiClientHeaderProviderBuilder().build()); - builder.setEndpoint(getDefaultEndpoint()); builder.setMtlsEndpoint(getDefaultMtlsEndpoint()); builder.setSwitchToMtlsEndpointAllowed(true); @@ -726,7 +734,6 @@ private static Builder createHttpJsonDefault() { builder.setTransportChannelProvider(defaultHttpJsonTransportProviderBuilder().build()); builder.setCredentialsProvider(defaultCredentialsProviderBuilder().build()); builder.setInternalHeaderProvider(defaultHttpJsonApiClientHeaderProviderBuilder().build()); - builder.setEndpoint(getDefaultEndpoint()); builder.setMtlsEndpoint(getDefaultMtlsEndpoint()); builder.setSwitchToMtlsEndpointAllowed(true); @@ -1119,6 +1126,15 @@ public UnaryCallSettings.Builder deleteDatabas return deleteDatabaseOperationSettings; } + /** Returns the endpoint set by the user or the the service's default endpoint. */ + @Override + public String getEndpoint() { + if (super.getEndpoint() != null) { + return super.getEndpoint(); + } + return getDefaultEndpoint(); + } + @Override public FirestoreAdminStubSettings build() throws IOException { return new FirestoreAdminStubSettings(this); diff --git a/google-cloud-firestore-bom/pom.xml b/google-cloud-firestore-bom/pom.xml index 26ae50a2d9..2439bbff05 100644 --- a/google-cloud-firestore-bom/pom.xml +++ b/google-cloud-firestore-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-firestore-bom - 3.16.0 + 3.16.1 pom com.google.cloud @@ -52,37 +52,37 @@ com.google.cloud google-cloud-firestore - 3.16.0 + 3.16.1 com.google.cloud google-cloud-firestore-admin - 3.16.0 + 3.16.1 com.google.api.grpc grpc-google-cloud-firestore-admin-v1 - 3.16.0 + 3.16.1 com.google.api.grpc grpc-google-cloud-firestore-v1 - 3.16.0 + 3.16.1 com.google.api.grpc proto-google-cloud-firestore-admin-v1 - 3.16.0 + 3.16.1 com.google.api.grpc proto-google-cloud-firestore-v1 - 3.16.0 + 3.16.1 com.google.cloud proto-google-cloud-firestore-bundle-v1 - 3.16.0 + 3.16.1 diff --git a/google-cloud-firestore/pom.xml b/google-cloud-firestore/pom.xml index 49e6c74c4a..6bd0b53ad2 100644 --- a/google-cloud-firestore/pom.xml +++ b/google-cloud-firestore/pom.xml @@ -2,7 +2,7 @@ 4.0.0 google-cloud-firestore - 3.16.0 + 3.16.1 jar Google Cloud Firestore https://github.com/googleapis/java-firestore @@ -12,7 +12,7 @@ com.google.cloud google-cloud-firestore-parent - 3.16.0 + 3.16.1 google-cloud-firestore @@ -158,7 +158,7 @@ com.google.cloud google-cloud-conformance-tests - 0.3.6 + 0.3.7 test diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/BulkCommitBatch.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/BulkCommitBatch.java index 5ad7868672..fd5e9ba268 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/BulkCommitBatch.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/BulkCommitBatch.java @@ -69,24 +69,21 @@ ApiFuture wrapResult(int writeIndex) { *

The writes in the batch are not applied atomically and can be applied out of order. */ ApiFuture bulkCommit() { + + // Follows same thread safety logic as `UpdateBuilder::commit`. + committed = true; + BatchWriteRequest request = buildBatchWriteRequest(); + Tracing.getTracer() .getCurrentSpan() .addAnnotation( TraceUtil.SPAN_NAME_BATCHWRITE, - ImmutableMap.of("numDocuments", AttributeValue.longAttributeValue(getWrites().size()))); - - final BatchWriteRequest.Builder request = BatchWriteRequest.newBuilder(); - request.setDatabase(firestore.getDatabaseName()); - - for (WriteOperation writeOperation : getWrites()) { - request.addWrites(writeOperation.write); - } - - committed = true; + ImmutableMap.of( + "numDocuments", AttributeValue.longAttributeValue(request.getWritesCount()))); ApiFuture response = processExceptions( - firestore.sendRequest(request.build(), firestore.getClient().batchWriteCallable())); + firestore.sendRequest(request, firestore.getClient().batchWriteCallable())); return ApiFutures.transformAsync( response, @@ -117,6 +114,13 @@ ApiFuture bulkCommit() { executor); } + private BatchWriteRequest buildBatchWriteRequest() { + BatchWriteRequest.Builder builder = BatchWriteRequest.newBuilder(); + builder.setDatabase(firestore.getDatabaseName()); + forEachWrite(builder::addWrites); + return builder.build(); + } + /** Maps an RPC failure to each individual write's result. */ private ApiFuture processExceptions(ApiFuture response) { return ApiFutures.catching( diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldMask.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldMask.java index 0277029da1..bec096abbe 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldMask.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/FieldMask.java @@ -16,10 +16,8 @@ package com.google.cloud.firestore; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.List; +import java.util.Collections; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; @@ -47,7 +45,7 @@ private FieldMask(SortedSet fieldPaths) { */ @Nonnull public static FieldMask of(String... fieldPaths) { - List paths = new ArrayList<>(); + TreeSet paths = new TreeSet<>(); for (String fieldPath : fieldPaths) { paths.add(FieldPath.fromDotSeparatedString(fieldPath)); } @@ -62,16 +60,18 @@ public static FieldMask of(String... fieldPaths) { */ @Nonnull public static FieldMask of(FieldPath... fieldPaths) { - return new FieldMask(Arrays.asList(fieldPaths)); + TreeSet paths = new TreeSet<>(); + Collections.addAll(paths, fieldPaths); + return new FieldMask(paths); } static FieldMask fromObject(Map values) { - List fieldPaths = extractFromMap(values, FieldPath.empty()); + TreeSet fieldPaths = extractFromMap(values, FieldPath.empty()); return new FieldMask(fieldPaths); } - private static List extractFromMap(Map values, FieldPath path) { - List fieldPaths = new ArrayList<>(); + private static TreeSet extractFromMap(Map values, FieldPath path) { + TreeSet fieldPaths = new TreeSet<>(); for (Map.Entry entry : values.entrySet()) { Object value = entry.getValue(); diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java index 56f1fc65a8..5bbb1164ad 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Firestore.java @@ -176,7 +176,6 @@ void getAll( * @see Ramping * up traffic */ - @BetaApi @Nonnull BulkWriter bulkWriter(); @@ -189,7 +188,6 @@ void getAll( * up traffic * @param options An options object to configure BulkWriter. */ - @BetaApi @Nonnull BulkWriter bulkWriter(BulkWriterOptions options); diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Precondition.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Precondition.java index 54b55b8188..fb8be8778c 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Precondition.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Precondition.java @@ -62,8 +62,8 @@ boolean isEmpty() { return exists == null && updateTime == null; } - boolean hasExists() { - return exists != null; + Boolean getExists() { + return exists; } com.google.firestore.v1.Precondition toPb() { diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Query.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Query.java index 7fb6856b88..920367dd0e 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Query.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Query.java @@ -1477,8 +1477,6 @@ public void stream(@Nonnull final ApiStreamObserver responseOb internalStream( new QuerySnapshotObserver() { - boolean hasCompleted = false; - @Override public void onNext(QueryDocumentSnapshot documentSnapshot) { responseObserver.onNext(documentSnapshot); @@ -1491,8 +1489,6 @@ public void onError(Throwable throwable) { @Override public void onCompleted() { - if (hasCompleted) return; - hasCompleted = true; responseObserver.onCompleted(); } }, @@ -1660,6 +1656,10 @@ private void internalStream( boolean firstResponse; int numDocuments; + // The stream's `onComplete()` could be called more than once, + // this flag makes sure only the first one is actually processed. + boolean hasCompleted = false; + @Override public void onStart(StreamController streamController) {} @@ -1695,7 +1695,7 @@ public void onResponse(RunQueryResponse response) { "Firestore.Query: Completed", ImmutableMap.of( "numDocuments", AttributeValue.longAttributeValue(numDocuments))); - documentObserver.onCompleted(readTime); + onComplete(); } } @@ -1723,6 +1723,9 @@ public void onError(Throwable throwable) { @Override public void onComplete() { + if (hasCompleted) return; + hasCompleted = true; + Tracing.getTracer() .getCurrentSpan() .addAnnotation( @@ -1788,9 +1791,6 @@ ApiFuture get(@Nullable ByteString transactionId) { internalStream( new QuerySnapshotObserver() { final List documentSnapshots = new ArrayList<>(); - // The stream's onCompleted could be called more than once, - // this flag makes sure only the first one is actually processed. - boolean hasCompleted = false; @Override public void onNext(QueryDocumentSnapshot documentSnapshot) { @@ -1804,9 +1804,6 @@ public void onError(Throwable throwable) { @Override public void onCompleted() { - if (hasCompleted) return; - hasCompleted = true; - // The results for limitToLast queries need to be flipped since we reversed the // ordering constraints before sending the query to the backend. List resultView = diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java index 3ca949373a..e76c2fdbae 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Transaction.java @@ -29,6 +29,8 @@ import com.google.protobuf.Empty; import io.opencensus.trace.Tracing; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -40,6 +42,7 @@ */ public final class Transaction extends UpdateBuilder { + private static final Logger LOGGER = Logger.getLogger(Transaction.class.getName()); private static final String READ_BEFORE_WRITE_ERROR_MSG = "Firestore transactions require all reads to be executed before all writes"; @@ -121,15 +124,29 @@ ApiFuture> commit() { /** Rolls a transaction back and releases all read locks. */ ApiFuture rollback() { Tracing.getTracer().getCurrentSpan().addAnnotation(TraceUtil.SPAN_NAME_ROLLBACK); - RollbackRequest.Builder reqBuilder = RollbackRequest.newBuilder(); - reqBuilder.setTransaction(transactionId); - reqBuilder.setDatabase(firestore.getDatabaseName()); + RollbackRequest req = + RollbackRequest.newBuilder() + .setTransaction(transactionId) + .setDatabase(firestore.getDatabaseName()) + .build(); ApiFuture rollbackFuture = - firestore.sendRequest(reqBuilder.build(), firestore.getClient().rollbackCallable()); - - return ApiFutures.transform( - rollbackFuture, beginTransactionResponse -> null, MoreExecutors.directExecutor()); + firestore.sendRequest(req, firestore.getClient().rollbackCallable()); + + ApiFuture transform = + ApiFutures.transform(rollbackFuture, resp -> null, MoreExecutors.directExecutor()); + + return ApiFutures.catching( + transform, + Throwable.class, + (error) -> { + LOGGER.log( + Level.WARNING, + "Failed best effort to rollback of transaction " + transactionId, + error); + return null; + }, + MoreExecutors.directExecutor()); } /** diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UpdateBuilder.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UpdateBuilder.java index 87cf833079..6ed342b201 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UpdateBuilder.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UpdateBuilder.java @@ -16,6 +16,9 @@ package com.google.cloud.firestore; +import static com.google.common.base.Predicates.not; +import static java.util.stream.Collectors.toCollection; + import com.google.api.core.ApiFuture; import com.google.api.core.ApiFutures; import com.google.api.core.InternalExtensionOnly; @@ -27,15 +30,20 @@ import com.google.firestore.v1.CommitResponse; import com.google.firestore.v1.Write; import com.google.protobuf.ByteString; +import com.google.protobuf.Timestamp; import io.opencensus.trace.AttributeValue; import io.opencensus.trace.Tracing; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.function.Consumer; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -45,11 +53,11 @@ */ @InternalExtensionOnly public abstract class UpdateBuilder { - static class WriteOperation { - Write.Builder write; - DocumentReference documentReference; + static final class WriteOperation { + final Write write; + final DocumentReference documentReference; - WriteOperation(DocumentReference documentReference, Write.Builder write) { + WriteOperation(DocumentReference documentReference, Write write) { this.documentReference = documentReference; this.write = write; } @@ -62,13 +70,11 @@ public String toString() { final FirestoreImpl firestore; + // All reads and writes on `writes` must be done in a block that is synchronized on `writes`; + // otherwise, you get undefined behavior. private final List writes = new ArrayList<>(); - protected boolean committed; - - boolean isCommitted() { - return committed; - } + protected volatile boolean committed; UpdateBuilder(FirestoreImpl firestore) { this.firestore = firestore; @@ -138,7 +144,6 @@ public T create( private T performCreate( @Nonnull DocumentReference documentReference, @Nonnull Map fields) { - verifyNotCommitted(); Tracing.getTracer().getCurrentSpan().addAnnotation(TraceUtil.SPAN_NAME_CREATEDOCUMENT); DocumentSnapshot documentSnapshot = DocumentSnapshot.fromObject( @@ -154,17 +159,7 @@ private T performCreate( write.addAllUpdateTransforms(documentTransform.toPb()); } - writes.add(new WriteOperation(documentReference, write)); - - return wrapResult(writes.size() - 1); - } - - private void verifyNotCommitted() { - Preconditions.checkState( - !isCommitted(), - String.format( - "Cannot modify a %s that has already been committed.", - this.getClass().getSimpleName())); + return addWrite(documentReference, write); } /** @@ -255,7 +250,6 @@ private T performSet( @Nonnull DocumentReference documentReference, @Nonnull Map fields, @Nonnull SetOptions options) { - verifyNotCommitted(); Map documentData; if (options.getFieldMask() != null) { @@ -272,9 +266,11 @@ private T performSet( DocumentTransform.fromFieldPathMap(documentReference, documentData); if (options.getFieldMask() != null) { - List fieldMask = new ArrayList<>(options.getFieldMask()); - fieldMask.removeAll(documentTransform.getFields()); - documentMask = new FieldMask(fieldMask); + TreeSet fieldPaths = + options.getFieldMask().stream() + .filter(not(documentTransform.getFields()::contains)) + .collect(toCollection(TreeSet::new)); + documentMask = new FieldMask(fieldPaths); } else if (options.isMerge()) { documentMask = FieldMask.fromObject(fields); } @@ -288,15 +284,28 @@ private T performSet( write.setUpdateMask(documentMask.toPb()); } - writes.add(new WriteOperation(documentReference, write)); + return addWrite(documentReference, write); + } - return wrapResult(writes.size() - 1); + private T addWrite(DocumentReference documentReference, Write.Builder write) { + WriteOperation operation = new WriteOperation(documentReference, write.build()); + int writeIndex; + synchronized (writes) { + Preconditions.checkState( + !committed, + String.format( + "Cannot modify a %s that has already been committed.", + this.getClass().getSimpleName())); + writes.add(operation); + writeIndex = writes.size() - 1; + } + return wrapResult(writeIndex); } /** Removes all values in 'fields' that are not specified in 'fieldMask'. */ - private Map applyFieldMask( + private static Map applyFieldMask( Map fields, List fieldMask) { - List remainingFields = new ArrayList<>(fieldMask); + Set remainingFields = new HashSet<>(fieldMask); Map filteredData = applyFieldMask(fields, remainingFields, FieldPath.empty()); @@ -304,7 +313,7 @@ private Map applyFieldMask( throw new IllegalArgumentException( String.format( "Field masks contains invalid path. No data exist at field '%s'.", - remainingFields.get(0))); + remainingFields.iterator().next())); } return filteredData; @@ -314,8 +323,8 @@ private Map applyFieldMask( * Strips all values in 'fields' that are not specified in 'fieldMask'. Modifies 'fieldMask' * inline and removes all matched fields. */ - private Map applyFieldMask( - Map fields, List fieldMask, FieldPath root) { + private static Map applyFieldMask( + Map fields, Set fieldMask, FieldPath root) { Map filteredMap = new HashMap<>(); for (Entry entry : fields.entrySet()) { @@ -335,7 +344,7 @@ private Map applyFieldMask( return filteredMap; } - private Map convertToFieldPaths( + private static Map convertToFieldPaths( @Nonnull Map fields, boolean splitOnDots) { Map fieldPaths = new HashMap<>(); @@ -382,7 +391,8 @@ public T update( @Nonnull Map fields, Precondition precondition) { Preconditions.checkArgument( - !precondition.hasExists(), "Precondition 'exists' cannot be specified for update() calls."); + !Boolean.FALSE.equals(precondition.getExists()), + "Precondition 'exists' cannot have the value 'false' for update() calls."); return performUpdate( documentReference, convertToFieldPaths(fields, /* splitOnDots= */ true), precondition); } @@ -450,7 +460,8 @@ public T update( @Nullable Object value, Object... moreFieldsAndValues) { Preconditions.checkArgument( - !precondition.hasExists(), "Precondition 'exists' cannot be specified for update() calls."); + !Boolean.FALSE.equals(precondition.getExists()), + "Precondition 'exists' cannot have the value 'false' for update() calls."); return performUpdate( documentReference, precondition, @@ -478,7 +489,8 @@ public T update( @Nullable Object value, Object... moreFieldsAndValues) { Preconditions.checkArgument( - !precondition.hasExists(), "Precondition 'exists' cannot be specified for update() calls."); + !Boolean.FALSE.equals(precondition.getExists()), + "Precondition 'exists' cannot have the value 'false' for update() calls."); return performUpdate(documentReference, precondition, fieldPath, value, moreFieldsAndValues); } @@ -524,7 +536,6 @@ private T performUpdate( @Nonnull DocumentReference documentReference, @Nonnull final Map fields, @Nonnull Precondition precondition) { - verifyNotCommitted(); Preconditions.checkArgument(!fields.isEmpty(), "Data for update() cannot be empty."); Tracing.getTracer().getCurrentSpan().addAnnotation(TraceUtil.SPAN_NAME_UPDATEDOCUMENT); Map deconstructedMap = expandObject(fields); @@ -544,10 +555,12 @@ public boolean allowTransform() { return true; } }); - List fieldPaths = new ArrayList<>(fields.keySet()); DocumentTransform documentTransform = DocumentTransform.fromFieldPathMap(documentReference, fields); - fieldPaths.removeAll(documentTransform.getFields()); + TreeSet fieldPaths = + fields.keySet().stream() + .filter(not(documentTransform.getFields()::contains)) + .collect(toCollection(TreeSet::new)); FieldMask fieldMask = new FieldMask(fieldPaths); Write.Builder write = documentSnapshot.toPb(); @@ -557,9 +570,8 @@ public boolean allowTransform() { if (!documentTransform.isEmpty()) { write.addAllUpdateTransforms(documentTransform.toPb()); } - writes.add(new WriteOperation(documentReference, write)); - return wrapResult(writes.size() - 1); + return addWrite(documentReference, write); } /** @@ -588,76 +600,98 @@ public T delete(@Nonnull DocumentReference documentReference) { private T performDelete( @Nonnull DocumentReference documentReference, @Nonnull Precondition precondition) { - verifyNotCommitted(); Tracing.getTracer().getCurrentSpan().addAnnotation(TraceUtil.SPAN_NAME_DELETEDOCUMENT); Write.Builder write = Write.newBuilder().setDelete(documentReference.getName()); if (!precondition.isEmpty()) { write.setCurrentDocument(precondition.toPb()); } - writes.add(new WriteOperation(documentReference, write)); - return wrapResult(writes.size() - 1); + return addWrite(documentReference, write); } /** Commit the current batch. */ ApiFuture> commit(@Nullable ByteString transactionId) { + + // Sequence is thread safe. + // + // 1. Set committed = true + // 2. Build commit request + // + // Step 1 sets uses volatile property to ensure committed is visible to all + // threads immediately. + // + // Step 2 uses `forEach(..)` that is synchronized, therefore will be blocked + // until any writes are complete. + // + // Writes will verify `committed==false` within synchronized block of code + // before appending writes. Since committed is set to true before accessing + // writes, we are ensured that no more writes will be appended after commit + // accesses writes. + committed = true; + CommitRequest request = buildCommitRequest(transactionId); + Tracing.getTracer() .getCurrentSpan() .addAnnotation( TraceUtil.SPAN_NAME_COMMIT, - ImmutableMap.of("numDocuments", AttributeValue.longAttributeValue(writes.size()))); - - final CommitRequest.Builder request = CommitRequest.newBuilder(); - request.setDatabase(firestore.getDatabaseName()); - - for (WriteOperation writeOperation : writes) { - request.addWrites(writeOperation.write); - } - - if (transactionId != null) { - request.setTransaction(transactionId); - } - - committed = true; + ImmutableMap.of( + "numDocuments", AttributeValue.longAttributeValue(request.getWritesCount()))); ApiFuture response = - firestore.sendRequest(request.build(), firestore.getClient().commitCallable()); + firestore.sendRequest(request, firestore.getClient().commitCallable()); return ApiFutures.transform( response, commitResponse -> { - List writeResults = - commitResponse.getWriteResultsList(); - - List result = new ArrayList<>(); - - for (com.google.firestore.v1.WriteResult writeResult : writeResults) { - result.add(WriteResult.fromProto(writeResult, commitResponse.getCommitTime())); - } - - return result; + Timestamp commitTime = commitResponse.getCommitTime(); + return commitResponse.getWriteResultsList().stream() + .map(writeResult -> WriteResult.fromProto(writeResult, commitTime)) + .collect(Collectors.toList()); }, MoreExecutors.directExecutor()); } + private CommitRequest buildCommitRequest(ByteString transactionId) { + CommitRequest.Builder builder = CommitRequest.newBuilder(); + builder.setDatabase(firestore.getDatabaseName()); + forEachWrite(builder::addWrites); + if (transactionId != null) { + builder.setTransaction(transactionId); + } + return builder.build(); + } + /** Checks whether any updates have been queued. */ boolean isEmpty() { - return writes.isEmpty(); + synchronized (writes) { + return writes.isEmpty(); + } } - List getWrites() { - return writes; + void forEachWrite(Consumer consumer) { + synchronized (writes) { + for (WriteOperation writeOperation : writes) { + consumer.accept(writeOperation.write); + } + } } /** Get the number of writes. */ public int getMutationsSize() { - return writes.size(); + synchronized (writes) { + return writes.size(); + } } @Override public String toString() { + final String writesAsString; + synchronized (writes) { + writesAsString = writes.toString(); + } + return String.format( - "%s{writes=%s, committed=%s}", getClass().getSimpleName(), writes, committed); + "%s{writes=%s, committed=%s}", getClass().getSimpleName(), writesAsString, committed); } } diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/v1/FirestoreClient.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/v1/FirestoreClient.java index 5e472ac97b..23be95fd39 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/v1/FirestoreClient.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/v1/FirestoreClient.java @@ -105,148 +105,149 @@ * Method * Description * Method Variants + * * - * GetDocument + *

GetDocument *

Gets a single document. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

*
    - *
  • getDocument(GetDocumentRequest request) + *
  • getDocument(GetDocumentRequest request) *

*

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • getDocumentCallable() + *
  • getDocumentCallable() *

* * * - * ListDocuments + *

ListDocuments *

Lists documents. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

*
    - *
  • listDocuments(ListDocumentsRequest request) + *
  • listDocuments(ListDocumentsRequest request) *

*

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • listDocumentsPagedCallable() - *
  • listDocumentsCallable() + *
  • listDocumentsPagedCallable() + *

  • listDocumentsCallable() *

* * * - * UpdateDocument + *

UpdateDocument *

Updates or inserts a document. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

*
    - *
  • updateDocument(UpdateDocumentRequest request) + *
  • updateDocument(UpdateDocumentRequest request) *

*

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

*
    - *
  • updateDocument(Document document, DocumentMask updateMask) + *
  • updateDocument(Document document, DocumentMask updateMask) *

*

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • updateDocumentCallable() + *
  • updateDocumentCallable() *

* * * - * DeleteDocument + *

DeleteDocument *

Deletes a document. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

*
    - *
  • deleteDocument(DeleteDocumentRequest request) + *
  • deleteDocument(DeleteDocumentRequest request) *

*

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

*
    - *
  • deleteDocument(String name) + *
  • deleteDocument(String name) *

*

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • deleteDocumentCallable() + *
  • deleteDocumentCallable() *

* * * - * BatchGetDocuments + *

BatchGetDocuments *

Gets multiple documents. *

Documents returned by this method are not guaranteed to be returned in the same order that they were requested. * *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • batchGetDocumentsCallable() + *
  • batchGetDocumentsCallable() *

* * * - * BeginTransaction + *

BeginTransaction *

Starts a new transaction. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

*
    - *
  • beginTransaction(BeginTransactionRequest request) + *
  • beginTransaction(BeginTransactionRequest request) *

*

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

*
    - *
  • beginTransaction(String database) + *
  • beginTransaction(String database) *

*

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • beginTransactionCallable() + *
  • beginTransactionCallable() *

* * * - * Commit + *

Commit *

Commits a transaction, while optionally updating documents. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

*
    - *
  • commit(CommitRequest request) + *
  • commit(CommitRequest request) *

*

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

*
    - *
  • commit(String database, List<Write> writes) + *
  • commit(String database, List<Write> writes) *

*

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • commitCallable() + *
  • commitCallable() *

* * * - * Rollback + *

Rollback *

Rolls back a transaction. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

*
    - *
  • rollback(RollbackRequest request) + *
  • rollback(RollbackRequest request) *

*

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

*
    - *
  • rollback(String database, ByteString transaction) + *
  • rollback(String database, ByteString transaction) *

*

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • rollbackCallable() + *
  • rollbackCallable() *

* * * - * RunQuery + *

RunQuery *

Runs a query. * *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • runQueryCallable() + *
  • runQueryCallable() *

* * * - * RunAggregationQuery + *

RunAggregationQuery *

Runs an aggregation query. *

Rather than producing [Document][google.firestore.v1.Document] results like [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery], this API allows running an aggregation to produce a series of [AggregationResult][google.firestore.v1.AggregationResult] server-side. *

High-Level Example: @@ -254,91 +255,91 @@ * *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • runAggregationQueryCallable() + *
  • runAggregationQueryCallable() *

* * * - * PartitionQuery + *

PartitionQuery *

Partitions a query by returning partition cursors that can be used to run the query in parallel. The returned partition cursors are split points that can be used by RunQuery as starting/end points for the query results. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

*
    - *
  • partitionQuery(PartitionQueryRequest request) + *
  • partitionQuery(PartitionQueryRequest request) *

*

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • partitionQueryPagedCallable() - *
  • partitionQueryCallable() + *
  • partitionQueryPagedCallable() + *

  • partitionQueryCallable() *

* * * - * Write + *

Write *

Streams batches of document updates and deletes, in order. This method is only available via gRPC or WebChannel (not REST). * *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • writeCallable() + *
  • writeCallable() *

* * * - * Listen + *

Listen *

Listens to changes. This method is only available via gRPC or WebChannel (not REST). * *

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • listenCallable() + *
  • listenCallable() *

* * * - * ListCollectionIds + *

ListCollectionIds *

Lists all the collection IDs underneath a document. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

*
    - *
  • listCollectionIds(ListCollectionIdsRequest request) + *
  • listCollectionIds(ListCollectionIdsRequest request) *

*

"Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.

*
    - *
  • listCollectionIds(String parent) + *
  • listCollectionIds(String parent) *

*

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • listCollectionIdsPagedCallable() - *
  • listCollectionIdsCallable() + *
  • listCollectionIdsPagedCallable() + *

  • listCollectionIdsCallable() *

* * * - * BatchWrite + *

BatchWrite *

Applies a batch of write operations. *

The BatchWrite method does not apply the write operations atomically and can apply them out of order. Method does not allow more than one write per document. Each write succeeds or fails independently. See the [BatchWriteResponse][google.firestore.v1.BatchWriteResponse] for the success status of each write. *

If you require an atomically applied set of writes, use [Commit][google.firestore.v1.Firestore.Commit] instead. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

*
    - *
  • batchWrite(BatchWriteRequest request) + *
  • batchWrite(BatchWriteRequest request) *

*

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • batchWriteCallable() + *
  • batchWriteCallable() *

* * * - * CreateDocument + *

CreateDocument *

Creates a new document. * *

Request object method variants only take one parameter, a request object, which must be constructed before the call.

*
    - *
  • createDocument(CreateDocumentRequest request) + *
  • createDocument(CreateDocumentRequest request) *

*

Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.

*
    - *
  • createDocumentCallable() + *
  • createDocumentCallable() *

* * diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/v1/stub/FirestoreStubSettings.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/v1/stub/FirestoreStubSettings.java index 65345559b0..f34ce93613 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/v1/stub/FirestoreStubSettings.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/v1/stub/FirestoreStubSettings.java @@ -426,6 +426,15 @@ public FirestoreStub createStub() throws IOException { "Transport not supported: %s", getTransportChannelProvider().getTransportName())); } + /** Returns the endpoint set by the user or the the service's default endpoint. */ + @Override + public String getEndpoint() { + if (super.getEndpoint() != null) { + return super.getEndpoint(); + } + return getDefaultEndpoint(); + } + /** Returns the default service name. */ @Override public String getServiceName() { @@ -769,7 +778,6 @@ private static Builder createDefault() { builder.setTransportChannelProvider(defaultTransportChannelProvider()); builder.setCredentialsProvider(defaultCredentialsProviderBuilder().build()); builder.setInternalHeaderProvider(defaultApiClientHeaderProviderBuilder().build()); - builder.setEndpoint(getDefaultEndpoint()); builder.setMtlsEndpoint(getDefaultMtlsEndpoint()); builder.setSwitchToMtlsEndpointAllowed(true); @@ -782,7 +790,6 @@ private static Builder createHttpJsonDefault() { builder.setTransportChannelProvider(defaultHttpJsonTransportProviderBuilder().build()); builder.setCredentialsProvider(defaultCredentialsProviderBuilder().build()); builder.setInternalHeaderProvider(defaultHttpJsonApiClientHeaderProviderBuilder().build()); - builder.setEndpoint(getDefaultEndpoint()); builder.setMtlsEndpoint(getDefaultMtlsEndpoint()); builder.setSwitchToMtlsEndpointAllowed(true); @@ -969,6 +976,15 @@ public UnaryCallSettings.Builder createDocument return createDocumentSettings; } + /** Returns the endpoint set by the user or the the service's default endpoint. */ + @Override + public String getEndpoint() { + if (super.getEndpoint() != null) { + return super.getEndpoint(); + } + return getDefaultEndpoint(); + } + @Override public FirestoreStubSettings build() throws IOException { return new FirestoreStubSettings(this); diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java index a871884020..706412dae9 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java @@ -16,6 +16,7 @@ package com.google.cloud.firestore; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; @@ -83,6 +84,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; import org.mockito.ArgumentCaptor; @@ -1195,10 +1197,10 @@ public RequestResponsePair( * `sendRequest()` is called. */ static class ResponseStubber { - int requestCount = 0; - List operationList = new ArrayList<>(); + List actualRequestList = new CopyOnWriteArrayList<>(); + void put(GeneratedMessageV3 request, ApiFuture response) { operationList.add(new RequestResponsePair(request, response)); } @@ -1209,8 +1211,7 @@ void initializeStub( for (final RequestResponsePair entry : operationList) { Answer> answer = invocationOnMock -> { - ++requestCount; - assertEquals(entry.request, invocationOnMock.getArguments()[0]); + actualRequestList.add(invocationOnMock.getArguments()[0]); return entry.response; }; stubber = (stubber != null) ? stubber.doAnswer(answer) : doAnswer(answer); @@ -1223,10 +1224,10 @@ void initializeStub( } public void verifyAllRequestsSent() { - assertEquals( - String.format("Expected %d requests, but got %d", operationList.size(), requestCount), - operationList.size(), - requestCount); + assertArrayEquals( + "Expected requests, but got actual requests", + operationList.stream().map(x -> x.request).toArray(), + actualRequestList.toArray()); } } diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/ToStringTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/ToStringTest.java index 9dca2518e7..6779edd185 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/ToStringTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/ToStringTest.java @@ -86,7 +86,8 @@ public void testWriteOperation() { documentReference, Collections.singletonMap("key", "value"), UserDataConverter.NO_DELETES) - .toPb()) + .toPb() + .build()) .toString(); assertThat(toStringResult).startsWith("WriteOperation{"); assertThat(toStringResult) diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/TransactionTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/TransactionTest.java index df9c72cedb..a1fa02e292 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/TransactionTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/TransactionTest.java @@ -16,6 +16,7 @@ package com.google.cloud.firestore; +import static com.google.api.core.ApiFutures.immediateFailedFuture; import static com.google.cloud.firestore.LocalFirestoreHelper.IMMEDIATE_RETRY_SETTINGS; import static com.google.cloud.firestore.LocalFirestoreHelper.SINGLE_FIELD_PROTO; import static com.google.cloud.firestore.LocalFirestoreHelper.TRANSACTION_ID; @@ -88,7 +89,7 @@ public class TransactionTest { private final ApiFuture RETRYABLE_API_EXCEPTION = - ApiFutures.immediateFailedFuture( + immediateFailedFuture( new ApiException( new Exception("Test exception"), GrpcStatusCode.of(Status.Code.UNKNOWN), true)); @@ -244,7 +245,7 @@ public void rollbackOnCallbackApiFutureErrorAsync() { ApiFuture transaction = firestoreMock.runAsyncTransaction( - t -> ApiFutures.immediateFailedFuture(new Exception("Expected exception")), options); + t -> immediateFailedFuture(new Exception("Expected exception")), options); try { transaction.get(); @@ -262,7 +263,7 @@ public void rollbackOnCallbackApiFutureErrorAsync() { @Test public void noRollbackOnBeginFailure() { - doReturn(ApiFutures.immediateFailedFuture(new Exception("Expected exception"))) + doReturn(immediateFailedFuture(new Exception("Expected exception"))) .when(firestoreMock) .sendRequest( requestCapture.capture(), ArgumentMatchers.>any()); @@ -288,7 +289,7 @@ public void noRollbackOnBeginFailure() { @Test public void noRollbackOnBeginFailureAsync() { - doReturn(ApiFutures.immediateFailedFuture(new Exception("Expected exception"))) + doReturn(immediateFailedFuture(new Exception("Expected exception"))) .when(firestoreMock) .sendRequest( requestCapture.capture(), ArgumentMatchers.>any()); @@ -493,7 +494,7 @@ public void retriesCommitBasedOnErrorCode() throws Exception { new ResponseStubber() { { put(begin(), beginResponse("foo1")); - put(commit("foo1"), ApiFutures.immediateFailedFuture(e)); + put(commit("foo1"), immediateFailedFuture(e)); put(rollback("foo1"), rollbackResponse()); put(begin("foo1"), beginResponse("foo2")); put(commit("foo2"), commitResponse(0, 0)); @@ -503,7 +504,7 @@ public void retriesCommitBasedOnErrorCode() throws Exception { new ResponseStubber() { { put(begin(), beginResponse("foo1")); - put(commit("foo1"), ApiFutures.immediateFailedFuture(e)); + put(commit("foo1"), immediateFailedFuture(e)); put(rollback("foo1"), rollbackResponse()); } }); @@ -511,32 +512,33 @@ public void retriesCommitBasedOnErrorCode() throws Exception { @Test public void retriesRollbackBasedOnErrorCode() throws Exception { - final ApiException commitException = exception(Status.Code.ABORTED, true); - + final ApiException retryable = exception(Status.Code.ABORTED, true); + + // Regardless of exception thrown by rollback, we should never retry + // calling rollback. Rollback is best effort, and will sometimes return + // ABORT error (which a transaction will retry) when transaction no longer + // exists on Firestore server side. Attempting to retry will in some cases + // simply exhaust retries with accumulated backoff delay, when a new + // transaction could simply be started (since the old transaction no longer + // exists server side). verifyRetries( /* expectedSequenceWithRetry= */ e -> { - final ApiFuture rollbackException = - ApiFutures.immediateFailedFuture(e); return new ResponseStubber() { { put(begin(), beginResponse("foo1")); - put(commit("foo1"), ApiFutures.immediateFailedFuture(commitException)); - put(rollback("foo1"), rollbackException); - put(rollback("foo1"), rollbackResponse()); + put(commit("foo1"), immediateFailedFuture(e)); + put(rollback("foo1"), immediateFailedFuture(retryable)); put(begin("foo1"), beginResponse("foo2")); put(commit("foo2"), commitResponse(0, 0)); } }; }, /* expectedSequenceWithoutRetry= */ e -> { - final ApiFuture rollbackException = - ApiFutures.immediateFailedFuture(e); return new ResponseStubber() { { put(begin(), beginResponse("foo1")); - put(commit("foo1"), ApiFutures.immediateFailedFuture(commitException)); - put(rollback("foo1"), rollbackException); - put(rollback("foo1"), rollbackResponse()); + put(commit("foo1"), immediateFailedFuture(e)); + put(rollback("foo1"), immediateFailedFuture(retryable)); } }; }); diff --git a/grpc-google-cloud-firestore-admin-v1/pom.xml b/grpc-google-cloud-firestore-admin-v1/pom.xml index b979af7393..1b05eaf92d 100644 --- a/grpc-google-cloud-firestore-admin-v1/pom.xml +++ b/grpc-google-cloud-firestore-admin-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-firestore-admin-v1 - 3.16.0 + 3.16.1 grpc-google-cloud-firestore-admin-v1 GRPC library for grpc-google-cloud-firestore-admin-v1 com.google.cloud google-cloud-firestore-parent - 3.16.0 + 3.16.1 diff --git a/grpc-google-cloud-firestore-admin-v1/src/main/java/com/google/firestore/admin/v1/FirestoreAdminGrpc.java b/grpc-google-cloud-firestore-admin-v1/src/main/java/com/google/firestore/admin/v1/FirestoreAdminGrpc.java index a12330a38e..7cfc990b34 100644 --- a/grpc-google-cloud-firestore-admin-v1/src/main/java/com/google/firestore/admin/v1/FirestoreAdminGrpc.java +++ b/grpc-google-cloud-firestore-admin-v1/src/main/java/com/google/firestore/admin/v1/FirestoreAdminGrpc.java @@ -841,7 +841,7 @@ default void updateField( * only supports listing fields that have been explicitly overridden. To issue * this query, call * [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] - * with the filter set to `indexConfig.usesAncestorConfig:false or + * with the filter set to `indexConfig.usesAncestorConfig:false` or * `ttlConfig:*`. * */ @@ -1157,7 +1157,7 @@ public void updateField( * only supports listing fields that have been explicitly overridden. To issue * this query, call * [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] - * with the filter set to `indexConfig.usesAncestorConfig:false or + * with the filter set to `indexConfig.usesAncestorConfig:false` or * `ttlConfig:*`. * */ @@ -1439,7 +1439,7 @@ public com.google.longrunning.Operation updateField( * only supports listing fields that have been explicitly overridden. To issue * this query, call * [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] - * with the filter set to `indexConfig.usesAncestorConfig:false or + * with the filter set to `indexConfig.usesAncestorConfig:false` or * `ttlConfig:*`. * */ @@ -1698,7 +1698,7 @@ protected FirestoreAdminFutureStub build( * only supports listing fields that have been explicitly overridden. To issue * this query, call * [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] - * with the filter set to `indexConfig.usesAncestorConfig:false or + * with the filter set to `indexConfig.usesAncestorConfig:false` or * `ttlConfig:*`. * */ diff --git a/grpc-google-cloud-firestore-v1/pom.xml b/grpc-google-cloud-firestore-v1/pom.xml index cb1b195683..807ed211d6 100644 --- a/grpc-google-cloud-firestore-v1/pom.xml +++ b/grpc-google-cloud-firestore-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-firestore-v1 - 3.16.0 + 3.16.1 grpc-google-cloud-firestore-v1 GRPC library for grpc-google-cloud-firestore-v1 com.google.cloud google-cloud-firestore-parent - 3.16.0 + 3.16.1 diff --git a/pom.xml b/pom.xml index 5001fae837..c49f0f9817 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-firestore-parent pom - 3.16.0 + 3.16.1 Google Cloud Firestore Parent https://github.com/googleapis/java-firestore @@ -150,38 +150,38 @@ com.google.api.grpc proto-google-cloud-firestore-admin-v1 - 3.16.0 + 3.16.1 com.google.cloud google-cloud-firestore - 3.16.0 + 3.16.1 com.google.cloud proto-google-cloud-firestore-bundle-v1 - 3.16.0 + 3.16.1 com.google.api.grpc proto-google-cloud-firestore-v1 - 3.16.0 + 3.16.1 com.google.api.grpc grpc-google-cloud-firestore-admin-v1 - 3.16.0 + 3.16.1 com.google.api.grpc grpc-google-cloud-firestore-v1 - 3.16.0 + 3.16.1 com.google.cloud google-cloud-shared-dependencies - 3.21.0 + 3.23.0 pom import @@ -195,7 +195,7 @@ com.google.truth truth - 1.1.5 + 1.3.0 test diff --git a/proto-google-cloud-firestore-admin-v1/pom.xml b/proto-google-cloud-firestore-admin-v1/pom.xml index ba1e334c7f..6f725f11d8 100644 --- a/proto-google-cloud-firestore-admin-v1/pom.xml +++ b/proto-google-cloud-firestore-admin-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-firestore-admin-v1 - 3.16.0 + 3.16.1 proto-google-cloud-firestore-admin-v1 PROTO library for proto-google-cloud-firestore-admin-v1 com.google.cloud google-cloud-firestore-parent - 3.16.0 + 3.16.1 diff --git a/proto-google-cloud-firestore-admin-v1/src/main/proto/google/firestore/admin/v1/firestore_admin.proto b/proto-google-cloud-firestore-admin-v1/src/main/proto/google/firestore/admin/v1/firestore_admin.proto index 53f134a1b5..07cc764b5f 100644 --- a/proto-google-cloud-firestore-admin-v1/src/main/proto/google/firestore/admin/v1/firestore_admin.proto +++ b/proto-google-cloud-firestore-admin-v1/src/main/proto/google/firestore/admin/v1/firestore_admin.proto @@ -164,7 +164,7 @@ service FirestoreAdmin { // only supports listing fields that have been explicitly overridden. To issue // this query, call // [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] - // with the filter set to `indexConfig.usesAncestorConfig:false or + // with the filter set to `indexConfig.usesAncestorConfig:false` or // `ttlConfig:*`. rpc ListFields(ListFieldsRequest) returns (ListFieldsResponse) { option (google.api.http) = { diff --git a/proto-google-cloud-firestore-bundle-v1/pom.xml b/proto-google-cloud-firestore-bundle-v1/pom.xml index 1e927d07b0..6aa7253332 100644 --- a/proto-google-cloud-firestore-bundle-v1/pom.xml +++ b/proto-google-cloud-firestore-bundle-v1/pom.xml @@ -5,14 +5,14 @@ 4.0.0 proto-google-cloud-firestore-bundle-v1 - 3.16.0 + 3.16.1 proto-google-cloud-firestore-bundle-v1 PROTO library for proto-google-cloud-firestore-bundle-v1 com.google.cloud google-cloud-firestore-parent - 3.16.0 + 3.16.1 diff --git a/proto-google-cloud-firestore-v1/pom.xml b/proto-google-cloud-firestore-v1/pom.xml index f43cf5359e..e6f7d50a80 100644 --- a/proto-google-cloud-firestore-v1/pom.xml +++ b/proto-google-cloud-firestore-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-firestore-v1 - 3.16.0 + 3.16.1 proto-google-cloud-firestore-v1 PROTO library for proto-google-cloud-firestore-v1 com.google.cloud google-cloud-firestore-parent - 3.16.0 + 3.16.1 diff --git a/proto-google-cloud-firestore-v1/src/main/java/com/google/firestore/v1/Document.java b/proto-google-cloud-firestore-v1/src/main/java/com/google/firestore/v1/Document.java index 8932dabcf3..ffee1bcd44 100644 --- a/proto-google-cloud-firestore-v1/src/main/java/com/google/firestore/v1/Document.java +++ b/proto-google-cloud-firestore-v1/src/main/java/com/google/firestore/v1/Document.java @@ -164,23 +164,23 @@ public int getFieldsCount() { * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. + * + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -209,23 +209,23 @@ public java.util.Map getFields( * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. + * + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -245,23 +245,23 @@ public java.util.Map getFieldsM * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. + * + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -289,23 +289,23 @@ public java.util.Map getFieldsM * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. + * + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -1046,23 +1046,23 @@ public int getFieldsCount() { * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. + * + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -1091,23 +1091,23 @@ public java.util.Map getFields( * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. + * + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -1127,23 +1127,23 @@ public java.util.Map getFieldsM * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. + * + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -1171,23 +1171,23 @@ public java.util.Map getFieldsM * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. + * + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -1221,23 +1221,23 @@ public Builder clearFields() { * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. + * + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -1266,23 +1266,23 @@ public java.util.Map getMutable * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. + * + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -1309,23 +1309,23 @@ public Builder putFields(java.lang.String key, com.google.firestore.v1.Value val * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. + * + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. diff --git a/proto-google-cloud-firestore-v1/src/main/java/com/google/firestore/v1/DocumentOrBuilder.java b/proto-google-cloud-firestore-v1/src/main/java/com/google/firestore/v1/DocumentOrBuilder.java index f04f0d82a2..6e68740080 100644 --- a/proto-google-cloud-firestore-v1/src/main/java/com/google/firestore/v1/DocumentOrBuilder.java +++ b/proto-google-cloud-firestore-v1/src/main/java/com/google/firestore/v1/DocumentOrBuilder.java @@ -58,23 +58,23 @@ public interface DocumentOrBuilder * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. + * + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -91,23 +91,23 @@ public interface DocumentOrBuilder * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. + * + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -127,23 +127,23 @@ public interface DocumentOrBuilder * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. + * + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -160,23 +160,23 @@ public interface DocumentOrBuilder * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. + * + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. @@ -197,23 +197,23 @@ com.google.firestore.v1.Value getFieldsOrDefault( * * The map keys represent field names. * - * A simple field name contains only characters `a` to `z`, `A` to `Z`, - * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - * `foo_bar_17`. - * * Field names matching the regular expression `__.*__` are reserved. Reserved - * field names are forbidden except in certain documented contexts. The map - * keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + * field names are forbidden except in certain documented contexts. The field + * names, represented as UTF-8, must not exceed 1,500 bytes and cannot be * empty. * * Field paths may be used in other contexts to refer to structured fields - * defined here. For `map_value`, the field path is represented by the simple - * or quoted field names of the containing fields, delimited by `.`. For - * example, the structured field - * `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - * represented by the field path `foo.x&y`. + * defined here. For `map_value`, the field path is represented by a + * dot-delimited (`.`) string of segments. Each segment is either a simple + * field name (defined below) or a quoted field name. For example, the + * structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + * }}}` would be represented by the field path `` foo.`x&y` ``. + * + * A simple field name contains only characters `a` to `z`, `A` to `Z`, + * `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + * `foo_bar_17`. * - * Within a field path, a quoted field name starts and ends with `` ` `` and + * A quoted field name starts and ends with `` ` `` and * may contain any character. Some characters, including `` ` ``, must be * escaped using a `\`. For example, `` `x&y` `` represents `x&y` and * `` `bak\`tik` `` represents `` bak`tik ``. diff --git a/proto-google-cloud-firestore-v1/src/main/java/com/google/firestore/v1/StructuredQuery.java b/proto-google-cloud-firestore-v1/src/main/java/com/google/firestore/v1/StructuredQuery.java index 2fdf3d3a37..d2d0b78692 100644 --- a/proto-google-cloud-firestore-v1/src/main/java/com/google/firestore/v1/StructuredQuery.java +++ b/proto-google-cloud-firestore-v1/src/main/java/com/google/firestore/v1/StructuredQuery.java @@ -23,6 +23,14 @@ * *
  * A Firestore query.
+ *
+ * The query stages are executed in the following order:
+ * 1. from
+ * 2. where
+ * 3. select
+ * 4. order_by + start_at + end_at
+ * 5. offset
+ * 6. limit
  * 
* * Protobuf type {@code google.firestore.v1.StructuredQuery} @@ -10417,6 +10425,14 @@ protected Builder newBuilderForType(com.google.protobuf.GeneratedMessageV3.Build * *
    * A Firestore query.
+   *
+   * The query stages are executed in the following order:
+   * 1. from
+   * 2. where
+   * 3. select
+   * 4. order_by + start_at + end_at
+   * 5. offset
+   * 6. limit
    * 
* * Protobuf type {@code google.firestore.v1.StructuredQuery} diff --git a/proto-google-cloud-firestore-v1/src/main/proto/google/firestore/v1/document.proto b/proto-google-cloud-firestore-v1/src/main/proto/google/firestore/v1/document.proto index 795200498a..a8764a1a28 100644 --- a/proto-google-cloud-firestore-v1/src/main/proto/google/firestore/v1/document.proto +++ b/proto-google-cloud-firestore-v1/src/main/proto/google/firestore/v1/document.proto @@ -41,23 +41,23 @@ message Document { // // The map keys represent field names. // - // A simple field name contains only characters `a` to `z`, `A` to `Z`, - // `0` to `9`, or `_`, and must not start with `0` to `9`. For example, - // `foo_bar_17`. - // // Field names matching the regular expression `__.*__` are reserved. Reserved - // field names are forbidden except in certain documented contexts. The map - // keys, represented as UTF-8, must not exceed 1,500 bytes and cannot be + // field names are forbidden except in certain documented contexts. The field + // names, represented as UTF-8, must not exceed 1,500 bytes and cannot be // empty. // // Field paths may be used in other contexts to refer to structured fields - // defined here. For `map_value`, the field path is represented by the simple - // or quoted field names of the containing fields, delimited by `.`. For - // example, the structured field - // `"foo" : { map_value: { "x&y" : { string_value: "hello" }}}` would be - // represented by the field path `foo.x&y`. + // defined here. For `map_value`, the field path is represented by a + // dot-delimited (`.`) string of segments. Each segment is either a simple + // field name (defined below) or a quoted field name. For example, the + // structured field `"foo" : { map_value: { "x&y" : { string_value: "hello" + // }}}` would be represented by the field path `` foo.`x&y` ``. + // + // A simple field name contains only characters `a` to `z`, `A` to `Z`, + // `0` to `9`, or `_`, and must not start with `0` to `9`. For example, + // `foo_bar_17`. // - // Within a field path, a quoted field name starts and ends with `` ` `` and + // A quoted field name starts and ends with `` ` `` and // may contain any character. Some characters, including `` ` ``, must be // escaped using a `\`. For example, `` `x&y` `` represents `x&y` and // `` `bak\`tik` `` represents `` bak`tik ``. diff --git a/proto-google-cloud-firestore-v1/src/main/proto/google/firestore/v1/query.proto b/proto-google-cloud-firestore-v1/src/main/proto/google/firestore/v1/query.proto index b7d01c24e5..09eefa2411 100644 --- a/proto-google-cloud-firestore-v1/src/main/proto/google/firestore/v1/query.proto +++ b/proto-google-cloud-firestore-v1/src/main/proto/google/firestore/v1/query.proto @@ -30,6 +30,14 @@ option php_namespace = "Google\\Cloud\\Firestore\\V1"; option ruby_package = "Google::Cloud::Firestore::V1"; // A Firestore query. +// +// The query stages are executed in the following order: +// 1. from +// 2. where +// 3. select +// 4. order_by + start_at + end_at +// 5. offset +// 6. limit message StructuredQuery { // A selection of a collection, such as `messages as m1`. message CollectionSelector { diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index b529548d96..b98bd6b25b 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -30,7 +30,7 @@ com.google.cloud google-cloud-firestore - 3.15.7 + 3.16.0 @@ -55,7 +55,7 @@ com.google.truth truth - 1.1.5 + 1.3.0 test
diff --git a/samples/native-image-sample/pom.xml b/samples/native-image-sample/pom.xml index 7a06356f98..224b9a9324 100644 --- a/samples/native-image-sample/pom.xml +++ b/samples/native-image-sample/pom.xml @@ -32,7 +32,7 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> com.google.cloud libraries-bom - 26.29.0 + 26.30.0 pom import @@ -66,7 +66,7 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> com.google.truth truth - 1.1.5 + 1.3.0 test
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index b2d79866f7..345b1109e6 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -29,7 +29,7 @@ com.google.cloud google-cloud-firestore - 3.15.7 + 3.16.0 @@ -41,7 +41,7 @@ com.google.truth truth - 1.1.5 + 1.3.0 test diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 51d2add5dc..94f1f32b42 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -34,7 +34,7 @@ com.google.cloud libraries-bom - 26.29.0 + 26.30.0 pom import @@ -69,7 +69,7 @@ com.google.truth truth - 1.1.5 + 1.3.0 test
diff --git a/versions.txt b/versions.txt index 124a5dedb6..ce911d1660 100644 --- a/versions.txt +++ b/versions.txt @@ -1,11 +1,11 @@ # Format: # module:released-version:current-version -google-cloud-firestore:3.16.0:3.16.0 -google-cloud-firestore-admin:3.16.0:3.16.0 -google-cloud-firestore-bom:3.16.0:3.16.0 -grpc-google-cloud-firestore-admin-v1:3.16.0:3.16.0 -grpc-google-cloud-firestore-v1:3.16.0:3.16.0 -proto-google-cloud-firestore-admin-v1:3.16.0:3.16.0 -proto-google-cloud-firestore-v1:3.16.0:3.16.0 -proto-google-cloud-firestore-bundle-v1:3.16.0:3.16.0 +google-cloud-firestore:3.16.1:3.16.1 +google-cloud-firestore-admin:3.16.1:3.16.1 +google-cloud-firestore-bom:3.16.1:3.16.1 +grpc-google-cloud-firestore-admin-v1:3.16.1:3.16.1 +grpc-google-cloud-firestore-v1:3.16.1:3.16.1 +proto-google-cloud-firestore-admin-v1:3.16.1:3.16.1 +proto-google-cloud-firestore-v1:3.16.1:3.16.1 +proto-google-cloud-firestore-bundle-v1:3.16.1:3.16.1