From 60a5e4c20860b2a08d9c4b482250fc6956e29483 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 11 Oct 2024 14:14:08 -0400 Subject: [PATCH] Synchronize protos (#6369) This is a result of comparison with official Firestore protos. Note, some gRPC endpoint and message additions were omitted since we have no plans of supporting them in SDK. --- firebase-firestore/CHANGELOG.md | 1 + .../firestore/v1/aggregation_result.proto | 7 +- .../google/firestore/v1/bloom_filter.proto | 26 +- .../proto/google/firestore/v1/common.proto | 26 +- .../proto/google/firestore/v1/document.proto | 35 +- .../proto/google/firestore/v1/firestore.proto | 358 +++++++++++------- .../src/proto/google/firestore/v1/query.proto | 284 ++++++++++---- .../src/proto/google/firestore/v1/write.proto | 72 ++-- 8 files changed, 515 insertions(+), 294 deletions(-) diff --git a/firebase-firestore/CHANGELOG.md b/firebase-firestore/CHANGELOG.md index e6f0f26cbc7..63ce09be53a 100644 --- a/firebase-firestore/CHANGELOG.md +++ b/firebase-firestore/CHANGELOG.md @@ -1,4 +1,5 @@ # Unreleased +* [changed] Update Firestore proto definitions. [#6369](//github.com/firebase/firebase-android-sdk/pull/6369) * [changed] Updated protobuf dependency to `3.25.5` to fix [CVE-2024-7254](https://github.com/advisories/GHSA-735f-pc8j-v9w8). diff --git a/firebase-firestore/src/proto/google/firestore/v1/aggregation_result.proto b/firebase-firestore/src/proto/google/firestore/v1/aggregation_result.proto index 538e3fef5e4..25e5d2e2e14 100644 --- a/firebase-firestore/src/proto/google/firestore/v1/aggregation_result.proto +++ b/firebase-firestore/src/proto/google/firestore/v1/aggregation_result.proto @@ -1,4 +1,4 @@ -// Copyright 2022 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. @@ -19,7 +19,7 @@ package google.firestore.v1; import "google/firestore/v1/document.proto"; option csharp_namespace = "Google.Cloud.Firestore.V1"; -option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore"; +option go_package = "cloud.google.com/go/firestore/apiv1/firestorepb;firestorepb"; option java_multiple_files = true; option java_outer_classname = "AggregationResultProto"; option java_package = "com.google.firestore.v1"; @@ -35,7 +35,8 @@ option ruby_package = "Google::Cloud::Firestore::V1"; message AggregationResult { // The result of the aggregation functions, ex: `COUNT(*) AS total_docs`. // - // The key is the [alias][google.firestore.v1.StructuredAggregationQuery.Aggregation.alias] + // The key is the + // [alias][google.firestore.v1.StructuredAggregationQuery.Aggregation.alias] // assigned to the aggregation function on input and the size of this map // equals the number of aggregation functions in the query. map aggregate_fields = 2; diff --git a/firebase-firestore/src/proto/google/firestore/v1/bloom_filter.proto b/firebase-firestore/src/proto/google/firestore/v1/bloom_filter.proto index 9487e3036fe..1b9eb376f26 100644 --- a/firebase-firestore/src/proto/google/firestore/v1/bloom_filter.proto +++ b/firebase-firestore/src/proto/google/firestore/v1/bloom_filter.proto @@ -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. @@ -17,7 +17,7 @@ syntax = "proto3"; package google.firestore.v1; option csharp_namespace = "Google.Cloud.Firestore.V1"; -option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore"; +option go_package = "cloud.google.com/go/firestore/apiv1/firestorepb;firestorepb"; option java_multiple_files = true; option java_outer_classname = "BloomFilterProto"; option java_package = "com.google.firestore.v1"; @@ -32,21 +32,21 @@ option ruby_package = "Google::Cloud::Firestore::V1"; // defines the number of bits of the last byte to be ignored as "padding". The // values of these "padding" bits are unspecified and must be ignored. // -// To retrieve the first bit, bit 0, calculate: (bitmap[0] & 0x01) != 0. -// To retrieve the second bit, bit 1, calculate: (bitmap[0] & 0x02) != 0. -// To retrieve the third bit, bit 2, calculate: (bitmap[0] & 0x04) != 0. -// To retrieve the fourth bit, bit 3, calculate: (bitmap[0] & 0x08) != 0. -// To retrieve bit n, calculate: (bitmap[n / 8] & (0x01 << (n % 8))) != 0. +// To retrieve the first bit, bit 0, calculate: `(bitmap[0] & 0x01) != 0`. +// To retrieve the second bit, bit 1, calculate: `(bitmap[0] & 0x02) != 0`. +// To retrieve the third bit, bit 2, calculate: `(bitmap[0] & 0x04) != 0`. +// To retrieve the fourth bit, bit 3, calculate: `(bitmap[0] & 0x08) != 0`. +// To retrieve bit n, calculate: `(bitmap[n / 8] & (0x01 << (n % 8))) != 0`. // // The "size" of a `BitSequence` (the number of bits it contains) is calculated -// by this formula: (bitmap.length * 8) - padding. +// by this formula: `(bitmap.length * 8) - padding`. message BitSequence { // The bytes that encode the bit sequence. // May have a length of zero. bytes bitmap = 1; // The number of bits of the last byte in `bitmap` to ignore as "padding". - // If the length of `bitmap` is zero, then this value must be 0. + // If the length of `bitmap` is zero, then this value must be `0`. // Otherwise, this value must be between 0 and 7, inclusive. int32 padding = 2; } @@ -57,10 +57,10 @@ message BitSequence { // hash as 2 distinct 64-bit hash values, interpreted as unsigned integers // using 2's complement encoding. // -// These two hash values, named h1 and h2, are then used to compute the -// `hash_count` hash values using the formula, starting at i=0: +// These two hash values, named `h1` and `h2`, are then used to compute the +// `hash_count` hash values using the formula, starting at `i=0`: // -// h(i) = h1 + (i * h2) +// h(i) = h1 + (i * h2) // // These resulting values are then taken modulo the number of bits in the bloom // filter to get the bits of the bloom filter to test for the given entry. @@ -70,4 +70,4 @@ message BloomFilter { // The number of hashes used by the algorithm. int32 hash_count = 2; -} \ No newline at end of file +} diff --git a/firebase-firestore/src/proto/google/firestore/v1/common.proto b/firebase-firestore/src/proto/google/firestore/v1/common.proto index 670cb41739b..fcb0f49fb00 100644 --- a/firebase-firestore/src/proto/google/firestore/v1/common.proto +++ b/firebase-firestore/src/proto/google/firestore/v1/common.proto @@ -1,4 +1,4 @@ -// Copyright 2018 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. @@ -11,32 +11,32 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -// syntax = "proto3"; package google.firestore.v1; -import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; option csharp_namespace = "Google.Cloud.Firestore.V1"; -option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore"; +option go_package = "cloud.google.com/go/firestore/apiv1/firestorepb;firestorepb"; option java_multiple_files = true; option java_outer_classname = "CommonProto"; option java_package = "com.google.firestore.v1"; option objc_class_prefix = "GCFS"; option php_namespace = "Google\\Cloud\\Firestore\\V1"; - +option ruby_package = "Google::Cloud::Firestore::V1"; // A set of field paths on a document. // Used to restrict a get or update operation on a document to a subset of its // fields. // This is different from standard field masks, as this is always scoped to a -// [Document][google.firestore.v1.Document], and takes in account the dynamic nature of [Value][google.firestore.v1.Value]. +// [Document][google.firestore.v1.Document], and takes in account the dynamic +// nature of [Value][google.firestore.v1.Value]. message DocumentMask { - // The list of field paths in the mask. See [Document.fields][google.firestore.v1.Document.fields] for a field - // path syntax reference. + // The list of field paths in the mask. See + // [Document.fields][google.firestore.v1.Document.fields] for a field path + // syntax reference. repeated string field_paths = 1; } @@ -49,7 +49,7 @@ message Precondition { bool exists = 1; // When set, the target document must exist and have been last updated at - // that time. + // that time. Timestamp must be microsecond aligned. google.protobuf.Timestamp update_time = 2; } } @@ -57,6 +57,9 @@ message Precondition { // Options for creating a new transaction. message TransactionOptions { // Options for a transaction that can be used to read and write documents. + // + // Firestore does not allow 3rd party auth requests to create read-write. + // transactions. message ReadWrite { // An optional transaction to retry. bytes retry_transaction = 1; @@ -68,7 +71,10 @@ message TransactionOptions { // consistency. oneof consistency_selector { // Reads documents at the given time. - // This may not be older than 60 seconds. + // + // This must be a microsecond precision timestamp within the past one + // hour, or if Point-in-Time Recovery is enabled, can additionally be a + // whole minute timestamp within the past 7 days. google.protobuf.Timestamp read_time = 2; } } diff --git a/firebase-firestore/src/proto/google/firestore/v1/document.proto b/firebase-firestore/src/proto/google/firestore/v1/document.proto index 268947856a8..52dc85ca9df 100644 --- a/firebase-firestore/src/proto/google/firestore/v1/document.proto +++ b/firebase-firestore/src/proto/google/firestore/v1/document.proto @@ -1,4 +1,4 @@ -// Copyright 2018 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. @@ -11,25 +11,24 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -// syntax = "proto3"; package google.firestore.v1; -import "google/api/annotations.proto"; +import "google/api/field_behavior.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/timestamp.proto"; import "google/type/latlng.proto"; option csharp_namespace = "Google.Cloud.Firestore.V1"; -option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore"; +option go_package = "cloud.google.com/go/firestore/apiv1/firestorepb;firestorepb"; option java_multiple_files = true; option java_outer_classname = "DocumentProto"; option java_package = "com.google.firestore.v1"; option objc_class_prefix = "GCFS"; option php_namespace = "Google\\Cloud\\Firestore\\V1"; - +option ruby_package = "Google::Cloud::Firestore::V1"; // A Firestore document. // @@ -43,23 +42,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 ``. @@ -124,7 +123,7 @@ message Value { // An array value. // - // Cannot directly contain another array value, though can contain an + // Cannot directly contain another array value, though can contain a // map which contains another array. ArrayValue array_value = 9; diff --git a/firebase-firestore/src/proto/google/firestore/v1/firestore.proto b/firebase-firestore/src/proto/google/firestore/v1/firestore.proto index 1bf75ea3c15..9ea56429afc 100644 --- a/firebase-firestore/src/proto/google/firestore/v1/firestore.proto +++ b/firebase-firestore/src/proto/google/firestore/v1/firestore.proto @@ -1,4 +1,4 @@ -// Copyright 2018 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. @@ -11,13 +11,14 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -// syntax = "proto3"; package google.firestore.v1; import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; import "google/firestore/v1/aggregation_result.proto"; import "google/firestore/v1/common.proto"; import "google/firestore/v1/document.proto"; @@ -29,31 +30,29 @@ import "google/protobuf/wrappers.proto"; import "google/rpc/status.proto"; option csharp_namespace = "Google.Cloud.Firestore.V1"; -option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore"; +option go_package = "cloud.google.com/go/firestore/apiv1/firestorepb;firestorepb"; option java_multiple_files = true; option java_outer_classname = "FirestoreProto"; option java_package = "com.google.firestore.v1"; -option objc_class_prefix = "GCFS"; option php_namespace = "Google\\Cloud\\Firestore\\V1"; +option ruby_package = "Google::Cloud::Firestore::V1"; + // Specification of the Firestore API. // The Cloud Firestore service. // -// This service exposes several types of comparable timestamps: -// -// * `create_time` - The time at which a document was created. Changes only -// when a document is deleted, then re-created. Increases in a strict -// monotonic fashion. -// * `update_time` - The time at which a document was last updated. Changes -// every time a document is modified. Does not change when a write results -// in no modifications. Increases in a strict monotonic fashion. -// * `read_time` - The time at which a particular state was observed. Used -// to denote a consistent snapshot of the database or the time at which a -// Document was observed to not exist. -// * `commit_time` - The time at which the writes in a transaction were -// committed. Any read with an equal or greater `read_time` is guaranteed -// to see the effects of the transaction. +// Cloud Firestore is a fast, fully managed, serverless, cloud-native NoSQL +// document database that simplifies storing, syncing, and querying data for +// your mobile, web, and IoT apps at global scale. Its client libraries provide +// live synchronization and offline support, while its security features and +// integrations with Firebase and Google Cloud Platform accelerate building +// truly serverless apps. service Firestore { + option (google.api.default_host) = "firestore.googleapis.com"; + option (google.api.oauth_scopes) = + "https://www.googleapis.com/auth/cloud-platform," + "https://www.googleapis.com/auth/datastore"; + // Gets a single document. rpc GetDocument(GetDocumentRequest) returns (Document) { option (google.api.http) = { @@ -65,14 +64,9 @@ service Firestore { rpc ListDocuments(ListDocumentsRequest) returns (ListDocumentsResponse) { option (google.api.http) = { get: "/v1/{parent=projects/*/databases/*/documents/*/**}/{collection_id}" - }; - } - - // Creates a new document. - rpc CreateDocument(CreateDocumentRequest) returns (Document) { - option (google.api.http) = { - post: "/v1/{parent=projects/*/databases/*/documents/**}/{collection_id}" - body: "document" + additional_bindings { + get: "/v1/{parent=projects/*/databases/*/documents}/{collection_id}" + } }; } @@ -82,6 +76,7 @@ service Firestore { patch: "/v1/{document.name=projects/*/databases/*/documents/*/**}" body: "document" }; + option (google.api.method_signature) = "document,update_mask"; } // Deletes a document. @@ -89,13 +84,15 @@ service Firestore { option (google.api.http) = { delete: "/v1/{name=projects/*/databases/*/documents/*/**}" }; + option (google.api.method_signature) = "name"; } // Gets multiple documents. // // Documents returned by this method are not guaranteed to be returned in the // same order that they were requested. - rpc BatchGetDocuments(BatchGetDocumentsRequest) returns (stream BatchGetDocumentsResponse) { + rpc BatchGetDocuments(BatchGetDocumentsRequest) + returns (stream BatchGetDocumentsResponse) { option (google.api.http) = { post: "/v1/{database=projects/*/databases/*}/documents:batchGet" body: "*" @@ -103,11 +100,13 @@ service Firestore { } // Starts a new transaction. - rpc BeginTransaction(BeginTransactionRequest) returns (BeginTransactionResponse) { + rpc BeginTransaction(BeginTransactionRequest) + returns (BeginTransactionResponse) { option (google.api.http) = { post: "/v1/{database=projects/*/databases/*}/documents:beginTransaction" body: "*" }; + option (google.api.method_signature) = "database"; } // Commits a transaction, while optionally updating documents. @@ -116,6 +115,7 @@ service Firestore { post: "/v1/{database=projects/*/databases/*}/documents:commit" body: "*" }; + option (google.api.method_signature) = "database,writes"; } // Rolls back a transaction. @@ -124,6 +124,7 @@ service Firestore { post: "/v1/{database=projects/*/databases/*}/documents:rollback" body: "*" }; + option (google.api.method_signature) = "database,transaction"; } // Runs a query. @@ -140,8 +141,9 @@ service Firestore { // 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 + // 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: @@ -150,7 +152,8 @@ service Firestore { // -- Return the number of documents in table given a filter. // SELECT COUNT(*) FROM ( SELECT * FROM k where a = true ); // ``` - rpc RunAggregationQuery(RunAggregationQueryRequest) returns (stream RunAggregationQueryResponse) { + rpc RunAggregationQuery(RunAggregationQueryRequest) + returns (stream RunAggregationQueryResponse) { option (google.api.http) = { post: "/v1/{parent=projects/*/databases/*/documents}:runAggregationQuery" body: "*" @@ -161,7 +164,8 @@ service Firestore { }; } - // Streams batches of document updates and deletes, in order. + // Streams batches of document updates and deletes, in order. This method is + // only available via gRPC or WebChannel (not REST). rpc Write(stream WriteRequest) returns (stream WriteResponse) { option (google.api.http) = { post: "/v1/{database=projects/*/databases/*}/documents:write" @@ -169,7 +173,8 @@ service Firestore { }; } - // Listens to changes. + // Listens to changes. This method is only available via gRPC or WebChannel + // (not REST). rpc Listen(stream ListenRequest) returns (stream ListenResponse) { option (google.api.http) = { post: "/v1/{database=projects/*/databases/*}/documents:listen" @@ -178,7 +183,8 @@ service Firestore { } // Lists all the collection IDs underneath a document. - rpc ListCollectionIds(ListCollectionIdsRequest) returns (ListCollectionIdsResponse) { + rpc ListCollectionIds(ListCollectionIdsRequest) + returns (ListCollectionIdsResponse) { option (google.api.http) = { post: "/v1/{parent=projects/*/databases/*/documents}:listCollectionIds" body: "*" @@ -187,14 +193,24 @@ service Firestore { body: "*" } }; + option (google.api.method_signature) = "parent"; + } + + // Creates a new document. + rpc CreateDocument(CreateDocumentRequest) returns (Document) { + option (google.api.http) = { + post: "/v1/{parent=projects/*/databases/*/documents/**}/{collection_id}" + body: "document" + }; } } -// The request for [Firestore.GetDocument][google.firestore.v1.Firestore.GetDocument]. +// The request for +// [Firestore.GetDocument][google.firestore.v1.Firestore.GetDocument]. message GetDocumentRequest { - // The resource name of the Document to get. In the format: + // Required. The resource name of the Document to get. In the format: // `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - string name = 1; + string name = 1 [(google.api.field_behavior) = REQUIRED]; // The fields to return. If not set, returns all fields. // @@ -209,87 +225,118 @@ message GetDocumentRequest { bytes transaction = 3; // Reads the version of the document at the given time. - // This may not be older than 60 seconds. + // + // This must be a microsecond precision timestamp within the past one hour, + // or if Point-in-Time Recovery is enabled, can additionally be a whole + // minute timestamp within the past 7 days. google.protobuf.Timestamp read_time = 5; } } -// The request for [Firestore.ListDocuments][google.firestore.v1.Firestore.ListDocuments]. +// The request for +// [Firestore.ListDocuments][google.firestore.v1.Firestore.ListDocuments]. message ListDocumentsRequest { - // The parent resource name. In the format: + // Required. The parent resource name. In the format: // `projects/{project_id}/databases/{database_id}/documents` or // `projects/{project_id}/databases/{database_id}/documents/{document_path}`. + // // For example: // `projects/my-project/databases/my-database/documents` or // `projects/my-project/databases/my-database/documents/chatrooms/my-chatroom` - string parent = 1; + string parent = 1 [(google.api.field_behavior) = REQUIRED]; - // The collection ID, relative to `parent`, to list. For example: `chatrooms` - // or `messages`. - string collection_id = 2; + // Optional. The collection ID, relative to `parent`, to list. + // + // For example: `chatrooms` or `messages`. + // + // This is optional, and when not provided, Firestore will list documents + // from all collections under the provided `parent`. + string collection_id = 2 [(google.api.field_behavior) = OPTIONAL]; - // The maximum number of documents to return. - int32 page_size = 3; + // Optional. The maximum number of documents to return in a single response. + // + // Firestore may return fewer than this value. + int32 page_size = 3 [(google.api.field_behavior) = OPTIONAL]; - // The `next_page_token` value returned from a previous List request, if any. - string page_token = 4; + // Optional. A page token, received from a previous `ListDocuments` response. + // + // Provide this to retrieve the subsequent page. When paginating, all other + // parameters (with the exception of `page_size`) must match the values set + // in the request that generated the page token. + string page_token = 4 [(google.api.field_behavior) = OPTIONAL]; - // The order to sort results by. For example: `priority desc, name`. - string order_by = 6; + // Optional. The optional ordering of the documents to return. + // + // For example: `priority desc, __name__ desc`. + // + // This mirrors the [`ORDER BY`][google.firestore.v1.StructuredQuery.order_by] + // used in Firestore queries but in a string representation. When absent, + // documents are ordered based on `__name__ ASC`. + string order_by = 6 [(google.api.field_behavior) = OPTIONAL]; - // The fields to return. If not set, returns all fields. + // Optional. The fields to return. If not set, returns all fields. // // If a document has a field that is not present in this mask, that field // will not be returned in the response. - DocumentMask mask = 7; + DocumentMask mask = 7 [(google.api.field_behavior) = OPTIONAL]; // The consistency mode for this transaction. // If not set, defaults to strong consistency. oneof consistency_selector { - // Reads documents in a transaction. + // Perform the read as part of an already active transaction. bytes transaction = 8; - // Reads documents as they were at the given time. - // This may not be older than 60 seconds. + // Perform the read at the provided time. + // + // This must be a microsecond precision timestamp within the past one hour, + // or if Point-in-Time Recovery is enabled, can additionally be a whole + // minute timestamp within the past 7 days. google.protobuf.Timestamp read_time = 10; } - // If the list should show missing documents. A missing document is a - // document that does not exist but has sub-documents. These documents will - // be returned with a key but will not have fields, [Document.create_time][google.firestore.v1.Document.create_time], - // or [Document.update_time][google.firestore.v1.Document.update_time] set. + // If the list should show missing documents. + // + // A document is missing if it does not exist, but there are sub-documents + // nested underneath it. When true, such missing documents will be returned + // with a key but will not have fields, + // [`create_time`][google.firestore.v1.Document.create_time], or + // [`update_time`][google.firestore.v1.Document.update_time] set. // - // Requests with `show_missing` may not specify `where` or - // `order_by`. + // Requests with `show_missing` may not specify `where` or `order_by`. bool show_missing = 12; } -// The response for [Firestore.ListDocuments][google.firestore.v1.Firestore.ListDocuments]. +// The response for +// [Firestore.ListDocuments][google.firestore.v1.Firestore.ListDocuments]. message ListDocumentsResponse { // The Documents found. repeated Document documents = 1; - // The next page token. + // A token to retrieve the next page of documents. + // + // If this field is omitted, there are no subsequent pages. string next_page_token = 2; } -// The request for [Firestore.CreateDocument][google.firestore.v1.Firestore.CreateDocument]. +// The request for +// [Firestore.CreateDocument][google.firestore.v1.Firestore.CreateDocument]. message CreateDocumentRequest { - // The parent resource. For example: + // Required. The parent resource. For example: // `projects/{project_id}/databases/{database_id}/documents` or // `projects/{project_id}/databases/{database_id}/documents/chatrooms/{chatroom_id}` - string parent = 1; + string parent = 1 [(google.api.field_behavior) = REQUIRED]; - // The collection ID, relative to `parent`, to list. For example: `chatrooms`. - string collection_id = 2; + // Required. The collection ID, relative to `parent`, to list. For example: + // `chatrooms`. + string collection_id = 2 [(google.api.field_behavior) = REQUIRED]; // The client-assigned document ID to use for this document. // // Optional. If not specified, an ID will be assigned by the service. string document_id = 3; - // The document to create. `name` must not be set. - Document document = 4; + // Required. The document to create. `name` must not be set. + Document document = 4 [(google.api.field_behavior) = REQUIRED]; // The fields to return. If not set, returns all fields. // @@ -298,11 +345,12 @@ message CreateDocumentRequest { DocumentMask mask = 5; } -// The request for [Firestore.UpdateDocument][google.firestore.v1.Firestore.UpdateDocument]. +// The request for +// [Firestore.UpdateDocument][google.firestore.v1.Firestore.UpdateDocument]. message UpdateDocumentRequest { - // The updated document. + // Required. The updated document. // Creates the document if it does not already exist. - Document document = 1; + Document document = 1 [(google.api.field_behavior) = REQUIRED]; // The fields to update. // None of the field paths in the mask may contain a reserved name. @@ -324,22 +372,24 @@ message UpdateDocumentRequest { Precondition current_document = 4; } -// The request for [Firestore.DeleteDocument][google.firestore.v1.Firestore.DeleteDocument]. +// The request for +// [Firestore.DeleteDocument][google.firestore.v1.Firestore.DeleteDocument]. message DeleteDocumentRequest { - // The resource name of the Document to delete. In the format: + // Required. The resource name of the Document to delete. In the format: // `projects/{project_id}/databases/{database_id}/documents/{document_path}`. - string name = 1; + string name = 1 [(google.api.field_behavior) = REQUIRED]; // An optional precondition on the document. // The request will fail if this is set and not met by the target document. Precondition current_document = 2; } -// The request for [Firestore.BatchGetDocuments][google.firestore.v1.Firestore.BatchGetDocuments]. +// The request for +// [Firestore.BatchGetDocuments][google.firestore.v1.Firestore.BatchGetDocuments]. message BatchGetDocumentsRequest { - // The database name. In the format: + // Required. The database name. In the format: // `projects/{project_id}/databases/{database_id}`. - string database = 1; + string database = 1 [(google.api.field_behavior) = REQUIRED]; // The names of the documents to retrieve. In the format: // `projects/{project_id}/databases/{database_id}/documents/{document_path}`. @@ -366,12 +416,16 @@ message BatchGetDocumentsRequest { TransactionOptions new_transaction = 5; // Reads documents as they were at the given time. - // This may not be older than 60 seconds. + // + // This must be a microsecond precision timestamp within the past one hour, + // or if Point-in-Time Recovery is enabled, can additionally be a whole + // minute timestamp within the past 7 days. google.protobuf.Timestamp read_time = 7; } } -// The streamed response for [Firestore.BatchGetDocuments][google.firestore.v1.Firestore.BatchGetDocuments]. +// The streamed response for +// [Firestore.BatchGetDocuments][google.firestore.v1.Firestore.BatchGetDocuments]. message BatchGetDocumentsResponse { // A single result. // This can be empty if the server is just returning a transaction. @@ -386,7 +440,8 @@ message BatchGetDocumentsResponse { // The transaction that was started as part of this request. // Will only be set in the first response, and only if - // [BatchGetDocumentsRequest.new_transaction][google.firestore.v1.BatchGetDocumentsRequest.new_transaction] was set in the request. + // [BatchGetDocumentsRequest.new_transaction][google.firestore.v1.BatchGetDocumentsRequest.new_transaction] + // was set in the request. bytes transaction = 3; // The time at which the document was read. @@ -396,18 +451,20 @@ message BatchGetDocumentsResponse { google.protobuf.Timestamp read_time = 4; } -// The request for [Firestore.BeginTransaction][google.firestore.v1.Firestore.BeginTransaction]. +// The request for +// [Firestore.BeginTransaction][google.firestore.v1.Firestore.BeginTransaction]. message BeginTransactionRequest { - // The database name. In the format: + // Required. The database name. In the format: // `projects/{project_id}/databases/{database_id}`. - string database = 1; + string database = 1 [(google.api.field_behavior) = REQUIRED]; // The options for the transaction. // Defaults to a read-write transaction. TransactionOptions options = 2; } -// The response for [Firestore.BeginTransaction][google.firestore.v1.Firestore.BeginTransaction]. +// The response for +// [Firestore.BeginTransaction][google.firestore.v1.Firestore.BeginTransaction]. message BeginTransactionResponse { // The transaction that was started. bytes transaction = 1; @@ -415,9 +472,9 @@ message BeginTransactionResponse { // The request for [Firestore.Commit][google.firestore.v1.Firestore.Commit]. message CommitRequest { - // The database name. In the format: + // Required. The database name. In the format: // `projects/{project_id}/databases/{database_id}`. - string database = 1; + string database = 1 [(google.api.field_behavior) = REQUIRED]; // The writes to apply. // @@ -436,29 +493,30 @@ message CommitResponse { // request. repeated WriteResult write_results = 1; - // The time at which the commit occurred. + // The time at which the commit occurred. Any read with an equal or greater + // `read_time` is guaranteed to see the effects of the commit. google.protobuf.Timestamp commit_time = 2; } // The request for [Firestore.Rollback][google.firestore.v1.Firestore.Rollback]. message RollbackRequest { - // The database name. In the format: + // Required. The database name. In the format: // `projects/{project_id}/databases/{database_id}`. - string database = 1; + string database = 1 [(google.api.field_behavior) = REQUIRED]; - // The transaction to roll back. - bytes transaction = 2; + // Required. The transaction to roll back. + bytes transaction = 2 [(google.api.field_behavior) = REQUIRED]; } // The request for [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery]. message RunQueryRequest { - // The parent resource name. In the format: + // Required. The parent resource name. In the format: // `projects/{project_id}/databases/{database_id}/documents` or // `projects/{project_id}/databases/{database_id}/documents/{document_path}`. // For example: // `projects/my-project/databases/my-database/documents` or // `projects/my-project/databases/my-database/documents/chatrooms/my-chatroom` - string parent = 1; + string parent = 1 [(google.api.field_behavior) = REQUIRED]; // The query to run. oneof query_type { @@ -469,7 +527,9 @@ message RunQueryRequest { // The consistency mode for this transaction. // If not set, defaults to strong consistency. oneof consistency_selector { - // Reads documents in a transaction. + // Run the query within an already active transaction. + // + // The value here is the opaque transaction ID to execute the query in. bytes transaction = 5; // Starts a new transaction and reads the documents. @@ -479,21 +539,25 @@ message RunQueryRequest { TransactionOptions new_transaction = 6; // Reads documents as they were at the given time. - // This may not be older than 60 seconds. + // + // This must be a microsecond precision timestamp within the past one hour, + // or if Point-in-Time Recovery is enabled, can additionally be a whole + // minute timestamp within the past 7 days. google.protobuf.Timestamp read_time = 7; } } -// The response for [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery]. +// The response for +// [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery]. message RunQueryResponse { // The transaction that was started as part of this request. // Can only be set in the first response, and only if - // [RunQueryRequest.new_transaction][google.firestore.v1.RunQueryRequest.new_transaction] was set in the request. - // If set, no other fields will be set in this response. + // [RunQueryRequest.new_transaction][google.firestore.v1.RunQueryRequest.new_transaction] + // was set in the request. If set, no other fields will be set in this + // response. bytes transaction = 2; - // A query result. - // Not set when reporting partial progress. + // A query result, not set when reporting partial progress. Document document = 1; // The time at which the document was read. This may be monotonically @@ -518,7 +582,7 @@ message RunAggregationQueryRequest { // For example: // `projects/my-project/databases/my-database/documents` or // `projects/my-project/databases/my-database/documents/chatrooms/my-chatroom` - string parent = 1; + string parent = 1 [(google.api.field_behavior) = REQUIRED]; // The query to run. oneof query_type { @@ -541,19 +605,19 @@ message RunAggregationQueryRequest { // Executes the query at the given timestamp. // - // Requires: - // - // * Cannot be more than 270 seconds in the past. + // This must be a microsecond precision timestamp within the past one hour, + // or if Point-in-Time Recovery is enabled, can additionally be a whole + // minute timestamp within the past 7 days. google.protobuf.Timestamp read_time = 6; } } -// The response for [Firestore.RunAggregationQuery][google.firestore.v1.Firestore.RunAggregationQuery]. +// The response for +// [Firestore.RunAggregationQuery][google.firestore.v1.Firestore.RunAggregationQuery]. message RunAggregationQueryResponse { // A single aggregation result. // - // Not present when reporting partial progress or when the query produced - // zero results. + // Not present when reporting partial progress. AggregationResult result = 1; // The transaction that was started as part of this request. @@ -562,7 +626,14 @@ message RunAggregationQueryResponse { // a new transaction. bytes transaction = 2; - // The time at which the aggregate value is valid for. + // The time at which the aggregate result was computed. This is always + // monotonically increasing; in this case, the previous AggregationResult in + // the result stream are guaranteed not to have changed between their + // `read_time` and this one. + // + // If the query returns no results, a response with `read_time` and no + // `result` will be sent, and this represents the time at which the query + // was run. google.protobuf.Timestamp read_time = 3; } @@ -577,10 +648,10 @@ message RunAggregationQueryResponse { // given token, then a response containing only an up-to-date token, to use in // the next request. message WriteRequest { - // The database name. In the format: + // Required. The database name. In the format: // `projects/{project_id}/databases/{database_id}`. // This is only required in the first message. - string database = 1; + string database = 1 [(google.api.field_behavior) = REQUIRED]; // The ID of the write stream to resume. // This may only be set in the first message. When left empty, a new write @@ -598,9 +669,9 @@ message WriteRequest { // A stream token that was previously sent by the server. // // The client should set this field to the token from the most recent - // [WriteResponse][google.firestore.v1.WriteResponse] it has received. This acknowledges that the client has - // received responses up to this token. After sending this token, earlier - // tokens may not be used anymore. + // [WriteResponse][google.firestore.v1.WriteResponse] it has received. This + // acknowledges that the client has received responses up to this token. After + // sending this token, earlier tokens may not be used anymore. // // The server may close the stream if there are too many unacknowledged // responses. @@ -633,15 +704,16 @@ message WriteResponse { // request. repeated WriteResult write_results = 3; - // The time at which the commit occurred. + // The time at which the commit occurred. Any read with an equal or greater + // `read_time` is guaranteed to see the effects of the write. google.protobuf.Timestamp commit_time = 4; } // A request for [Firestore.Listen][google.firestore.v1.Firestore.Listen] message ListenRequest { - // The database name. In the format: + // Required. The database name. In the format: // `projects/{project_id}/databases/{database_id}`. - string database = 1; + string database = 1 [(google.api.field_behavior) = REQUIRED]; // The supported target changes. oneof target_change { @@ -669,8 +741,8 @@ message ListenResponse { // A [Document][google.firestore.v1.Document] has been deleted. DocumentDelete document_delete = 4; - // A [Document][google.firestore.v1.Document] has been removed from a target (because it is no longer - // relevant to that target). + // A [Document][google.firestore.v1.Document] has been removed from a target + // (because it is no longer relevant to that target). DocumentRemove document_remove = 6; // A filter to apply to the set of documents previously returned for the @@ -721,10 +793,12 @@ message Target { // When to start listening. // - // If not specified, all matching Documents are returned before any - // subsequent changes. + // If specified, only the matching Documents that have been updated AFTER the + // `resume_token` or `read_time` will be returned. Otherwise, all matching + // Documents are returned before any subsequent changes. oneof resume_type { - // A resume token from a prior [TargetChange][google.firestore.v1.TargetChange] for an identical target. + // A resume token from a prior + // [TargetChange][google.firestore.v1.TargetChange] for an identical target. // // Using a resume token with a different target is unsupported and may fail. bytes resume_token = 4; @@ -735,14 +809,23 @@ message Target { google.protobuf.Timestamp read_time = 11; } - // A client provided target ID. + // The target ID that identifies the target on the stream. Must be a positive + // number and non-zero. // - // If not set, the server will assign an ID for the target. + // If `target_id` is 0 (or unspecified), the server will assign an ID for this + // target and return that in a `TargetChange::ADD` event. Once a target with + // `target_id=0` is added, all subsequent targets must also have + // `target_id=0`. If an `AddTarget` request with `target_id != 0` is + // sent to the server after a target with `target_id=0` is added, the server + // will immediately send a response with a `TargetChange::Remove` event. // - // Used for resuming a target without changing IDs. The IDs can either be - // client-assigned or be server-assigned in a previous stream. All targets - // with client provided IDs must be added before adding a target that needs - // a server-assigned id. + // Note that if the client sends multiple `AddTarget` requests + // without an ID, the order of IDs returned in `TargetChage.target_ids` are + // undefined. Therefore, clients should provide a target ID instead of relying + // on the server to assign one. + // + // If `target_id` is non-zero, there must not be an existing active target on + // this stream with the same ID. int32 target_id = 5; // If the target should be removed once it is current and consistent. @@ -754,7 +837,6 @@ message Target { // This value is only relevant when a `resume_type` is provided. This value // being present and greater than zero signals that the client wants // `ExistenceFilter.unchanged_names` to be included in the response. - // google.protobuf.Int32Value expected_count = 12; } @@ -796,11 +878,7 @@ message TargetChange { // // If empty, the change applies to all targets. // - // For `target_change_type=ADD`, the order of the target IDs matches the order - // of the requests to add the targets. This allows clients to unambiguously - // associate server-assigned target IDs with added targets. - // - // For other states, the order of the target IDs is not defined. + // The order of the target IDs is not defined. repeated int32 target_ids = 2; // The error that resulted in this change, if applicable. @@ -825,13 +903,14 @@ message TargetChange { google.protobuf.Timestamp read_time = 6; } -// The request for [Firestore.ListCollectionIds][google.firestore.v1.Firestore.ListCollectionIds]. +// The request for +// [Firestore.ListCollectionIds][google.firestore.v1.Firestore.ListCollectionIds]. message ListCollectionIdsRequest { - // The parent document. In the format: + // Required. The parent document. In the format: // `projects/{project_id}/databases/{database_id}/documents/{document_path}`. // For example: // `projects/my-project/databases/my-database/documents/chatrooms/my-chatroom` - string parent = 1; + string parent = 1 [(google.api.field_behavior) = REQUIRED]; // The maximum number of results to return. int32 page_size = 2; @@ -841,7 +920,8 @@ message ListCollectionIdsRequest { string page_token = 3; } -// The response from [Firestore.ListCollectionIds][google.firestore.v1.Firestore.ListCollectionIds]. +// The response from +// [Firestore.ListCollectionIds][google.firestore.v1.Firestore.ListCollectionIds]. message ListCollectionIdsResponse { // The collection ids. repeated string collection_ids = 1; diff --git a/firebase-firestore/src/proto/google/firestore/v1/query.proto b/firebase-firestore/src/proto/google/firestore/v1/query.proto index b6139c305f5..4e5e93cfa61 100644 --- a/firebase-firestore/src/proto/google/firestore/v1/query.proto +++ b/firebase-firestore/src/proto/google/firestore/v1/query.proto @@ -1,4 +1,4 @@ -// Copyright 2019 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. @@ -11,26 +11,33 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -// syntax = "proto3"; package google.firestore.v1; -import "google/api/annotations.proto"; +import "google/api/field_behavior.proto"; import "google/firestore/v1/document.proto"; import "google/protobuf/wrappers.proto"; option csharp_namespace = "Google.Cloud.Firestore.V1"; -option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore"; +option go_package = "cloud.google.com/go/firestore/apiv1/firestorepb;firestorepb"; option java_multiple_files = true; option java_outer_classname = "QueryProto"; option java_package = "com.google.firestore.v1"; option objc_class_prefix = "GCFS"; 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 { @@ -77,7 +84,10 @@ message StructuredQuery { Operator op = 1; // The list of filters to combine. - // Must contain at least one filter. + // + // Requires: + // + // * At least one filter is present. repeated Filter filters = 2; } @@ -116,7 +126,7 @@ message StructuredQuery { // * That `field` come first in `order_by`. GREATER_THAN_OR_EQUAL = 4; - // The given `field` is equal to the given `value`.. + // The given `field` is equal to the given `value`. EQUAL = 5; // The given `field` is not equal to the given `value`. @@ -134,8 +144,9 @@ message StructuredQuery { // // Requires: // - // * That `value` is a non-empty `ArrayValue` with at most 10 values. - // * No other `IN` or `ARRAY_CONTAINS_ANY`. (-- or `NOT_IN` --) + // * That `value` is a non-empty `ArrayValue`, subject to disjunction + // limits. + // * No `NOT_IN` filters in the same query. IN = 8; // The given `field` is an array that contains any of the values in the @@ -143,8 +154,10 @@ message StructuredQuery { // // Requires: // - // * That `value` is a non-empty `ArrayValue` with at most 10 values. - // * No other `IN` or `ARRAY_CONTAINS_ANY`. (-- or `NOT_IN` --) + // * That `value` is a non-empty `ArrayValue`, subject to disjunction + // limits. + // * No other `ARRAY_CONTAINS_ANY` filters within the same disjunction. + // * No `NOT_IN` filters in the same query. ARRAY_CONTAINS_ANY = 9; // The value of the `field` is not in the given array. @@ -152,7 +165,7 @@ message StructuredQuery { // Requires: // // * That `value` is a non-empty `ArrayValue` with at most 10 values. - // * No other `IN`, `ARRAY_CONTAINS_ANY`, `NOT_IN`, `NOT_EQUAL`, + // * No other `OR`, `IN`, `ARRAY_CONTAINS_ANY`, `NOT_IN`, `NOT_EQUAL`, // `IS_NOT_NULL`, or `IS_NOT_NAN`. // * That `field` comes first in the `order_by`. NOT_IN = 10; @@ -172,30 +185,30 @@ message StructuredQuery { message UnaryFilter { // A unary operator. enum Operator { - // Unspecified. This value must not be used. - OPERATOR_UNSPECIFIED = 0; - - // The given `field` is equal to `NaN`. - IS_NAN = 2; - - // The given `field` is equal to `NULL`. - IS_NULL = 3; - - // The given `field` is not equal to `NaN`. - // - // Requires: - // - // * No other `NOT_EQUAL`, `NOT_IN`, `IS_NOT_NULL`, or `IS_NOT_NAN`. - // * That `field` comes first in the `order_by`. - IS_NOT_NAN = 4; - - // The given `field` is not equal to `NULL`. - // - // Requires: - // - // * A single `NOT_EQUAL`, `NOT_IN`, `IS_NOT_NULL`, or `IS_NOT_NAN`. - // * That `field` comes first in the `order_by`. - IS_NOT_NULL = 5; + // Unspecified. This value must not be used. + OPERATOR_UNSPECIFIED = 0; + + // The given `field` is equal to `NaN`. + IS_NAN = 2; + + // The given `field` is equal to `NULL`. + IS_NULL = 3; + + // The given `field` is not equal to `NaN`. + // + // Requires: + // + // * No other `NOT_EQUAL`, `NOT_IN`, `IS_NOT_NULL`, or `IS_NOT_NAN`. + // * That `field` comes first in the `order_by`. + IS_NOT_NAN = 4; + + // The given `field` is not equal to `NULL`. + // + // Requires: + // + // * A single `NOT_EQUAL`, `NOT_IN`, `IS_NOT_NULL`, or `IS_NOT_NAN`. + // * That `field` comes first in the `order_by`. + IS_NOT_NULL = 5; } // The unary operator to apply. @@ -217,8 +230,27 @@ message StructuredQuery { Direction direction = 2; } - // A reference to a field, such as `max(messages.time) as max_time`. + // A sort direction. + enum Direction { + // Unspecified. + DIRECTION_UNSPECIFIED = 0; + + // Ascending. + ASCENDING = 1; + + // Descending. + DESCENDING = 2; + } + + // A reference to a field in a document, ex: `stats.operations`. message FieldReference { + // A reference to a field in a document. + // + // Requires: + // + // * MUST be a dot-delimited (`.`) string of segments, where each segment + // conforms to [document field name][google.firestore.v1.Document.fields] + // limitations. string field_path = 2; } @@ -231,19 +263,11 @@ message StructuredQuery { repeated FieldReference fields = 2; } - // A sort direction. - enum Direction { - // Unspecified. - DIRECTION_UNSPECIFIED = 0; - - // Ascending. - ASCENDING = 1; - - // Descending. - DESCENDING = 2; - } - - // The projection to return. + // Optional sub-set of the fields to return. + // + // This acts as a [DocumentMask][google.firestore.v1.DocumentMask] over the + // documents returned from a query. When not set, assumes that the caller + // wants all fields returned. Projection select = 1; // The collections to query. @@ -254,66 +278,119 @@ message StructuredQuery { // The order to apply to the query results. // - // Firestore guarantees a stable ordering through the following rules: + // Firestore allows callers to provide a full ordering, a partial ordering, or + // no ordering at all. In all cases, Firestore guarantees a stable ordering + // through the following rules: // - // * Any field required to appear in `order_by`, that is not already - // specified in `order_by`, is appended to the order in field name order - // by default. + // * The `order_by` is required to reference all fields used with an + // inequality filter. + // * All fields that are required to be in the `order_by` but are not already + // present are appended in lexicographical ordering of the field name. // * If an order on `__name__` is not specified, it is appended by default. // // Fields are appended with the same sort direction as the last order // specified, or 'ASCENDING' if no order was specified. For example: // - // * `SELECT * FROM Foo ORDER BY A` becomes - // `SELECT * FROM Foo ORDER BY A, __name__` - // * `SELECT * FROM Foo ORDER BY A DESC` becomes - // `SELECT * FROM Foo ORDER BY A DESC, __name__ DESC` - // * `SELECT * FROM Foo WHERE A > 1` becomes - // `SELECT * FROM Foo WHERE A > 1 ORDER BY A, __name__` + // * `ORDER BY a` becomes `ORDER BY a ASC, __name__ ASC` + // * `ORDER BY a DESC` becomes `ORDER BY a DESC, __name__ DESC` + // * `WHERE a > 1` becomes `WHERE a > 1 ORDER BY a ASC, __name__ ASC` + // * `WHERE __name__ > ... AND a > 1` becomes + // `WHERE __name__ > ... AND a > 1 ORDER BY a ASC, __name__ ASC` repeated Order order_by = 4; - // A starting point for the query results. + // A potential prefix of a position in the result set to start the query at. + // + // The ordering of the result set is based on the `ORDER BY` clause of the + // original query. + // + // ``` + // SELECT * FROM k WHERE a = 1 AND b > 2 ORDER BY b ASC, __name__ ASC; + // ``` + // + // This query's results are ordered by `(b ASC, __name__ ASC)`. + // + // Cursors can reference either the full ordering or a prefix of the location, + // though it cannot reference more fields than what are in the provided + // `ORDER BY`. + // + // Continuing off the example above, attaching the following start cursors + // will have varying impact: + // + // - `START BEFORE (2, /k/123)`: start the query right before `a = 1 AND + // b > 2 AND __name__ > /k/123`. + // - `START AFTER (10)`: start the query right after `a = 1 AND b > 10`. + // + // Unlike `OFFSET` which requires scanning over the first N results to skip, + // a start cursor allows the query to begin at a logical position. This + // position is not required to match an actual result, it will scan forward + // from this position to find the next document. + // + // Requires: + // + // * The number of values cannot be greater than the number of fields + // specified in the `ORDER BY` clause. Cursor start_at = 7; - // A end point for the query results. + // A potential prefix of a position in the result set to end the query at. + // + // This is similar to `START_AT` but with it controlling the end position + // rather than the start position. + // + // Requires: + // + // * The number of values cannot be greater than the number of fields + // specified in the `ORDER BY` clause. Cursor end_at = 8; - // The number of results to skip. + // The number of documents to skip before returning the first result. + // + // This applies after the constraints specified by the `WHERE`, `START AT`, & + // `END AT` but before the `LIMIT` clause. // - // Applies before limit, but after all other constraints. Must be >= 0 if - // specified. + // Requires: + // + // * The value must be greater than or equal to zero if specified. int32 offset = 6; // The maximum number of results to return. // // Applies after all other constraints. - // Must be >= 0 if specified. + // + // Requires: + // + // * The value must be greater than or equal to zero if specified. google.protobuf.Int32Value limit = 5; } +// Firestore query for running an aggregation over a +// [StructuredQuery][google.firestore.v1.StructuredQuery]. message StructuredAggregationQuery { - // Defines a aggregation that produces a single result. + // Defines an aggregation that produces a single result. message Aggregation { // Count of documents that match the query. // // The `COUNT(*)` aggregation function operates on the entire document // so it does not require a field reference. message Count { - // Optional. Optional constraint on the maximum number of documents to count. + // Optional. Optional constraint on the maximum number of documents to + // count. // // This provides a way to set an upper bound on the number of documents - // to scan, limiting latency and cost. + // to scan, limiting latency, and cost. + // + // Unspecified is interpreted as no bound. // // High-Level Example: // // ``` - // SELECT COUNT_UP_TO(1000) FROM ( SELECT * FROM k ); + // AGGREGATE COUNT_UP_TO(1000) OVER ( SELECT * FROM k ); // ``` // // Requires: // // * Must be greater than zero when present. - google.protobuf.Int64Value up_to = 1; + google.protobuf.Int64Value up_to = 1 + [(google.api.field_behavior) = OPTIONAL]; } // Sum of the values of the requested field. @@ -321,12 +398,22 @@ message StructuredAggregationQuery { // * Only numeric values will be aggregated. All non-numeric values // including `NULL` are skipped. // - // * If the aggregated values contain `NaN`, returns `NaN`. + // * If the aggregated values contain `NaN`, returns `NaN`. Infinity math + // follows IEEE-754 standards. // // * If the aggregated value set is empty, returns 0. // - // * Returns a 64-bit integer if the sum result is an integer value and does - // not overflow or underflow. Otherwise, the result is returned as a double. + // * Returns a 64-bit integer if all aggregated numbers are integers and the + // sum result does not overflow. Otherwise, the result is returned as a + // double. Note that even if all the aggregated values are integers, the + // result is returned as a double if it cannot fit within a 64-bit signed + // integer. When this occurs, the returned value will lose precision. + // + // * When underflow occurs, floating-point aggregation is non-deterministic. + // This means that running the same query repeatedly without any changes to + // the underlying values could produce slightly different results each + // time. In those cases, values should be stored as integers over + // floating-point numbers. message Sum { // The field to aggregate on. StructuredQuery.FieldReference field = 1; @@ -337,7 +424,8 @@ message StructuredAggregationQuery { // * Only numeric values will be aggregated. All non-numeric values // including `NULL` are skipped. // - // * If the aggregated values contain `NaN`, returns `NaN`. + // * If the aggregated values contain `NaN`, returns `NaN`. Infinity math + // follows IEEE-754 standards. // // * If the aggregated value set is empty, returns `NULL`. // @@ -359,14 +447,42 @@ message StructuredAggregationQuery { Avg avg = 3; } - // Required. The name of the field to store the result of the aggregation into. + // Optional. Optional name of the field to store the result of the + // aggregation into. + // + // If not provided, Firestore will pick a default name following the format + // `field_`. For example: + // + // ``` + // AGGREGATE + // COUNT_UP_TO(1) AS count_up_to_1, + // COUNT_UP_TO(2), + // COUNT_UP_TO(3) AS count_up_to_3, + // COUNT(*) + // OVER ( + // ... + // ); + // ``` + // + // becomes: + // + // ``` + // AGGREGATE + // COUNT_UP_TO(1) AS count_up_to_1, + // COUNT_UP_TO(2) AS field_1, + // COUNT_UP_TO(3) AS count_up_to_3, + // COUNT(*) AS field_2 + // OVER ( + // ... + // ); + // ``` // // Requires: // - // * Must be present. // * Must be unique across all aggregation aliases. - // * Conform to existing [document field name][google.firestore.v1.Document.fields] limitations. - string alias = 7; + // * Conform to [document field name][google.firestore.v1.Document.fields] + // limitations. + string alias = 7 [(google.api.field_behavior) = OPTIONAL]; } // The base query to aggregate over. @@ -375,8 +491,14 @@ message StructuredAggregationQuery { StructuredQuery structured_query = 1; } - // Optional. Series of aggregations to apply on top of the `structured_query`. - repeated Aggregation aggregations = 3; + // Optional. Series of aggregations to apply over the results of the + // `structured_query`. + // + // Requires: + // + // * A minimum of one and maximum of five aggregations per query. + repeated Aggregation aggregations = 3 + [(google.api.field_behavior) = OPTIONAL]; } // A position in a query result set. diff --git a/firebase-firestore/src/proto/google/firestore/v1/write.proto b/firebase-firestore/src/proto/google/firestore/v1/write.proto index 49acae6ebf6..f74b32e2782 100644 --- a/firebase-firestore/src/proto/google/firestore/v1/write.proto +++ b/firebase-firestore/src/proto/google/firestore/v1/write.proto @@ -1,4 +1,4 @@ -// Copyright 2018 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. @@ -11,26 +11,24 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -// syntax = "proto3"; package google.firestore.v1; -import "google/api/annotations.proto"; import "google/firestore/v1/bloom_filter.proto"; import "google/firestore/v1/common.proto"; import "google/firestore/v1/document.proto"; import "google/protobuf/timestamp.proto"; option csharp_namespace = "Google.Cloud.Firestore.V1"; -option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore"; +option go_package = "cloud.google.com/go/firestore/apiv1/firestorepb;firestorepb"; option java_multiple_files = true; option java_outer_classname = "WriteProto"; option java_package = "com.google.firestore.v1"; option objc_class_prefix = "GCFS"; option php_namespace = "Google\\Cloud\\Firestore\\V1"; - +option ruby_package = "Google::Cloud::Firestore::V1"; // A write on a document. message Write { @@ -48,7 +46,7 @@ message Write { // This only requires read access to the document. string verify = 5; - // Applies a tranformation to a document. + // Applies a transformation to a document. DocumentTransform transform = 6; } @@ -87,12 +85,14 @@ message DocumentTransform { SERVER_VALUE_UNSPECIFIED = 0; // The time at which the server processed the request, with millisecond - // precision. + // precision. If used on multiple fields (same or different documents) in + // a transaction, all the fields will get the same server timestamp. REQUEST_TIME = 1; } - // The path of the field. See [Document.fields][google.firestore.v1.Document.fields] for the field path syntax - // reference. + // The path of the field. See + // [Document.fields][google.firestore.v1.Document.fields] for the field path + // syntax reference. string field_path = 1; // The transformation to apply on the field. @@ -186,18 +186,20 @@ message WriteResult { // previous update_time. google.protobuf.Timestamp update_time = 1; - // The results of applying each [DocumentTransform.FieldTransform][google.firestore.v1.DocumentTransform.FieldTransform], in the - // same order. + // The results of applying each + // [DocumentTransform.FieldTransform][google.firestore.v1.DocumentTransform.FieldTransform], + // in the same order. repeated Value transform_results = 2; } // A [Document][google.firestore.v1.Document] has changed. // -// May be the result of multiple [writes][google.firestore.v1.Write], including deletes, that -// ultimately resulted in a new value for the [Document][google.firestore.v1.Document]. +// May be the result of multiple [writes][google.firestore.v1.Write], including +// deletes, that ultimately resulted in a new value for the +// [Document][google.firestore.v1.Document]. // -// Multiple [DocumentChange][google.firestore.v1.DocumentChange] messages may be returned for the same logical -// change, if multiple targets are affected. +// Multiple [DocumentChange][google.firestore.v1.DocumentChange] messages may be +// returned for the same logical change, if multiple targets are affected. message DocumentChange { // The new state of the [Document][google.firestore.v1.Document]. // @@ -213,13 +215,15 @@ message DocumentChange { // A [Document][google.firestore.v1.Document] has been deleted. // -// May be the result of multiple [writes][google.firestore.v1.Write], including updates, the -// last of which deleted the [Document][google.firestore.v1.Document]. +// May be the result of multiple [writes][google.firestore.v1.Write], including +// updates, the last of which deleted the +// [Document][google.firestore.v1.Document]. // -// Multiple [DocumentDelete][google.firestore.v1.DocumentDelete] messages may be returned for the same logical -// delete, if multiple targets are affected. +// Multiple [DocumentDelete][google.firestore.v1.DocumentDelete] messages may be +// returned for the same logical delete, if multiple targets are affected. message DocumentDelete { - // The resource name of the [Document][google.firestore.v1.Document] that was deleted. + // The resource name of the [Document][google.firestore.v1.Document] that was + // deleted. string document = 1; // A set of target IDs for targets that previously matched this entity. @@ -231,16 +235,19 @@ message DocumentDelete { google.protobuf.Timestamp read_time = 4; } -// A [Document][google.firestore.v1.Document] has been removed from the view of the targets. +// A [Document][google.firestore.v1.Document] has been removed from the view of +// the targets. // // Sent if the document is no longer relevant to a target and is out of view. // Can be sent instead of a DocumentDelete or a DocumentChange if the server // can not send the new value of the document. // -// Multiple [DocumentRemove][google.firestore.v1.DocumentRemove] messages may be returned for the same logical -// write or delete, if multiple targets are affected. +// Multiple [DocumentRemove][google.firestore.v1.DocumentRemove] messages may be +// returned for the same logical write or delete, if multiple targets are +// affected. message DocumentRemove { - // The resource name of the [Document][google.firestore.v1.Document] that has gone out of view. + // The resource name of the [Document][google.firestore.v1.Document] that has + // gone out of view. string document = 1; // A set of target IDs for targets that previously matched this document. @@ -257,17 +264,22 @@ message ExistenceFilter { // The target ID to which this filter applies. int32 target_id = 1; - // The total count of documents that match [target_id][google.firestore.v1.ExistenceFilter.target_id]. + // The total count of documents that match + // [target_id][google.firestore.v1.ExistenceFilter.target_id]. // // If different from the count of documents in the client that match, the // client must manually determine which documents no longer match the target. + // + // The client can use the `unchanged_names` bloom filter to assist with + // this determination by testing ALL the document names against the filter; + // if the document name is NOT in the filter, it means the document no + // longer matches the target. int32 count = 2; - // A bloom filter that contains the UTF-8 byte encodings of the resource names - // of the documents that match [target_id][google.firestore.v1.ExistenceFilter.target_id], in the - // form `projects/{project_id}/databases/{database_id}/documents/{document_path}` - // that have NOT changed since the query results indicated by the resume token - // or timestamp given in `Target.resume_type`. + // A bloom filter that, despite its name, contains the UTF-8 byte encodings of + // the resource names of ALL the documents that match + // [target_id][google.firestore.v1.ExistenceFilter.target_id], in the form + // `projects/{project_id}/databases/{database_id}/documents/{document_path}`. // // This bloom filter may be omitted at the server's discretion, such as if it // is deemed that the client will not make use of it or if it is too