diff --git a/common/api-review/firestore-lite.api.md b/common/api-review/firestore-lite.api.md index 4a9ef4c0171..c64526a2352 100644 --- a/common/api-review/firestore-lite.api.md +++ b/common/api-review/firestore-lite.api.md @@ -226,6 +226,9 @@ export function getCount(query: export function getDoc(reference: DocumentReference): Promise>; // @public +export function getDocs(query: VectorQuery): Promise>; + +// @public (undocumented) export function getDocs(query: Query): Promise>; // @public @@ -320,7 +323,7 @@ export class QueryEndAtConstraint extends QueryConstraint { } // @public -export function queryEqual(left: Query, right: Query): boolean; +export function queryEqual(left: Query | VectorQuery, right: Query | VectorQuery): boolean; // @public export class QueryFieldFilterConstraint extends QueryConstraint { @@ -390,7 +393,7 @@ export interface Settings { } // @public -export function snapshotEqual(left: DocumentSnapshot | QuerySnapshot, right: DocumentSnapshot | QuerySnapshot): boolean; +export function snapshotEqual(left: DocumentSnapshot | QuerySnapshot | VectorQuerySnapshot, right: DocumentSnapshot | QuerySnapshot | VectorQuerySnapshot): boolean; // @public export function startAfter(snapshot: DocumentSnapshot): QueryStartAtConstraint; @@ -463,6 +466,37 @@ export function updateDoc(refere // @public export function vector(values?: number[]): VectorValue; +// @public (undocumented) +export class VectorQuery { + protected constructor(); + get query(): Query; +} + +// @public (undocumented) +export interface VectorQueryOptions { + // (undocumented) + distanceMeasure: 'EUCLIDEAN' | 'COSINE' | 'DOT_PRODUCT'; + // (undocumented) + distanceResultField?: string | FieldPath; + // (undocumented) + distanceThreshold?: number; + // (undocumented) + limit: number; + // (undocumented) + queryVector: VectorValue | number[]; + // (undocumented) + vectorField: string | FieldPath; +} + +// @public (undocumented) +export class VectorQuerySnapshot { + get docs(): Array>; + get empty(): boolean; + forEach(callback: (result: QueryDocumentSnapshot) => void, thisArg?: unknown): void; + readonly query: VectorQuery; + get size(): number; +} + // @public export class VectorValue { /* Excluded from this release type: __constructor */ diff --git a/common/api-review/firestore.api.md b/common/api-review/firestore.api.md index 34b56b97f21..58d8ee737a9 100644 --- a/common/api-review/firestore.api.md +++ b/common/api-review/firestore.api.md @@ -222,6 +222,9 @@ export abstract class FieldValue { abstract isEqual(other: FieldValue): boolean; } +// @public (undocumented) +export function findNearest(query: Query, options: VectorQueryOptions): VectorQuery; + // @public export class Firestore { get app(): FirebaseApp; @@ -299,6 +302,9 @@ export function getDocsFromCache // @public export function getDocsFromServer(query: Query): Promise>; +// @public +export function getDocsFromServer(vectorQuery: VectorQuery): Promise>; + // @public export function getFirestore(): Firestore; @@ -578,7 +584,7 @@ export class QueryEndAtConstraint extends QueryConstraint { } // @public -export function queryEqual(left: Query, right: Query): boolean; +export function queryEqual(left: Query | VectorQuery, right: Query | VectorQuery): boolean; // @public export class QueryFieldFilterConstraint extends QueryConstraint { @@ -748,6 +754,38 @@ export function updateDoc(refere // @public export function vector(values?: number[]): VectorValue; +// @public (undocumented) +export class VectorQuery { + protected constructor(); + get query(): Query; +} + +// @public (undocumented) +export interface VectorQueryOptions { + // (undocumented) + distanceMeasure: 'EUCLIDEAN' | 'COSINE' | 'DOT_PRODUCT'; + // (undocumented) + distanceResultField?: string | FieldPath; + // (undocumented) + distanceThreshold?: number; + // (undocumented) + limit: number; + // (undocumented) + queryVector: VectorValue | number[]; + // (undocumented) + vectorField: string | FieldPath; +} + +// @public +export class VectorQuerySnapshot { + get docs(): Array>; + get empty(): boolean; + forEach(callback: (result: QueryDocumentSnapshot) => void, thisArg?: unknown): void; + readonly metadata: SnapshotMetadata; + readonly query: VectorQuery; + get size(): number; +} + // @public export class VectorValue { /* Excluded from this release type: __constructor */ diff --git a/packages/firestore/lite/index.ts b/packages/firestore/lite/index.ts index b751f0a8254..31e4264ec1d 100644 --- a/packages/firestore/lite/index.ts +++ b/packages/firestore/lite/index.ts @@ -140,6 +140,9 @@ export { } from '../src/lite-api/snapshot'; export { VectorValue } from '../src/lite-api/vector_value'; +export { VectorQuery } from '../src/lite-api/vector_query'; +export { VectorQuerySnapshot } from '../src/lite-api/vector_query_snapshot'; +export { VectorQueryOptions } from '../src/lite-api/vector_query_options'; export { WriteBatch, writeBatch } from '../src/lite-api/write_batch'; diff --git a/packages/firestore/package.json b/packages/firestore/package.json index cfd6bc61c3a..5385531836f 100644 --- a/packages/firestore/package.json +++ b/packages/firestore/package.json @@ -120,6 +120,7 @@ "chai-exclude": "2.1.0", "json-stable-stringify": "1.1.1", "protobufjs": "7.2.6", + "protobufjs-cli": "^1.1.3", "rollup": "2.79.1", "rollup-plugin-copy": "3.5.0", "rollup-plugin-copy-assets": "2.0.3", diff --git a/packages/firestore/src/api.ts b/packages/firestore/src/api.ts index ea969c6b94c..565b4b6267b 100644 --- a/packages/firestore/src/api.ts +++ b/packages/firestore/src/api.ts @@ -176,7 +176,12 @@ export { vector } from './api/field_value_impl'; -export { VectorValue } from './lite-api/vector_value'; +export { VectorValue } from './api/vector_value'; +export { VectorQuery } from './api/vector_query'; +export { VectorQuerySnapshot } from './api/vector_query_snapshot'; +export { VectorQueryOptions } from './api/vector_query_options'; + +export { findNearest } from './api/find_nearest'; export { LogLevelString as LogLevel, setLogLevel } from './util/log'; diff --git a/packages/firestore/src/api/find_nearest.ts b/packages/firestore/src/api/find_nearest.ts new file mode 100644 index 00000000000..2db38687c12 --- /dev/null +++ b/packages/firestore/src/api/find_nearest.ts @@ -0,0 +1,18 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { findNearest } from '../lite-api/find_nearest'; diff --git a/packages/firestore/src/api/reference_impl.ts b/packages/firestore/src/api/reference_impl.ts index e730fb40da7..1e415c447b1 100644 --- a/packages/firestore/src/api/reference_impl.ts +++ b/packages/firestore/src/api/reference_impl.ts @@ -24,6 +24,8 @@ import { NextFn, PartialObserver } from '../api/observer'; +import { QueryDocumentSnapshot } from '../api/snapshot'; +import { VectorQuerySnapshot } from '../api/vector_query_snapshot'; import { ListenerDataSource } from '../core/event_manager'; import { firestoreClientAddSnapshotsInSyncListener, @@ -32,6 +34,7 @@ import { firestoreClientGetDocumentsViaSnapshotListener, firestoreClientGetDocumentViaSnapshotListener, firestoreClientListen, + firestoreClientRunVectorQuery, firestoreClientWrite } from '../core/firestore_client'; import { newQueryForPath, Query as InternalQuery } from '../core/query'; @@ -59,6 +62,7 @@ import { parseUpdateVarargs } from '../lite-api/user_data_reader'; import { AbstractUserDataWriter } from '../lite-api/user_data_writer'; +import { VectorQuery } from '../lite-api/vector_query'; import { DeleteMutation, Mutation, Precondition } from '../model/mutation'; import { debugAssert } from '../util/assert'; import { ByteString } from '../util/byte_string'; @@ -270,17 +274,96 @@ export function getDocsFromServer< DbModelType extends DocumentData >( query: Query -): Promise> { - query = cast>(query, Query); - const firestore = cast(query.firestore, Firestore); - const client = ensureFirestoreConfigured(firestore); - const userDataWriter = new ExpUserDataWriter(firestore); +): Promise>; - return firestoreClientGetDocumentsViaSnapshotListener(client, query._query, { - source: 'server' - }).then( - snapshot => new QuerySnapshot(firestore, userDataWriter, query, snapshot) - ); +/** + * Executes the query and returns the results as a `QuerySnapshot` from the + * server. Returns an error if the network is not available. + * + * @returns A `Promise` that will be resolved with the results of the query. + */ +export function getDocsFromServer< + AppModelType, + DbModelType extends DocumentData +>( + vectorQuery: VectorQuery +): Promise>; + +/** + * Executes the query and returns the results as a `QuerySnapshot` from the + * server. Returns an error if the network is not available. + * + * @returns A `Promise` that will be resolved with the results of the query. + */ +export function getDocsFromServer< + AppModelType, + DbModelType extends DocumentData +>( + queryOrVectorQuery: + | Query + | VectorQuery +): Promise< + | QuerySnapshot + | VectorQuerySnapshot +> { + // If the query is a Query instance + if ( + 'type' in queryOrVectorQuery && + (queryOrVectorQuery.type! === 'query' || + queryOrVectorQuery.type! === 'collection') + ) { + const query = cast>( + queryOrVectorQuery, + Query + ); + + const firestore = cast(query.firestore, Firestore); + const client = ensureFirestoreConfigured(firestore); + const userDataWriter = new ExpUserDataWriter(firestore); + + return firestoreClientGetDocumentsViaSnapshotListener( + client, + query._query, + { + source: 'server' + } + ).then( + snapshot => new QuerySnapshot(firestore, userDataWriter, query, snapshot) + ); + } else { + // the query is a VectorQuery instance + const vectorQuery: VectorQuery = cast< + VectorQuery + >(queryOrVectorQuery, VectorQuery); + + const firestore = cast(vectorQuery.query.firestore, Firestore); + const client = ensureFirestoreConfigured(firestore); + const userDataWriter = new ExpUserDataWriter(firestore); + + // Run the aggregation and convert the results + return firestoreClientRunVectorQuery(client, vectorQuery._vectorQuery).then( + result => { + const docs = result.map( + doc => + new QueryDocumentSnapshot( + firestore, + userDataWriter, + doc.key, + doc, + new SnapshotMetadata(false, false), + vectorQuery.query.converter + ) + ); + + return new VectorQuerySnapshot( + firestore, + userDataWriter, + vectorQuery, + docs + ); + } + ); + } } /** diff --git a/packages/firestore/src/api/snapshot.ts b/packages/firestore/src/api/snapshot.ts index 29e1616b61c..c39bc29c147 100644 --- a/packages/firestore/src/api/snapshot.ts +++ b/packages/firestore/src/api/snapshot.ts @@ -28,10 +28,12 @@ import { } from '../lite-api/reference'; import { DocumentSnapshot as LiteDocumentSnapshot, - fieldPathFromArgument, FirestoreDataConverter as LiteFirestoreDataConverter } from '../lite-api/snapshot'; -import { UntypedFirestoreDataConverter } from '../lite-api/user_data_reader'; +import { + fieldPathFromArgument, + UntypedFirestoreDataConverter +} from '../lite-api/user_data_reader'; import { AbstractUserDataWriter } from '../lite-api/user_data_writer'; import { Document } from '../model/document'; import { DocumentKey } from '../model/document_key'; diff --git a/packages/firestore/src/api/vector_query.ts b/packages/firestore/src/api/vector_query.ts new file mode 100644 index 00000000000..a7740aba6a8 --- /dev/null +++ b/packages/firestore/src/api/vector_query.ts @@ -0,0 +1,18 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { VectorQuery } from '../lite-api/vector_query'; diff --git a/packages/firestore/src/api/vector_query_options.ts b/packages/firestore/src/api/vector_query_options.ts new file mode 100644 index 00000000000..486018d5f66 --- /dev/null +++ b/packages/firestore/src/api/vector_query_options.ts @@ -0,0 +1,18 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { VectorQueryOptions } from '../lite-api/vector_query_options'; diff --git a/packages/firestore/src/api/vector_query_snapshot.ts b/packages/firestore/src/api/vector_query_snapshot.ts new file mode 100644 index 00000000000..417c4f9be16 --- /dev/null +++ b/packages/firestore/src/api/vector_query_snapshot.ts @@ -0,0 +1,95 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DocumentData } from '../lite-api/reference'; +import { AbstractUserDataWriter } from '../lite-api/user_data_writer'; +import { VectorQuery } from '../lite-api/vector_query'; + +import { Firestore } from './database'; +import { QueryDocumentSnapshot, SnapshotMetadata } from './snapshot'; + +/** + * A `VectorQuerySnapshot` contains zero or more `DocumentSnapshot` objects + * representing the results of a vector query. The documents can be accessed as an + * array via the `docs` property or enumerated using the `forEach` method. The + * number of documents can be determined via the `empty` and `size` + * properties. + */ +export class VectorQuerySnapshot< + AppModelType = DocumentData, + DbModelType extends DocumentData = DocumentData +> { + /** + * Metadata about this snapshot, concerning its source and if it has local + * modifications. + */ + readonly metadata: SnapshotMetadata; + + /** + * The VectorQuery on which you called `get` or `onSnapshot` in order to get this + * `QuerySnapshot`. + */ + readonly query: VectorQuery; + + /** @hideconstructor */ + constructor( + readonly _firestore: Firestore, + readonly _userDataWriter: AbstractUserDataWriter, + query: VectorQuery, + readonly _docs: Array> + ) { + this.metadata = new SnapshotMetadata(false, false); + this.query = query; + } + + /** An array of all the documents in the `QuerySnapshot`. */ + get docs(): Array> { + const result: Array> = []; + this.forEach(doc => result.push(doc)); + return result; + } + + /** The number of documents in the `QuerySnapshot`. */ + get size(): number { + return this._docs.length; + } + + /** True if there are no documents in the `QuerySnapshot`. */ + get empty(): boolean { + return this.size === 0; + } + + /** + * Enumerates all of the documents in the `QuerySnapshot`. + * + * @param callback - A callback to be called with a `QueryDocumentSnapshot` for + * each document in the snapshot. + * @param thisArg - The `this` binding for the callback. + */ + forEach( + callback: ( + result: QueryDocumentSnapshot + ) => void, + thisArg?: unknown + ): void { + this._docs.forEach(doc => { + callback.call(thisArg, doc); + }); + } + + // TODO remove docChanges from the API design +} diff --git a/packages/firestore/src/api/vector_value.ts b/packages/firestore/src/api/vector_value.ts new file mode 100644 index 00000000000..522fa11964e --- /dev/null +++ b/packages/firestore/src/api/vector_value.ts @@ -0,0 +1,18 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { VectorValue } from '../lite-api/vector_value'; diff --git a/packages/firestore/src/core/firestore_client.ts b/packages/firestore/src/core/firestore_client.ts index 6e21737380b..5d0baec2dd7 100644 --- a/packages/firestore/src/core/firestore_client.ts +++ b/packages/firestore/src/core/firestore_client.ts @@ -42,7 +42,11 @@ import { toByteStreamReader } from '../platform/byte_stream_reader'; import { newSerializer } from '../platform/serializer'; import { newTextEncoder } from '../platform/text_serializer'; import { ApiClientObjectMap, Value } from '../protos/firestore_proto_api'; -import { Datastore, invokeRunAggregationQueryRpc } from '../remote/datastore'; +import { + Datastore, + invokeRunAggregationQueryRpc, + invokeRunQueryRpcForVectorQuery +} from '../remote/datastore'; import { RemoteStore, remoteStoreDisableNetwork, @@ -93,6 +97,7 @@ import { import { Transaction } from './transaction'; import { TransactionOptions } from './transaction_options'; import { TransactionRunner } from './transaction_runner'; +import { VectorQuery } from './vector_query'; import { View } from './view'; import { ViewSnapshot } from './view_snapshot'; @@ -557,6 +562,23 @@ export function firestoreClientRunAggregateQuery( return deferred.promise; } +export function firestoreClientRunVectorQuery( + client: FirestoreClient, + vectorQuery: VectorQuery +): Promise { + const deferred = new Deferred(); + + client.asyncQueue.enqueueAndForget(async () => { + try { + const datastore = await getDatastore(client); + deferred.resolve(invokeRunQueryRpcForVectorQuery(datastore, vectorQuery)); + } catch (e) { + deferred.reject(e as Error); + } + }); + return deferred.promise; +} + export function firestoreClientWrite( client: FirestoreClient, mutations: Mutation[] diff --git a/packages/firestore/src/core/query.ts b/packages/firestore/src/core/query.ts index b13296ad7ee..f7d2b1b9eda 100644 --- a/packages/firestore/src/core/query.ts +++ b/packages/firestore/src/core/query.ts @@ -285,9 +285,8 @@ export function queryToTarget(query: Query): Target { /** * Converts this `Query` instance to its corresponding `Target` representation, - * for use within an aggregate query. Unlike targets for non-aggregate queries, - * aggregate query targets do not contain normalized order-bys, they only - * contain explicit order-bys. + * for use within an aggregate or vector query. Unlike targets for standard queries, + * aggregate and vector query targets do not contain normalized order-bys. */ export function queryToAggregateTarget(query: Query): Target { const queryImpl = debugCast(query, QueryImpl); diff --git a/packages/firestore/src/core/vector_query.ts b/packages/firestore/src/core/vector_query.ts new file mode 100644 index 00000000000..1620979ea7d --- /dev/null +++ b/packages/firestore/src/core/vector_query.ts @@ -0,0 +1,77 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ObjectValue } from '../model/object_value'; +import { FieldPath } from '../model/path'; + +import { Query } from './query'; + +/** + * Union type representing the aggregate type to be performed. + */ +export type DistanceMeasure = 'EUCLIDEAN' | 'COSINE' | 'DOT_PRODUCT'; + +/** + * Represents an VectorQuery. + */ +export interface VectorQuery { + readonly query: Query; + vectorField: FieldPath; + queryVector: ObjectValue; + limit: number; + distanceMeasure: DistanceMeasure; + distanceResultField?: FieldPath; + distanceThreshold?: number; +} + +/** + * Concrete implementation of the VectorQuery type. + */ +class VectorQueryImpl implements VectorQuery { + constructor( + readonly query: Query, + readonly vectorField: FieldPath, + readonly queryVector: ObjectValue, + readonly limit: number, + readonly distanceMeasure: DistanceMeasure, + readonly distanceResultField?: FieldPath, + readonly distanceThreshold?: number + ) {} +} + +/** + * Creates a new VectorQuery + */ +export function newVectorQuery( + query: Query, + vectorField: FieldPath, + queryVector: ObjectValue, + limit: number, + distanceMeasure: DistanceMeasure, + distanceResultField?: FieldPath, + distanceThreshold?: number +): VectorQuery { + return new VectorQueryImpl( + query, + vectorField, + queryVector, + limit, + distanceMeasure, + distanceResultField, + distanceThreshold + ); +} diff --git a/packages/firestore/src/lite-api/find_nearest.ts b/packages/firestore/src/lite-api/find_nearest.ts new file mode 100644 index 00000000000..a14aec5e121 --- /dev/null +++ b/packages/firestore/src/lite-api/find_nearest.ts @@ -0,0 +1,67 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + newVectorQuery, + VectorQuery as InternalVectorQuery +} from '../core/vector_query'; +import { ObjectValue } from '../model/object_value'; + +import { Firestore } from './database'; +import { DocumentData, Query } from './reference'; +import { + fieldPathFromArgument, + newUserDataReader, + parseVectorValue, + UserDataSource +} from './user_data_reader'; +import { VectorQuery } from './vector_query'; +import { VectorQueryOptions } from './vector_query_options'; +import { VectorValue } from './vector_value'; + +export function findNearest( + query: Query, + options: VectorQueryOptions +): VectorQuery { + const internalVectorQuery: InternalVectorQuery = newVectorQuery( + query._query, + fieldPathFromArgument('findNearest', options.vectorField), + _parseQueryVector(query.firestore, options.queryVector), + options.limit, + options.distanceMeasure, + options.distanceResultField + ? fieldPathFromArgument('findNearest', options.distanceResultField) + : undefined, + options.distanceThreshold + ); + return new VectorQuery(query, internalVectorQuery); +} + +/** + * Creates a new ObjectValue proto value representing a VectorValue + */ +function _parseQueryVector( + firestore: Firestore, + queryVector: VectorValue | number[] +): ObjectValue { + const parseContext = newUserDataReader(firestore).createContext( + UserDataSource.Argument, + 'findNearest' + ); + const value = parseVectorValue(queryVector, parseContext); + return new ObjectValue(value); +} diff --git a/packages/firestore/src/lite-api/query.ts b/packages/firestore/src/lite-api/query.ts index f0a357b828c..f019f0d0936 100644 --- a/packages/firestore/src/lite-api/query.ts +++ b/packages/firestore/src/lite-api/query.ts @@ -52,8 +52,9 @@ import { import { FieldPath } from './field_path'; import { DocumentData, DocumentReference, Query } from './reference'; -import { DocumentSnapshot, fieldPathFromArgument } from './snapshot'; +import { DocumentSnapshot } from './snapshot'; import { + fieldPathFromArgument, newUserDataReader, parseQueryValue, UserDataReader diff --git a/packages/firestore/src/lite-api/reference.ts b/packages/firestore/src/lite-api/reference.ts index 26ae2fbd433..031a34c0ab3 100644 --- a/packages/firestore/src/lite-api/reference.ts +++ b/packages/firestore/src/lite-api/reference.ts @@ -39,6 +39,7 @@ import { FieldPath } from './field_path'; import { FieldValue } from './field_value'; import { FirestoreDataConverter } from './snapshot'; import { NestedUpdateFields, Primitive } from './types'; +import { VectorQuery } from './vector_query'; /** * Document data (for use with {@link @firebase/firestore/lite#(setDoc:1)}) consists of fields mapped to @@ -640,8 +641,12 @@ export function refEqual( * Firestore database. */ export function queryEqual( - left: Query, - right: Query + left: + | Query + | VectorQuery, + right: + | Query + | VectorQuery ): boolean { left = getModularInstance(left); right = getModularInstance(right); @@ -652,6 +657,9 @@ export function queryEqual( queryEquals(left._query, right._query) && left.converter === right.converter ); + } else if (left instanceof VectorQuery && right instanceof VectorQuery) { + return queryEqual(left.query, right.query); + // TODO test for equality of other properties } return false; } diff --git a/packages/firestore/src/lite-api/reference_impl.ts b/packages/firestore/src/lite-api/reference_impl.ts index 6876ed0a877..572d5b952f3 100644 --- a/packages/firestore/src/lite-api/reference_impl.ts +++ b/packages/firestore/src/lite-api/reference_impl.ts @@ -26,7 +26,8 @@ import { DeleteMutation, Precondition } from '../model/mutation'; import { invokeBatchGetDocumentsRpc, invokeCommitRpc, - invokeRunQueryRpc + invokeRunQueryRpc, + invokeRunQueryRpcForVectorQuery } from '../remote/datastore'; import { hardAssert } from '../util/assert'; import { ByteString } from '../util/byte_string'; @@ -62,6 +63,8 @@ import { UntypedFirestoreDataConverter } from './user_data_reader'; import { AbstractUserDataWriter } from './user_data_writer'; +import { VectorQuery } from './vector_query'; +import { VectorQuerySnapshot } from './vector_query_snapshot'; /** * Converts custom model object of type T into `DocumentData` by applying the @@ -158,35 +161,85 @@ export function getDoc( * @param query - The `Query` to execute. * @returns A Promise that will be resolved with the results of the query. */ +export function getDocs( + query: VectorQuery +): Promise>; + export function getDocs( query: Query -): Promise> { - query = cast>(query, Query); - validateHasExplicitOrderByForLimitToLast(query._query); +): Promise>; - const datastore = getDatastore(query.firestore); - const userDataWriter = new LiteUserDataWriter(query.firestore); - return invokeRunQueryRpc(datastore, query._query).then(result => { - const docs = result.map( - doc => - new QueryDocumentSnapshot( - query.firestore, - userDataWriter, - doc.key, - doc, - query.converter - ) - ); +export function getDocs( + queryOrVectorQuery: + | Query + | VectorQuery +): Promise< + | QuerySnapshot + | VectorQuerySnapshot +> { + // If the query is a Query instance + if ( + 'type' in queryOrVectorQuery && + (queryOrVectorQuery.type! === 'query' || + queryOrVectorQuery.type! === 'collection') + ) { + const query: Query = cast< + Query + >(queryOrVectorQuery, Query); + validateHasExplicitOrderByForLimitToLast(query._query); - if (query._query.limitType === LimitType.Last) { - // Limit to last queries reverse the orderBy constraint that was - // specified by the user. As such, we need to reverse the order of the - // results to return the documents in the expected order. - docs.reverse(); - } + const datastore = getDatastore(query.firestore); + const userDataWriter = new LiteUserDataWriter(query.firestore); + return invokeRunQueryRpc(datastore, query._query).then(result => { + const docs = result.map( + doc => + new QueryDocumentSnapshot( + query.firestore, + userDataWriter, + doc.key, + doc, + query.converter + ) + ); - return new QuerySnapshot(query, docs); - }); + if (query._query.limitType === LimitType.Last) { + // Limit to last queries reverse the orderBy constraint that was + // specified by the user. As such, we need to reverse the order of the + // results to return the documents in the expected order. + docs.reverse(); + } + + return new QuerySnapshot(query, docs); + }); + } else { + // the query is a VectorQuery instance + const vectorQuery: VectorQuery = cast< + VectorQuery + >(queryOrVectorQuery, VectorQuery); + + const datastore = getDatastore(vectorQuery.query.firestore); + const userDataWriter = new LiteUserDataWriter(vectorQuery.query.firestore); + return invokeRunQueryRpcForVectorQuery( + datastore, + vectorQuery._vectorQuery + ).then(result => { + const docs = result.map( + doc => + new QueryDocumentSnapshot( + vectorQuery.query.firestore, + userDataWriter, + doc.key, + doc, + vectorQuery.query.converter + ) + ); + + return new VectorQuerySnapshot( + vectorQuery, + docs + ); + }); + } } /** diff --git a/packages/firestore/src/lite-api/snapshot.ts b/packages/firestore/src/lite-api/snapshot.ts index 3024e2e9db0..d497719792f 100644 --- a/packages/firestore/src/lite-api/snapshot.ts +++ b/packages/firestore/src/lite-api/snapshot.ts @@ -15,11 +15,10 @@ * limitations under the License. */ -import { Compat, getModularInstance } from '@firebase/util'; +import { getModularInstance } from '@firebase/util'; import { Document } from '../model/document'; import { DocumentKey } from '../model/document_key'; -import { FieldPath as InternalFieldPath } from '../model/path'; import { arrayEquals } from '../util/misc'; import { Firestore } from './database'; @@ -34,10 +33,11 @@ import { WithFieldValue } from './reference'; import { - fieldPathFromDotSeparatedString, + fieldPathFromArgument, UntypedFirestoreDataConverter } from './user_data_reader'; import { AbstractUserDataWriter } from './user_data_writer'; +import { VectorQuerySnapshot } from './vector_query_snapshot'; /** * Converter used by `withConverter()` to transform user objects of type @@ -483,10 +483,12 @@ export class QuerySnapshot< export function snapshotEqual( left: | DocumentSnapshot - | QuerySnapshot, + | QuerySnapshot + | VectorQuerySnapshot, right: | DocumentSnapshot | QuerySnapshot + | VectorQuerySnapshot ): boolean { left = getModularInstance(left); right = getModularInstance(right); @@ -505,23 +507,15 @@ export function snapshotEqual( queryEqual(left.query, right.query) && arrayEquals(left.docs, right.docs, snapshotEqual) ); + } else if ( + left instanceof VectorQuerySnapshot && + right instanceof VectorQuerySnapshot + ) { + return ( + queryEqual(left.query, right.query) && + arrayEquals(left.docs, right.docs, snapshotEqual) + ); } return false; } - -/** - * Helper that calls `fromDotSeparatedString()` but wraps any error thrown. - */ -export function fieldPathFromArgument( - methodName: string, - arg: string | FieldPath | Compat -): InternalFieldPath { - if (typeof arg === 'string') { - return fieldPathFromDotSeparatedString(methodName, arg); - } else if (arg instanceof FieldPath) { - return arg._internalPath; - } else { - return arg._delegate._internalPath; - } -} diff --git a/packages/firestore/src/lite-api/user_data_reader.ts b/packages/firestore/src/lite-api/user_data_reader.ts index ebd4b49085f..3f2ebd7ee0f 100644 --- a/packages/firestore/src/lite-api/user_data_reader.ts +++ b/packages/firestore/src/lite-api/user_data_reader.ts @@ -920,9 +920,10 @@ function parseScalarValue( * Creates a new VectorValue proto value (using the internal format). */ export function parseVectorValue( - value: VectorValue, + value: VectorValue | number[], context: ParseContextImpl -): ProtoValue { +): { mapValue: ProtoMapValue } { + const values = value instanceof VectorValue ? value.toArray() : value; const mapValue: ProtoMapValue = { fields: { [TYPE_KEY]: { @@ -930,7 +931,7 @@ export function parseVectorValue( }, [VECTOR_MAP_VECTORS_KEY]: { arrayValue: { - values: value.toArray().map(value => { + values: values.map(value => { if (typeof value !== 'number') { throw context.createError( 'VectorValues must only contain numeric values.' @@ -1001,8 +1002,11 @@ export function fieldPathFromArgument( return path._internalPath; } else if (typeof path === 'string') { return fieldPathFromDotSeparatedString(methodName, path); + } else if (isCompatFieldPath(path)) { + return path._delegate._internalPath; } else { - const message = 'Field path arguments must be of type string or '; + const message = + 'Field path arguments must be of type string, FieldPath, or Compat'; throw createError( message, methodName, @@ -1013,6 +1017,19 @@ export function fieldPathFromArgument( } } +/** + * Type guard to identify Compat. + */ +function isCompatFieldPath( + path: PublicFieldPath | Compat +): path is Compat { + if (!('_delegate' in path)) { + return false; + } + + return path._delegate instanceof FieldPath; +} + /** * Matches any characters in a field path string that are reserved. */ diff --git a/packages/firestore/src/lite-api/vector_query.ts b/packages/firestore/src/lite-api/vector_query.ts new file mode 100644 index 00000000000..1ed99b6a54c --- /dev/null +++ b/packages/firestore/src/lite-api/vector_query.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { VectorQuery as InternalVectorQuery } from '../core/vector_query'; + +import { DocumentData, Query } from './reference'; + +export class VectorQuery< + AppModelType = DocumentData, + DbModelType extends DocumentData = DocumentData +> { + /** @hideconstructor protected */ + constructor( + private readonly _query: Query, + readonly _vectorQuery: InternalVectorQuery + ) {} + + /** The query whose results participants in the vector search. Filtering + * performed by the query will apply before the vector search. + */ + get query(): Query { + return this._query; + } +} diff --git a/packages/firestore/src/lite-api/vector_query_options.ts b/packages/firestore/src/lite-api/vector_query_options.ts new file mode 100644 index 00000000000..1cac11ed319 --- /dev/null +++ b/packages/firestore/src/lite-api/vector_query_options.ts @@ -0,0 +1,28 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FieldPath } from './field_path'; +import { VectorValue } from './vector_value'; + +export interface VectorQueryOptions { + vectorField: string | FieldPath; + queryVector: VectorValue | number[]; + limit: number; + distanceMeasure: 'EUCLIDEAN' | 'COSINE' | 'DOT_PRODUCT'; + distanceResultField?: string | FieldPath; + distanceThreshold?: number; +} diff --git a/packages/firestore/src/lite-api/vector_query_snapshot.ts b/packages/firestore/src/lite-api/vector_query_snapshot.ts new file mode 100644 index 00000000000..52a2584373b --- /dev/null +++ b/packages/firestore/src/lite-api/vector_query_snapshot.ts @@ -0,0 +1,53 @@ +import { DocumentData } from './reference'; +import { QueryDocumentSnapshot } from './snapshot'; +import { VectorQuery } from './vector_query'; + +export class VectorQuerySnapshot< + AppModelType = DocumentData, + DbModelType extends DocumentData = DocumentData +> { + /** + * The query on which you called {@link getDocs} in order to get this + * `VectorQuerySnapshot`. + */ + readonly query: VectorQuery; + + /** @hideconstructor */ + constructor( + _query: VectorQuery, + readonly _docs: Array> + ) { + this.query = _query; + } + + /** An array of all the documents in the `VectorQuerySnapshot`. */ + get docs(): Array> { + return [...this._docs]; + } + + /** The number of documents in the `VectorQuerySnapshot`. */ + get size(): number { + return this.docs.length; + } + + /** True if there are no documents in the `VectorQuerySnapshot`. */ + get empty(): boolean { + return this.docs.length === 0; + } + + /** + * Enumerates all of the documents in the `VectorQuerySnapshot`. + * + * @param callback - A callback to be called with a `QueryDocumentSnapshot` for + * each document in the snapshot. + * @param thisArg - The `this` binding for the callback. + */ + forEach( + callback: ( + result: QueryDocumentSnapshot + ) => void, + thisArg?: unknown + ): void { + this._docs.forEach(callback, thisArg); + } +} diff --git a/packages/firestore/src/protos/README.md b/packages/firestore/src/protos/README.md index 24919e59b63..0671da3aaec 100644 --- a/packages/firestore/src/protos/README.md +++ b/packages/firestore/src/protos/README.md @@ -1,2 +1,2 @@ These protos are copied from https://github.com/googleapis/googleapis and -https://github.com/google/protobuf. Run update.sh to update them. +https://github.com/google/protobuf. Run `./update.sh` to update them. diff --git a/packages/firestore/src/protos/compile.sh b/packages/firestore/src/protos/compile.sh index 26c46d1a40d..426da9e4fb8 100755 --- a/packages/firestore/src/protos/compile.sh +++ b/packages/firestore/src/protos/compile.sh @@ -18,10 +18,9 @@ set -euo pipefail # Variables PROTOS_DIR="." -PBJS="$(npm bin)/pbjs" +PBJS="../../node_modules/.bin/pbjs" -"${PBJS}" --proto_path=. --target=json -o protos.json \ - -r firestore_v1 \ - "${PROTOS_DIR}/google/firestore/v1/*.proto" \ +"${PBJS}" --path=. --target=json -o protos.json \ + -r firestore/v1 "${PROTOS_DIR}/google/firestore/v1/*.proto" \ "${PROTOS_DIR}/google/protobuf/*.proto" "${PROTOS_DIR}/google/type/*.proto" \ "${PROTOS_DIR}/google/rpc/*.proto" "${PROTOS_DIR}/google/api/*.proto" diff --git a/packages/firestore/src/protos/firestore_proto_api.ts b/packages/firestore/src/protos/firestore_proto_api.ts index 9618d71b86a..ba8cd051b2f 100644 --- a/packages/firestore/src/protos/firestore_proto_api.ts +++ b/packages/firestore/src/protos/firestore_proto_api.ts @@ -144,6 +144,19 @@ export interface IValueNullValueEnum { values(): ValueNullValue[]; } export declare const ValueNullValueEnum: IValueNullValueEnum; +export declare type DistanceMeasure = + | 'DISTANCE_MEASURE_UNSPECIFIED' + | 'EUCLIDEAN' + | 'COSINE' + | 'DOT_PRODUCT'; +export interface IDistanceMeasureEnum { + DISTANCE_MEASURE_UNSPECIFIED: DistanceMeasure; + EUCLIDEAN: DistanceMeasure; + COSINE: DistanceMeasure; + DOT_PRODUCT: DistanceMeasure; + values(): DistanceMeasure[]; +} +export declare const DistanceMeasureEnum: IDistanceMeasureEnum; export declare namespace firestoreV1ApiClientInterfaces { interface ArrayValue { values?: Value[]; @@ -391,6 +404,15 @@ export declare namespace firestoreV1ApiClientInterfaces { endAt?: Cursor; offset?: number; limit?: number | { value: number }; + findNearest?: FindNearest; + } + interface FindNearest { + vectorField?: FieldReference; + queryVector?: Value; + distanceMeasure?: DistanceMeasure; + limit?: number | { value: number }; + distanceResultField?: string; + distanceThreshold?: number | { value: number }; } interface Target { query?: QueryTarget; @@ -495,6 +517,7 @@ export declare type FieldReference = export declare type FieldTransform = firestoreV1ApiClientInterfaces.FieldTransform; export declare type Filter = firestoreV1ApiClientInterfaces.Filter; +export declare type FindNearest = firestoreV1ApiClientInterfaces.FindNearest; export declare type Index = firestoreV1ApiClientInterfaces.Index; export declare type IndexField = firestoreV1ApiClientInterfaces.IndexField; export declare type LatLng = firestoreV1ApiClientInterfaces.LatLng; diff --git a/packages/firestore/src/protos/google/api/annotations.proto b/packages/firestore/src/protos/google/api/annotations.proto index efdab3db6ca..84c48164aa9 100644 --- a/packages/firestore/src/protos/google/api/annotations.proto +++ b/packages/firestore/src/protos/google/api/annotations.proto @@ -1,4 +1,4 @@ -// Copyright 2015 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. diff --git a/packages/firestore/src/protos/google/api/client.proto b/packages/firestore/src/protos/google/api/client.proto index 3b3fd0c401f..211575880c1 100644 --- a/packages/firestore/src/protos/google/api/client.proto +++ b/packages/firestore/src/protos/google/api/client.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. @@ -16,7 +16,9 @@ syntax = "proto3"; package google.api; +import "google/api/launch_stage.proto"; import "google/protobuf/descriptor.proto"; +import "google/protobuf/duration.proto"; option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; option java_multiple_files = true; @@ -96,4 +98,348 @@ extend google.protobuf.ServiceOptions { // ... // } string oauth_scopes = 1050; + + // The API version of this service, which should be sent by version-aware + // clients to the service. This allows services to abide by the schema and + // behavior of the service at the time this API version was deployed. + // The format of the API version must be treated as opaque by clients. + // Services may use a format with an apparent structure, but clients must + // not rely on this to determine components within an API version, or attempt + // to construct other valid API versions. Note that this is for upcoming + // functionality and may not be implemented for all services. + // + // Example: + // + // service Foo { + // option (google.api.api_version) = "v1_20230821_preview"; + // } + string api_version = 525000001; +} + +// Required information for every language. +message CommonLanguageSettings { + // Link to automatically generated reference documentation. Example: + // https://cloud.google.com/nodejs/docs/reference/asset/latest + string reference_docs_uri = 1 [deprecated = true]; + + // The destination where API teams want this client library to be published. + repeated ClientLibraryDestination destinations = 2; +} + +// Details about how and where to publish client libraries. +message ClientLibrarySettings { + // Version of the API to apply these settings to. This is the full protobuf + // package for the API, ending in the version element. + // Examples: "google.cloud.speech.v1" and "google.spanner.admin.database.v1". + string version = 1; + + // Launch stage of this version of the API. + LaunchStage launch_stage = 2; + + // When using transport=rest, the client request will encode enums as + // numbers rather than strings. + bool rest_numeric_enums = 3; + + // Settings for legacy Java features, supported in the Service YAML. + JavaSettings java_settings = 21; + + // Settings for C++ client libraries. + CppSettings cpp_settings = 22; + + // Settings for PHP client libraries. + PhpSettings php_settings = 23; + + // Settings for Python client libraries. + PythonSettings python_settings = 24; + + // Settings for Node client libraries. + NodeSettings node_settings = 25; + + // Settings for .NET client libraries. + DotnetSettings dotnet_settings = 26; + + // Settings for Ruby client libraries. + RubySettings ruby_settings = 27; + + // Settings for Go client libraries. + GoSettings go_settings = 28; +} + +// This message configures the settings for publishing [Google Cloud Client +// libraries](https://cloud.google.com/apis/docs/cloud-client-libraries) +// generated from the service config. +message Publishing { + // A list of API method settings, e.g. the behavior for methods that use the + // long-running operation pattern. + repeated MethodSettings method_settings = 2; + + // Link to a *public* URI where users can report issues. Example: + // https://issuetracker.google.com/issues/new?component=190865&template=1161103 + string new_issue_uri = 101; + + // Link to product home page. Example: + // https://cloud.google.com/asset-inventory/docs/overview + string documentation_uri = 102; + + // Used as a tracking tag when collecting data about the APIs developer + // relations artifacts like docs, packages delivered to package managers, + // etc. Example: "speech". + string api_short_name = 103; + + // GitHub label to apply to issues and pull requests opened for this API. + string github_label = 104; + + // GitHub teams to be added to CODEOWNERS in the directory in GitHub + // containing source code for the client libraries for this API. + repeated string codeowner_github_teams = 105; + + // A prefix used in sample code when demarking regions to be included in + // documentation. + string doc_tag_prefix = 106; + + // For whom the client library is being published. + ClientLibraryOrganization organization = 107; + + // Client library settings. If the same version string appears multiple + // times in this list, then the last one wins. Settings from earlier + // settings with the same version string are discarded. + repeated ClientLibrarySettings library_settings = 109; + + // Optional link to proto reference documentation. Example: + // https://cloud.google.com/pubsub/lite/docs/reference/rpc + string proto_reference_documentation_uri = 110; + + // Optional link to REST reference documentation. Example: + // https://cloud.google.com/pubsub/lite/docs/reference/rest + string rest_reference_documentation_uri = 111; +} + +// Settings for Java client libraries. +message JavaSettings { + // The package name to use in Java. Clobbers the java_package option + // set in the protobuf. This should be used **only** by APIs + // who have already set the language_settings.java.package_name" field + // in gapic.yaml. API teams should use the protobuf java_package option + // where possible. + // + // Example of a YAML configuration:: + // + // publishing: + // java_settings: + // library_package: com.google.cloud.pubsub.v1 + string library_package = 1; + + // Configure the Java class name to use instead of the service's for its + // corresponding generated GAPIC client. Keys are fully-qualified + // service names as they appear in the protobuf (including the full + // the language_settings.java.interface_names" field in gapic.yaml. API + // teams should otherwise use the service name as it appears in the + // protobuf. + // + // Example of a YAML configuration:: + // + // publishing: + // java_settings: + // service_class_names: + // - google.pubsub.v1.Publisher: TopicAdmin + // - google.pubsub.v1.Subscriber: SubscriptionAdmin + map service_class_names = 2; + + // Some settings. + CommonLanguageSettings common = 3; +} + +// Settings for C++ client libraries. +message CppSettings { + // Some settings. + CommonLanguageSettings common = 1; +} + +// Settings for Php client libraries. +message PhpSettings { + // Some settings. + CommonLanguageSettings common = 1; +} + +// Settings for Python client libraries. +message PythonSettings { + // Experimental features to be included during client library generation. + // These fields will be deprecated once the feature graduates and is enabled + // by default. + message ExperimentalFeatures { + // Enables generation of asynchronous REST clients if `rest` transport is + // enabled. By default, asynchronous REST clients will not be generated. + // This feature will be enabled by default 1 month after launching the + // feature in preview packages. + bool rest_async_io_enabled = 1; + } + + // Some settings. + CommonLanguageSettings common = 1; + + // Experimental features to be included during client library generation. + ExperimentalFeatures experimental_features = 2; +} + +// Settings for Node client libraries. +message NodeSettings { + // Some settings. + CommonLanguageSettings common = 1; +} + +// Settings for Dotnet client libraries. +message DotnetSettings { + // Some settings. + CommonLanguageSettings common = 1; + + // Map from original service names to renamed versions. + // This is used when the default generated types + // would cause a naming conflict. (Neither name is + // fully-qualified.) + // Example: Subscriber to SubscriberServiceApi. + map renamed_services = 2; + + // Map from full resource types to the effective short name + // for the resource. This is used when otherwise resource + // named from different services would cause naming collisions. + // Example entry: + // "datalabeling.googleapis.com/Dataset": "DataLabelingDataset" + map renamed_resources = 3; + + // List of full resource types to ignore during generation. + // This is typically used for API-specific Location resources, + // which should be handled by the generator as if they were actually + // the common Location resources. + // Example entry: "documentai.googleapis.com/Location" + repeated string ignored_resources = 4; + + // Namespaces which must be aliased in snippets due to + // a known (but non-generator-predictable) naming collision + repeated string forced_namespace_aliases = 5; + + // Method signatures (in the form "service.method(signature)") + // which are provided separately, so shouldn't be generated. + // Snippets *calling* these methods are still generated, however. + repeated string handwritten_signatures = 6; +} + +// Settings for Ruby client libraries. +message RubySettings { + // Some settings. + CommonLanguageSettings common = 1; +} + +// Settings for Go client libraries. +message GoSettings { + // Some settings. + CommonLanguageSettings common = 1; +} + +// Describes the generator configuration for a method. +message MethodSettings { + // Describes settings to use when generating API methods that use the + // long-running operation pattern. + // All default values below are from those used in the client library + // generators (e.g. + // [Java](https://github.com/googleapis/gapic-generator-java/blob/04c2faa191a9b5a10b92392fe8482279c4404803/src/main/java/com/google/api/generator/gapic/composer/common/RetrySettingsComposer.java)). + message LongRunning { + // Initial delay after which the first poll request will be made. + // Default value: 5 seconds. + google.protobuf.Duration initial_poll_delay = 1; + + // Multiplier to gradually increase delay between subsequent polls until it + // reaches max_poll_delay. + // Default value: 1.5. + float poll_delay_multiplier = 2; + + // Maximum time between two subsequent poll requests. + // Default value: 45 seconds. + google.protobuf.Duration max_poll_delay = 3; + + // Total polling timeout. + // Default value: 5 minutes. + google.protobuf.Duration total_poll_timeout = 4; + } + + // The fully qualified name of the method, for which the options below apply. + // This is used to find the method to apply the options. + // + // Example: + // + // publishing: + // method_settings: + // - selector: google.storage.control.v2.StorageControl.CreateFolder + // # method settings for CreateFolder... + string selector = 1; + + // Describes settings to use for long-running operations when generating + // API methods for RPCs. Complements RPCs that use the annotations in + // google/longrunning/operations.proto. + // + // Example of a YAML configuration:: + // + // publishing: + // method_settings: + // - selector: google.cloud.speech.v2.Speech.BatchRecognize + // long_running: + // initial_poll_delay: 60s # 1 minute + // poll_delay_multiplier: 1.5 + // max_poll_delay: 360s # 6 minutes + // total_poll_timeout: 54000s # 90 minutes + LongRunning long_running = 2; + + // List of top-level fields of the request message, that should be + // automatically populated by the client libraries based on their + // (google.api.field_info).format. Currently supported format: UUID4. + // + // Example of a YAML configuration: + // + // publishing: + // method_settings: + // - selector: google.example.v1.ExampleService.CreateExample + // auto_populated_fields: + // - request_id + repeated string auto_populated_fields = 3; +} + +// The organization for which the client libraries are being published. +// Affects the url where generated docs are published, etc. +enum ClientLibraryOrganization { + // Not useful. + CLIENT_LIBRARY_ORGANIZATION_UNSPECIFIED = 0; + + // Google Cloud Platform Org. + CLOUD = 1; + + // Ads (Advertising) Org. + ADS = 2; + + // Photos Org. + PHOTOS = 3; + + // Street View Org. + STREET_VIEW = 4; + + // Shopping Org. + SHOPPING = 5; + + // Geo Org. + GEO = 6; + + // Generative AI - https://developers.generativeai.google + GENERATIVE_AI = 7; +} + +// To where should client libraries be published? +enum ClientLibraryDestination { + // Client libraries will neither be generated nor published to package + // managers. + CLIENT_LIBRARY_DESTINATION_UNSPECIFIED = 0; + + // Generate the client library in a repo under github.com/googleapis, + // but don't publish it to package managers. + GITHUB = 10; + + // Publish the library to package managers like nuget.org and npmjs.com. + PACKAGE_MANAGER = 20; } diff --git a/packages/firestore/src/protos/google/api/field_behavior.proto b/packages/firestore/src/protos/google/api/field_behavior.proto index c4abe3b670f..2865ba05373 100644 --- a/packages/firestore/src/protos/google/api/field_behavior.proto +++ b/packages/firestore/src/protos/google/api/field_behavior.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. @@ -37,7 +37,7 @@ extend google.protobuf.FieldOptions { // google.protobuf.Timestamp expire_time = 1 // [(google.api.field_behavior) = OUTPUT_ONLY, // (google.api.field_behavior) = IMMUTABLE]; - repeated google.api.FieldBehavior field_behavior = 1052; + repeated google.api.FieldBehavior field_behavior = 1052 [packed = false]; } // An indicator of the behavior of a given field (for example, that a field @@ -87,4 +87,18 @@ enum FieldBehavior { // a non-empty value will be returned. The user will not be aware of what // non-empty value to expect. NON_EMPTY_DEFAULT = 7; + + // Denotes that the field in a resource (a message annotated with + // google.api.resource) is used in the resource name to uniquely identify the + // resource. For AIP-compliant APIs, this should only be applied to the + // `name` field on the resource. + // + // This behavior should not be applied to references to other resources within + // the message. + // + // The identifier field of resources often have different field behavior + // depending on the request it is embedded in (e.g. for Create methods name + // is optional and unused, while for Update methods it is required). Instead + // of method-specific annotations, only `IDENTIFIER` is required. + IDENTIFIER = 8; } diff --git a/packages/firestore/src/protos/google/api/http.proto b/packages/firestore/src/protos/google/api/http.proto index 113fa936a09..e3270371d44 100644 --- a/packages/firestore/src/protos/google/api/http.proto +++ b/packages/firestore/src/protos/google/api/http.proto @@ -1,4 +1,4 @@ -// Copyright 2015 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. @@ -41,7 +41,7 @@ message Http { bool fully_decode_reserved_expansion = 2; } -// # gRPC Transcoding +// gRPC Transcoding // // gRPC Transcoding is a feature for mapping between a gRPC method and one or // more HTTP REST endpoints. It allows developers to build a single API service @@ -82,9 +82,8 @@ message Http { // // This enables an HTTP REST to gRPC mapping as below: // -// HTTP | gRPC -// -----|----- -// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` +// - HTTP: `GET /v1/messages/123456` +// - gRPC: `GetMessage(name: "messages/123456")` // // Any fields in the request message which are not bound by the path template // automatically become HTTP query parameters if there is no HTTP request body. @@ -108,11 +107,9 @@ message Http { // // This enables a HTTP JSON to RPC mapping as below: // -// HTTP | gRPC -// -----|----- -// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | -// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: -// "foo"))` +// - HTTP: `GET /v1/messages/123456?revision=2&sub.subfield=foo` +// - gRPC: `GetMessage(message_id: "123456" revision: 2 sub: +// SubMessage(subfield: "foo"))` // // Note that fields which are mapped to URL query parameters must have a // primitive type or a repeated primitive type or a non-repeated message type. @@ -142,10 +139,8 @@ message Http { // representation of the JSON in the request body is determined by // protos JSON encoding: // -// HTTP | gRPC -// -----|----- -// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: -// "123456" message { text: "Hi!" })` +// - HTTP: `PATCH /v1/messages/123456 { "text": "Hi!" }` +// - gRPC: `UpdateMessage(message_id: "123456" message { text: "Hi!" })` // // The special name `*` can be used in the body mapping to define that // every field not bound by the path template should be mapped to the @@ -168,10 +163,8 @@ message Http { // // The following HTTP JSON to RPC mapping is enabled: // -// HTTP | gRPC -// -----|----- -// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: -// "123456" text: "Hi!")` +// - HTTP: `PATCH /v1/messages/123456 { "text": "Hi!" }` +// - gRPC: `UpdateMessage(message_id: "123456" text: "Hi!")` // // Note that when using `*` in the body mapping, it is not possible to // have HTTP parameters, as all fields not bound by the path end in @@ -199,29 +192,32 @@ message Http { // // This enables the following two alternative HTTP JSON to RPC mappings: // -// HTTP | gRPC -// -----|----- -// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` -// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: -// "123456")` +// - HTTP: `GET /v1/messages/123456` +// - gRPC: `GetMessage(message_id: "123456")` // -// ## Rules for HTTP mapping +// - HTTP: `GET /v1/users/me/messages/123456` +// - gRPC: `GetMessage(user_id: "me" message_id: "123456")` +// +// Rules for HTTP mapping // // 1. Leaf request fields (recursive expansion nested messages in the request // message) are classified into three categories: // - Fields referred by the path template. They are passed via the URL path. -// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP +// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They +// are passed via the HTTP // request body. // - All other fields are passed via the URL query parameters, and the // parameter name is the field path in the request message. A repeated // field can be represented as multiple query parameters under the same // name. -// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields +// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL +// query parameter, all fields // are passed via URL path and HTTP request body. -// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all +// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP +// request body, all // fields are passed via URL path and URL query parameters. // -// ### Path template syntax +// Path template syntax // // Template = "/" Segments [ Verb ] ; // Segments = Segment { "/" Segment } ; @@ -260,7 +256,7 @@ message Http { // Document](https://developers.google.com/discovery/v1/reference/apis) as // `{+var}`. // -// ## Using gRPC API Service Configuration +// Using gRPC API Service Configuration // // gRPC API Service Configuration (service config) is a configuration language // for configuring a gRPC service to become a user-facing product. The @@ -275,15 +271,14 @@ message Http { // specified in the service config will override any matching transcoding // configuration in the proto. // -// Example: +// The following example selects a gRPC method and applies an `HttpRule` to it: // // http: // rules: -// # Selects a gRPC method and applies HttpRule to it. // - selector: example.v1.Messaging.GetMessage // get: /v1/messages/{message_id}/{sub.subfield} // -// ## Special notes +// Special notes // // When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the // proto to JSON conversion must follow the [proto3 @@ -313,7 +308,8 @@ message Http { message HttpRule { // Selects a method to which this rule applies. // - // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + // Refer to [selector][google.api.DocumentationRule.selector] for syntax + // details. string selector = 1; // Determines the URL pattern is matched by this rules. This pattern can be diff --git a/packages/firestore/src/protos/google/firestore/v1/aggregation_result.proto b/packages/firestore/src/protos/google/firestore/v1/aggregation_result.proto index 538e3fef5e4..25e5d2e2e14 100644 --- a/packages/firestore/src/protos/google/firestore/v1/aggregation_result.proto +++ b/packages/firestore/src/protos/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/packages/firestore/src/protos/google/firestore/v1/bloom_filter.proto b/packages/firestore/src/protos/google/firestore/v1/bloom_filter.proto index 6f3b70d4650..1b9eb376f26 100644 --- a/packages/firestore/src/protos/google/firestore/v1/bloom_filter.proto +++ b/packages/firestore/src/protos/google/firestore/v1/bloom_filter.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. @@ -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. diff --git a/packages/firestore/src/protos/google/firestore/v1/common.proto b/packages/firestore/src/protos/google/firestore/v1/common.proto index 3bc978ca9a0..fcb0f49fb00 100644 --- a/packages/firestore/src/protos/google/firestore/v1/common.proto +++ b/packages/firestore/src/protos/google/firestore/v1/common.proto @@ -1,4 +1,4 @@ -// Copyright 2021 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,10 +17,9 @@ syntax = "proto3"; package google.firestore.v1; import "google/protobuf/timestamp.proto"; -import "google/api/annotations.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"; @@ -32,10 +31,12 @@ option ruby_package = "Google::Cloud::Firestore::V1"; // 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; } @@ -48,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; } } @@ -56,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; @@ -67,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/packages/firestore/src/protos/google/firestore/v1/document.proto b/packages/firestore/src/protos/google/firestore/v1/document.proto index 5238a943ce4..52dc85ca9df 100644 --- a/packages/firestore/src/protos/google/firestore/v1/document.proto +++ b/packages/firestore/src/protos/google/firestore/v1/document.proto @@ -1,4 +1,4 @@ -// Copyright 2021 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. @@ -16,13 +16,13 @@ syntax = "proto3"; package google.firestore.v1; +import "google/api/field_behavior.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/timestamp.proto"; import "google/type/latlng.proto"; -import "google/api/annotations.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"; @@ -42,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 ``. @@ -123,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/packages/firestore/src/protos/google/firestore/v1/firestore.proto b/packages/firestore/src/protos/google/firestore/v1/firestore.proto index a8fc0d54b51..2ed6bf070c4 100644 --- a/packages/firestore/src/protos/google/firestore/v1/firestore.proto +++ b/packages/firestore/src/protos/google/firestore/v1/firestore.proto @@ -1,4 +1,4 @@ -// Copyright 2021 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. @@ -23,6 +23,7 @@ import "google/firestore/v1/aggregation_result.proto"; import "google/firestore/v1/common.proto"; import "google/firestore/v1/document.proto"; import "google/firestore/v1/query.proto"; +import "google/firestore/v1/query_profile.proto"; import "google/firestore/v1/write.proto"; import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; @@ -30,11 +31,10 @@ 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"; @@ -46,8 +46,8 @@ option ruby_package = "Google::Cloud::Firestore::V1"; // 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 (GCP) accelerate -// building truly serverless apps. +// 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) = @@ -65,6 +65,9 @@ service Firestore { rpc ListDocuments(ListDocumentsRequest) returns (ListDocumentsResponse) { option (google.api.http) = { get: "/v1/{parent=projects/*/databases/*/documents/*/**}/{collection_id}" + additional_bindings { + get: "/v1/{parent=projects/*/databases/*/documents}/{collection_id}" + } }; } @@ -89,7 +92,8 @@ service Firestore { // // 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: "*" @@ -97,7 +101,8 @@ 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: "*" @@ -137,8 +142,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: @@ -147,7 +153,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: "*" @@ -157,7 +164,7 @@ service Firestore { } }; } - + // 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. @@ -172,7 +179,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" @@ -180,7 +188,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" @@ -189,7 +198,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: "*" @@ -206,7 +216,8 @@ service Firestore { // 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. + // [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. @@ -226,7 +237,8 @@ service Firestore { } } -// The request for [Firestore.GetDocument][google.firestore.v1.Firestore.GetDocument]. +// The request for +// [Firestore.GetDocument][google.firestore.v1.Firestore.GetDocument]. message GetDocumentRequest { // Required. The resource name of the Document to get. In the format: // `projects/{project_id}/databases/{database_id}/documents/{document_path}`. @@ -245,78 +257,109 @@ message GetDocumentRequest { bytes transaction = 3; // Reads the version of the document at the given time. - // This may not be older than 270 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 { // 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 [(google.api.field_behavior) = REQUIRED]; - // Required. The collection ID, relative to `parent`, to list. For example: `chatrooms` - // or `messages`. - string collection_id = 2 [(google.api.field_behavior) = REQUIRED]; + // 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 270 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. // - // Requests with `show_missing` may not specify `where` or - // `order_by`. + // 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`. 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 { // 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 [(google.api.field_behavior) = REQUIRED]; - // Required. The collection ID, relative to `parent`, to list. For example: `chatrooms`. + // 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. @@ -334,7 +377,8 @@ 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 { // Required. The updated document. // Creates the document if it does not already exist. @@ -360,7 +404,8 @@ 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 { // Required. The resource name of the Document to delete. In the format: // `projects/{project_id}/databases/{database_id}/documents/{document_path}`. @@ -371,7 +416,8 @@ message DeleteDocumentRequest { 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 { // Required. The database name. In the format: // `projects/{project_id}/databases/{database_id}`. @@ -402,12 +448,16 @@ message BatchGetDocumentsRequest { TransactionOptions new_transaction = 5; // Reads documents as they were at the given time. - // This may not be older than 270 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. @@ -422,17 +472,19 @@ 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. - // This may be monotonically increasing, in this case the previous documents in + // This may be monotically increasing, in this case the previous documents in // the result stream are guaranteed not to have changed between their // read_time and this one. 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 { // Required. The database name. In the format: // `projects/{project_id}/databases/{database_id}`. @@ -443,7 +495,8 @@ message BeginTransactionRequest { 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; @@ -506,7 +559,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. @@ -516,21 +571,29 @@ message RunQueryRequest { TransactionOptions new_transaction = 6; // Reads documents as they were at the given time. - // This may not be older than 270 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; } + + // Optional. Explain options for the query. If set, additional query + // statistics will be returned. If not, only query results will be returned. + ExplainOptions explain_options = 10 [(google.api.field_behavior) = OPTIONAL]; } -// 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 @@ -545,9 +608,24 @@ message RunQueryResponse { // The number of results that have been skipped due to an offset between // the last response and the current response. int32 skipped_results = 4; + + // The continuation mode for the query. If present, it indicates the current + // query response stream has finished. This can be set with or without a + // `document` present, but when set, no more results are returned. + oneof continuation_selector { + // If present, Firestore has completely finished the request and no more + // documents will be returned. + bool done = 6; + } + + // Query explain metrics. This is only present when the + // [RunQueryRequest.explain_options][google.firestore.v1.RunQueryRequest.explain_options] + // is provided, and it is sent only once with the last response in the stream. + ExplainMetrics explain_metrics = 11; } -// The request for [Firestore.RunAggregationQuery][google.firestore.v1.Firestore.RunAggregationQuery]. +// The request for +// [Firestore.RunAggregationQuery][google.firestore.v1.Firestore.RunAggregationQuery]. message RunAggregationQueryRequest { // Required. The parent resource name. In the format: // `projects/{project_id}/databases/{database_id}/documents` or @@ -578,19 +656,23 @@ 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; } + + // Optional. Explain options for the query. If set, additional query + // statistics will be returned. If not, only query results will be returned. + ExplainOptions explain_options = 8 [(google.api.field_behavior) = OPTIONAL]; } -// 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. @@ -599,11 +681,24 @@ 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; + + // Query explain metrics. This is only present when the + // [RunAggregationQueryRequest.explain_options][google.firestore.v1.RunAggregationQueryRequest.explain_options] + // is provided, and it is sent only once with the last response in the stream. + ExplainMetrics explain_metrics = 10; } -// The request for [Firestore.PartitionQuery][google.firestore.v1.Firestore.PartitionQuery]. +// The request for +// [Firestore.PartitionQuery][google.firestore.v1.Firestore.PartitionQuery]. message PartitionQueryRequest { // Required. The parent resource name. In the format: // `projects/{project_id}/databases/{database_id}/documents`. @@ -653,9 +748,21 @@ message PartitionQueryRequest { // if more results exist. A second call to PartitionQuery will return up to // 2 partitions, to complete the total of 10 specified in `partition_count`. int32 page_size = 5; + + // The consistency mode for this request. + // If not set, defaults to strong consistency. + oneof consistency_selector { + // Reads documents as they were at the given 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 = 6; + } } -// The response for [Firestore.PartitionQuery][google.firestore.v1.Firestore.PartitionQuery]. +// The response for +// [Firestore.PartitionQuery][google.firestore.v1.Firestore.PartitionQuery]. message PartitionQueryResponse { // Partition results. // Each partition is a split point that can be used by RunQuery as a starting @@ -673,7 +780,7 @@ message PartitionQueryResponse { // * query, start_at B // // An empty result may indicate that the query has too few results to be - // partitioned. + // partitioned, or that the query is not yet supported for partitioning. repeated Cursor partitions = 1; // A page token that may be used to request an additional set of results, up @@ -714,9 +821,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. @@ -786,8 +893,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 @@ -838,10 +945,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; @@ -854,6 +963,21 @@ message Target { // The target ID that identifies the target on the stream. Must be a positive // number and non-zero. + // + // 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. + // + // 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. @@ -865,7 +989,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; } @@ -932,7 +1055,8 @@ 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 { // Required. The parent document. In the format: // `projects/{project_id}/databases/{database_id}/documents/{document_path}`. @@ -946,9 +1070,21 @@ message ListCollectionIdsRequest { // A page token. Must be a value from // [ListCollectionIdsResponse][google.firestore.v1.ListCollectionIdsResponse]. string page_token = 3; + + // The consistency mode for this request. + // If not set, defaults to strong consistency. + oneof consistency_selector { + // Reads documents as they were at the given 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 = 4; + } } -// 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; @@ -957,7 +1093,8 @@ message ListCollectionIdsResponse { string next_page_token = 2; } -// The request for [Firestore.BatchWrite][google.firestore.v1.Firestore.BatchWrite]. +// The request for +// [Firestore.BatchWrite][google.firestore.v1.Firestore.BatchWrite]. message BatchWriteRequest { // Required. The database name. In the format: // `projects/{project_id}/databases/{database_id}`. @@ -974,7 +1111,8 @@ message BatchWriteRequest { map labels = 3; } -// The response from [Firestore.BatchWrite][google.firestore.v1.Firestore.BatchWrite]. +// The response from +// [Firestore.BatchWrite][google.firestore.v1.Firestore.BatchWrite]. message BatchWriteResponse { // The result of applying the writes. // diff --git a/packages/firestore/src/protos/google/firestore/v1/query.proto b/packages/firestore/src/protos/google/firestore/v1/query.proto index 9ce102e6901..3b2280076ef 100644 --- a/packages/firestore/src/protos/google/firestore/v1/query.proto +++ b/packages/firestore/src/protos/google/firestore/v1/query.proto @@ -1,4 +1,4 @@ -// Copyright 2021 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. @@ -16,12 +16,12 @@ syntax = "proto3"; package google.firestore.v1; +import "google/api/field_behavior.proto"; import "google/firestore/v1/document.proto"; import "google/protobuf/wrappers.proto"; -import "google/api/annotations.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"; @@ -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 { @@ -76,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; } @@ -133,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 @@ -142,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. @@ -151,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; @@ -216,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; } @@ -230,19 +263,78 @@ message StructuredQuery { repeated FieldReference fields = 2; } - // A sort direction. - enum Direction { - // Unspecified. - DIRECTION_UNSPECIFIED = 0; - - // Ascending. - ASCENDING = 1; + // Nearest Neighbors search config. The ordering provided by FindNearest + // supersedes the order_by stage. If multiple documents have the same vector + // distance, the returned document order is not guaranteed to be stable + // between queries. + message FindNearest { + // The distance measure to use when comparing vectors. + enum DistanceMeasure { + // Should not be set. + DISTANCE_MEASURE_UNSPECIFIED = 0; + + // Measures the EUCLIDEAN distance between the vectors. See + // [Euclidean](https://en.wikipedia.org/wiki/Euclidean_distance) to learn + // more. The resulting distance decreases the more similar two vectors + // are. + EUCLIDEAN = 1; + + // COSINE distance compares vectors based on the angle between them, which + // allows you to measure similarity that isn't based on the vectors + // magnitude. We recommend using DOT_PRODUCT with unit normalized vectors + // instead of COSINE distance, which is mathematically equivalent with + // better performance. See [Cosine + // Similarity](https://en.wikipedia.org/wiki/Cosine_similarity) to learn + // more about COSINE similarity and COSINE distance. The resulting + // COSINE distance decreases the more similar two vectors are. + COSINE = 2; + + // Similar to cosine but is affected by the magnitude of the vectors. See + // [Dot Product](https://en.wikipedia.org/wiki/Dot_product) to learn more. + // The resulting distance increases the more similar two vectors are. + DOT_PRODUCT = 3; + } - // Descending. - DESCENDING = 2; + // Required. An indexed vector field to search upon. Only documents which + // contain vectors whose dimensionality match the query_vector can be + // returned. + FieldReference vector_field = 1 [(google.api.field_behavior) = REQUIRED]; + + // Required. The query vector that we are searching on. Must be a vector of + // no more than 2048 dimensions. + Value query_vector = 2 [(google.api.field_behavior) = REQUIRED]; + + // Required. The distance measure to use, required. + DistanceMeasure distance_measure = 3 + [(google.api.field_behavior) = REQUIRED]; + + // Required. The number of nearest neighbors to return. Must be a positive + // integer of no more than 1000. + google.protobuf.Int32Value limit = 4 + [(google.api.field_behavior) = REQUIRED]; + + // Optional. Optional name of the field to output the result of the vector + // distance calculation. Must conform to [document field + // name][google.firestore.v1.Document.fields] limitations. + string distance_result_field = 5 [(google.api.field_behavior) = OPTIONAL]; + + // Optional. Option to specify a threshold for which no less similar + // documents will be returned. The behavior of the specified + // `distance_measure` will affect the meaning of the distance threshold. + // Since DOT_PRODUCT distances increase when the vectors are more similar, + // the comparison is inverted. + // + // For EUCLIDEAN, COSINE: WHERE distance <= distance_threshold + // For DOT_PRODUCT: WHERE distance >= distance_threshold + google.protobuf.DoubleValue distance_threshold = 6 + [(google.api.field_behavior) = OPTIONAL]; } - // 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. @@ -253,66 +345,126 @@ 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. // - // Applies before limit, but after all other constraints. Must be >= 0 if - // specified. + // This applies after the constraints specified by the `WHERE`, `START AT`, & + // `END AT` but before the `LIMIT` clause. + // + // 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; + + // Optional. A potential nearest neighbors search. + // + // Applies after all other filters and ordering. + // + // Finds the closest vector embeddings to the given query vector. + FindNearest find_nearest = 9 [(google.api.field_behavior) = OPTIONAL]; } +// 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. @@ -320,12 +472,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; @@ -336,7 +498,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`. // @@ -358,14 +521,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. @@ -374,8 +565,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/packages/firestore/src/protos/google/firestore/v1/write.proto b/packages/firestore/src/protos/google/firestore/v1/write.proto index d8465955b67..f74b32e2782 100644 --- a/packages/firestore/src/protos/google/firestore/v1/write.proto +++ b/packages/firestore/src/protos/google/firestore/v1/write.proto @@ -1,4 +1,4 @@ -// Copyright 2021 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. @@ -20,10 +20,9 @@ import "google/firestore/v1/bloom_filter.proto"; import "google/firestore/v1/common.proto"; import "google/firestore/v1/document.proto"; import "google/protobuf/timestamp.proto"; -import "google/api/annotations.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"; @@ -91,8 +90,9 @@ message DocumentTransform { 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 -// cannot send the new value of the document. +// 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 diff --git a/packages/firestore/src/protos/google/rpc/status.proto b/packages/firestore/src/protos/google/rpc/status.proto index 3b1f7a932f2..90b70ddf917 100644 --- a/packages/firestore/src/protos/google/rpc/status.proto +++ b/packages/firestore/src/protos/google/rpc/status.proto @@ -1,4 +1,4 @@ -// Copyright 2020 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. @@ -33,12 +33,14 @@ option objc_class_prefix = "RPC"; // You can find out more about this error model and how to work with it in the // [API Design Guide](https://cloud.google.com/apis/design/errors). message Status { - // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + // The status code, which should be an enum value of + // [google.rpc.Code][google.rpc.Code]. int32 code = 1; // A developer-facing error message, which should be in English. Any // user-facing error message should be localized and sent in the - // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + // [google.rpc.Status.details][google.rpc.Status.details] field, or localized + // by the client. string message = 2; // A list of messages that carry the error details. There is a common set of diff --git a/packages/firestore/src/protos/google/type/latlng.proto b/packages/firestore/src/protos/google/type/latlng.proto index 9231456e328..daeba48b4c9 100644 --- a/packages/firestore/src/protos/google/type/latlng.proto +++ b/packages/firestore/src/protos/google/type/latlng.proto @@ -1,4 +1,4 @@ -// Copyright 2021 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. diff --git a/packages/firestore/src/protos/protos.json b/packages/firestore/src/protos/protos.json index b2c50ccaeeb..fe9bbb827b1 100644 --- a/packages/firestore/src/protos/protos.json +++ b/packages/firestore/src/protos/protos.json @@ -2,1418 +2,519 @@ "nested": { "google": { "nested": { - "protobuf": { - "options": { - "csharp_namespace": "Google.Protobuf.WellKnownTypes", - "go_package": "github.com/golang/protobuf/ptypes/wrappers", - "java_package": "com.google.protobuf", - "java_outer_classname": "WrappersProto", - "java_multiple_files": true, - "objc_class_prefix": "GPB", - "cc_enable_arenas": true, - "optimize_for": "SPEED" - }, + "firestore": { "nested": { - "Timestamp": { - "fields": { - "seconds": { - "type": "int64", - "id": 1 - }, - "nanos": { - "type": "int32", - "id": 2 - } - } - }, - "FileDescriptorSet": { - "fields": { - "file": { - "rule": "repeated", - "type": "FileDescriptorProto", - "id": 1 - } - } - }, - "FileDescriptorProto": { - "fields": { - "name": { - "type": "string", - "id": 1 - }, - "package": { - "type": "string", - "id": 2 - }, - "dependency": { - "rule": "repeated", - "type": "string", - "id": 3 - }, - "publicDependency": { - "rule": "repeated", - "type": "int32", - "id": 10, - "options": { - "packed": false - } - }, - "weakDependency": { - "rule": "repeated", - "type": "int32", - "id": 11, - "options": { - "packed": false - } - }, - "messageType": { - "rule": "repeated", - "type": "DescriptorProto", - "id": 4 - }, - "enumType": { - "rule": "repeated", - "type": "EnumDescriptorProto", - "id": 5 - }, - "service": { - "rule": "repeated", - "type": "ServiceDescriptorProto", - "id": 6 - }, - "extension": { - "rule": "repeated", - "type": "FieldDescriptorProto", - "id": 7 - }, - "options": { - "type": "FileOptions", - "id": 8 - }, - "sourceCodeInfo": { - "type": "SourceCodeInfo", - "id": 9 - }, - "syntax": { - "type": "string", - "id": 12 - } - } - }, - "DescriptorProto": { - "fields": { - "name": { - "type": "string", - "id": 1 - }, - "field": { - "rule": "repeated", - "type": "FieldDescriptorProto", - "id": 2 - }, - "extension": { - "rule": "repeated", - "type": "FieldDescriptorProto", - "id": 6 - }, - "nestedType": { - "rule": "repeated", - "type": "DescriptorProto", - "id": 3 - }, - "enumType": { - "rule": "repeated", - "type": "EnumDescriptorProto", - "id": 4 - }, - "extensionRange": { - "rule": "repeated", - "type": "ExtensionRange", - "id": 5 - }, - "oneofDecl": { - "rule": "repeated", - "type": "OneofDescriptorProto", - "id": 8 - }, - "options": { - "type": "MessageOptions", - "id": 7 - }, - "reservedRange": { - "rule": "repeated", - "type": "ReservedRange", - "id": 9 - }, - "reservedName": { - "rule": "repeated", - "type": "string", - "id": 10 - } + "v1": { + "options": { + "csharp_namespace": "Google.Cloud.Firestore.V1", + "go_package": "cloud.google.com/go/firestore/apiv1/firestorepb;firestorepb", + "java_multiple_files": true, + "java_outer_classname": "WriteProto", + "java_package": "com.google.firestore.v1", + "objc_class_prefix": "GCFS", + "php_namespace": "Google\\Cloud\\Firestore\\V1", + "ruby_package": "Google::Cloud::Firestore::V1" }, "nested": { - "ExtensionRange": { + "AggregationResult": { "fields": { - "start": { - "type": "int32", + "aggregateFields": { + "keyType": "string", + "type": "Value", + "id": 2 + } + } + }, + "Document": { + "fields": { + "name": { + "type": "string", "id": 1 }, - "end": { - "type": "int32", + "fields": { + "keyType": "string", + "type": "Value", "id": 2 + }, + "createTime": { + "type": "google.protobuf.Timestamp", + "id": 3 + }, + "updateTime": { + "type": "google.protobuf.Timestamp", + "id": 4 } } }, - "ReservedRange": { + "Value": { + "oneofs": { + "valueType": { + "oneof": [ + "nullValue", + "booleanValue", + "integerValue", + "doubleValue", + "timestampValue", + "stringValue", + "bytesValue", + "referenceValue", + "geoPointValue", + "arrayValue", + "mapValue" + ] + } + }, "fields": { - "start": { - "type": "int32", + "nullValue": { + "type": "google.protobuf.NullValue", + "id": 11 + }, + "booleanValue": { + "type": "bool", "id": 1 }, - "end": { - "type": "int32", + "integerValue": { + "type": "int64", "id": 2 + }, + "doubleValue": { + "type": "double", + "id": 3 + }, + "timestampValue": { + "type": "google.protobuf.Timestamp", + "id": 10 + }, + "stringValue": { + "type": "string", + "id": 17 + }, + "bytesValue": { + "type": "bytes", + "id": 18 + }, + "referenceValue": { + "type": "string", + "id": 5 + }, + "geoPointValue": { + "type": "google.type.LatLng", + "id": 8 + }, + "arrayValue": { + "type": "ArrayValue", + "id": 9 + }, + "mapValue": { + "type": "MapValue", + "id": 6 } } - } - } - }, - "FieldDescriptorProto": { - "fields": { - "name": { - "type": "string", - "id": 1 }, - "number": { - "type": "int32", - "id": 3 - }, - "label": { - "type": "Label", - "id": 4 - }, - "type": { - "type": "Type", - "id": 5 - }, - "typeName": { - "type": "string", - "id": 6 - }, - "extendee": { - "type": "string", - "id": 2 - }, - "defaultValue": { - "type": "string", - "id": 7 - }, - "oneofIndex": { - "type": "int32", - "id": 9 - }, - "jsonName": { - "type": "string", - "id": 10 - }, - "options": { - "type": "FieldOptions", - "id": 8 - } - }, - "nested": { - "Type": { - "values": { - "TYPE_DOUBLE": 1, - "TYPE_FLOAT": 2, - "TYPE_INT64": 3, - "TYPE_UINT64": 4, - "TYPE_INT32": 5, - "TYPE_FIXED64": 6, - "TYPE_FIXED32": 7, - "TYPE_BOOL": 8, - "TYPE_STRING": 9, - "TYPE_GROUP": 10, - "TYPE_MESSAGE": 11, - "TYPE_BYTES": 12, - "TYPE_UINT32": 13, - "TYPE_ENUM": 14, - "TYPE_SFIXED32": 15, - "TYPE_SFIXED64": 16, - "TYPE_SINT32": 17, - "TYPE_SINT64": 18 + "ArrayValue": { + "fields": { + "values": { + "rule": "repeated", + "type": "Value", + "id": 1 + } } }, - "Label": { - "values": { - "LABEL_OPTIONAL": 1, - "LABEL_REQUIRED": 2, - "LABEL_REPEATED": 3 + "MapValue": { + "fields": { + "fields": { + "keyType": "string", + "type": "Value", + "id": 1 + } } - } - } - }, - "OneofDescriptorProto": { - "fields": { - "name": { - "type": "string", - "id": 1 - }, - "options": { - "type": "OneofOptions", - "id": 2 - } - } - }, - "EnumDescriptorProto": { - "fields": { - "name": { - "type": "string", - "id": 1 - }, - "value": { - "rule": "repeated", - "type": "EnumValueDescriptorProto", - "id": 2 - }, - "options": { - "type": "EnumOptions", - "id": 3 - } - } - }, - "EnumValueDescriptorProto": { - "fields": { - "name": { - "type": "string", - "id": 1 - }, - "number": { - "type": "int32", - "id": 2 - }, - "options": { - "type": "EnumValueOptions", - "id": 3 - } - } - }, - "ServiceDescriptorProto": { - "fields": { - "name": { - "type": "string", - "id": 1 - }, - "method": { - "rule": "repeated", - "type": "MethodDescriptorProto", - "id": 2 - }, - "options": { - "type": "ServiceOptions", - "id": 3 - } - } - }, - "MethodDescriptorProto": { - "fields": { - "name": { - "type": "string", - "id": 1 - }, - "inputType": { - "type": "string", - "id": 2 - }, - "outputType": { - "type": "string", - "id": 3 - }, - "options": { - "type": "MethodOptions", - "id": 4 - }, - "clientStreaming": { - "type": "bool", - "id": 5 }, - "serverStreaming": { - "type": "bool", - "id": 6 - } - } - }, - "FileOptions": { - "fields": { - "javaPackage": { - "type": "string", - "id": 1 - }, - "javaOuterClassname": { - "type": "string", - "id": 8 - }, - "javaMultipleFiles": { - "type": "bool", - "id": 10 - }, - "javaGenerateEqualsAndHash": { - "type": "bool", - "id": 20, - "options": { - "deprecated": true + "BitSequence": { + "fields": { + "bitmap": { + "type": "bytes", + "id": 1 + }, + "padding": { + "type": "int32", + "id": 2 + } } }, - "javaStringCheckUtf8": { - "type": "bool", - "id": 27 - }, - "optimizeFor": { - "type": "OptimizeMode", - "id": 9, - "options": { - "default": "SPEED" + "BloomFilter": { + "fields": { + "bits": { + "type": "BitSequence", + "id": 1 + }, + "hashCount": { + "type": "int32", + "id": 2 + } } }, - "goPackage": { - "type": "string", - "id": 11 - }, - "ccGenericServices": { - "type": "bool", - "id": 16 - }, - "javaGenericServices": { - "type": "bool", - "id": 17 - }, - "pyGenericServices": { - "type": "bool", - "id": 18 + "DocumentMask": { + "fields": { + "fieldPaths": { + "rule": "repeated", + "type": "string", + "id": 1 + } + } }, - "deprecated": { - "type": "bool", - "id": 23 + "Precondition": { + "oneofs": { + "conditionType": { + "oneof": [ + "exists", + "updateTime" + ] + } + }, + "fields": { + "exists": { + "type": "bool", + "id": 1 + }, + "updateTime": { + "type": "google.protobuf.Timestamp", + "id": 2 + } + } }, - "ccEnableArenas": { - "type": "bool", - "id": 31 - }, - "objcClassPrefix": { - "type": "string", - "id": 36 - }, - "csharpNamespace": { - "type": "string", - "id": 37 - }, - "uninterpretedOption": { - "rule": "repeated", - "type": "UninterpretedOption", - "id": 999 - } - }, - "extensions": [ - [ - 1000, - 536870911 - ] - ], - "reserved": [ - [ - 38, - 38 - ] - ], - "nested": { - "OptimizeMode": { - "values": { - "SPEED": 1, - "CODE_SIZE": 2, - "LITE_RUNTIME": 3 - } - } - } - }, - "MessageOptions": { - "fields": { - "messageSetWireFormat": { - "type": "bool", - "id": 1 - }, - "noStandardDescriptorAccessor": { - "type": "bool", - "id": 2 - }, - "deprecated": { - "type": "bool", - "id": 3 - }, - "mapEntry": { - "type": "bool", - "id": 7 - }, - "uninterpretedOption": { - "rule": "repeated", - "type": "UninterpretedOption", - "id": 999 - } - }, - "extensions": [ - [ - 1000, - 536870911 - ] - ], - "reserved": [ - [ - 8, - 8 - ] - ] - }, - "FieldOptions": { - "fields": { - "ctype": { - "type": "CType", - "id": 1, - "options": { - "default": "STRING" + "TransactionOptions": { + "oneofs": { + "mode": { + "oneof": [ + "readOnly", + "readWrite" + ] + } + }, + "fields": { + "readOnly": { + "type": "ReadOnly", + "id": 2 + }, + "readWrite": { + "type": "ReadWrite", + "id": 3 + } + }, + "nested": { + "ReadWrite": { + "fields": { + "retryTransaction": { + "type": "bytes", + "id": 1 + } + } + }, + "ReadOnly": { + "oneofs": { + "consistencySelector": { + "oneof": [ + "readTime" + ] + } + }, + "fields": { + "readTime": { + "type": "google.protobuf.Timestamp", + "id": 2 + } + } + } } }, - "packed": { - "type": "bool", - "id": 2 - }, - "jstype": { - "type": "JSType", - "id": 6, + "Firestore": { "options": { - "default": "JS_NORMAL" - } - }, - "lazy": { - "type": "bool", - "id": 5 - }, - "deprecated": { - "type": "bool", - "id": 3 - }, - "weak": { - "type": "bool", - "id": 10 - }, - "uninterpretedOption": { - "rule": "repeated", - "type": "UninterpretedOption", - "id": 999 - } - }, - "extensions": [ - [ - 1000, - 536870911 - ] - ], - "reserved": [ - [ - 4, - 4 - ] - ], - "nested": { - "CType": { - "values": { - "STRING": 0, - "CORD": 1, - "STRING_PIECE": 2 - } - }, - "JSType": { - "values": { - "JS_NORMAL": 0, - "JS_STRING": 1, - "JS_NUMBER": 2 - } - } - } - }, - "OneofOptions": { - "fields": { - "uninterpretedOption": { - "rule": "repeated", - "type": "UninterpretedOption", - "id": 999 - } - }, - "extensions": [ - [ - 1000, - 536870911 - ] - ] - }, - "EnumOptions": { - "fields": { - "allowAlias": { - "type": "bool", - "id": 2 - }, - "deprecated": { - "type": "bool", - "id": 3 - }, - "uninterpretedOption": { - "rule": "repeated", - "type": "UninterpretedOption", - "id": 999 - } - }, - "extensions": [ - [ - 1000, - 536870911 - ] - ] - }, - "EnumValueOptions": { - "fields": { - "deprecated": { - "type": "bool", - "id": 1 - }, - "uninterpretedOption": { - "rule": "repeated", - "type": "UninterpretedOption", - "id": 999 - } - }, - "extensions": [ - [ - 1000, - 536870911 - ] - ] - }, - "ServiceOptions": { - "fields": { - "deprecated": { - "type": "bool", - "id": 33 - }, - "uninterpretedOption": { - "rule": "repeated", - "type": "UninterpretedOption", - "id": 999 - } - }, - "extensions": [ - [ - 1000, - 536870911 - ] - ] - }, - "MethodOptions": { - "fields": { - "deprecated": { - "type": "bool", - "id": 33 - }, - "uninterpretedOption": { - "rule": "repeated", - "type": "UninterpretedOption", - "id": 999 - } - }, - "extensions": [ - [ - 1000, - 536870911 - ] - ] - }, - "UninterpretedOption": { - "fields": { - "name": { - "rule": "repeated", - "type": "NamePart", - "id": 2 - }, - "identifierValue": { - "type": "string", - "id": 3 - }, - "positiveIntValue": { - "type": "uint64", - "id": 4 - }, - "negativeIntValue": { - "type": "int64", - "id": 5 - }, - "doubleValue": { - "type": "double", - "id": 6 - }, - "stringValue": { - "type": "bytes", - "id": 7 - }, - "aggregateValue": { - "type": "string", - "id": 8 - } - }, - "nested": { - "NamePart": { - "fields": { - "namePart": { - "rule": "required", - "type": "string", - "id": 1 - }, - "isExtension": { - "rule": "required", - "type": "bool", - "id": 2 - } - } - } - } - }, - "SourceCodeInfo": { - "fields": { - "location": { - "rule": "repeated", - "type": "Location", - "id": 1 - } - }, - "nested": { - "Location": { - "fields": { - "path": { - "rule": "repeated", - "type": "int32", - "id": 1 + "(google.api.default_host)": "firestore.googleapis.com", + "(google.api.oauth_scopes)": "https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/datastore" + }, + "methods": { + "GetDocument": { + "requestType": "GetDocumentRequest", + "responseType": "Document", + "options": { + "(google.api.http).get": "/v1/{name=projects/*/databases/*/documents/*/**}" + }, + "parsedOptions": [ + { + "(google.api.http)": { + "get": "/v1/{name=projects/*/databases/*/documents/*/**}" + } + } + ] }, - "span": { - "rule": "repeated", - "type": "int32", - "id": 2 + "ListDocuments": { + "requestType": "ListDocumentsRequest", + "responseType": "ListDocumentsResponse", + "options": { + "(google.api.http).get": "/v1/{parent=projects/*/databases/*/documents/*/**}/{collection_id}", + "(google.api.http).additional_bindings.get": "/v1/{parent=projects/*/databases/*/documents}/{collection_id}" + }, + "parsedOptions": [ + { + "(google.api.http)": { + "get": "/v1/{parent=projects/*/databases/*/documents/*/**}/{collection_id}", + "additional_bindings": { + "get": "/v1/{parent=projects/*/databases/*/documents}/{collection_id}" + } + } + } + ] }, - "leadingComments": { - "type": "string", - "id": 3 + "UpdateDocument": { + "requestType": "UpdateDocumentRequest", + "responseType": "Document", + "options": { + "(google.api.http).patch": "/v1/{document.name=projects/*/databases/*/documents/*/**}", + "(google.api.http).body": "document", + "(google.api.method_signature)": "document,update_mask" + }, + "parsedOptions": [ + { + "(google.api.http)": { + "patch": "/v1/{document.name=projects/*/databases/*/documents/*/**}", + "body": "document" + } + }, + { + "(google.api.method_signature)": "document,update_mask" + } + ] }, - "trailingComments": { - "type": "string", - "id": 4 + "DeleteDocument": { + "requestType": "DeleteDocumentRequest", + "responseType": "google.protobuf.Empty", + "options": { + "(google.api.http).delete": "/v1/{name=projects/*/databases/*/documents/*/**}", + "(google.api.method_signature)": "name" + }, + "parsedOptions": [ + { + "(google.api.http)": { + "delete": "/v1/{name=projects/*/databases/*/documents/*/**}" + } + }, + { + "(google.api.method_signature)": "name" + } + ] }, - "leadingDetachedComments": { - "rule": "repeated", - "type": "string", - "id": 6 - } - } - } - } - }, - "GeneratedCodeInfo": { - "fields": { - "annotation": { - "rule": "repeated", - "type": "Annotation", - "id": 1 - } - }, - "nested": { - "Annotation": { - "fields": { - "path": { - "rule": "repeated", - "type": "int32", - "id": 1 + "BatchGetDocuments": { + "requestType": "BatchGetDocumentsRequest", + "responseType": "BatchGetDocumentsResponse", + "responseStream": true, + "options": { + "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:batchGet", + "(google.api.http).body": "*" + }, + "parsedOptions": [ + { + "(google.api.http)": { + "post": "/v1/{database=projects/*/databases/*}/documents:batchGet", + "body": "*" + } + } + ] }, - "sourceFile": { - "type": "string", - "id": 2 + "BeginTransaction": { + "requestType": "BeginTransactionRequest", + "responseType": "BeginTransactionResponse", + "options": { + "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:beginTransaction", + "(google.api.http).body": "*", + "(google.api.method_signature)": "database" + }, + "parsedOptions": [ + { + "(google.api.http)": { + "post": "/v1/{database=projects/*/databases/*}/documents:beginTransaction", + "body": "*" + } + }, + { + "(google.api.method_signature)": "database" + } + ] }, - "begin": { - "type": "int32", - "id": 3 + "Commit": { + "requestType": "CommitRequest", + "responseType": "CommitResponse", + "options": { + "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:commit", + "(google.api.http).body": "*", + "(google.api.method_signature)": "database,writes" + }, + "parsedOptions": [ + { + "(google.api.http)": { + "post": "/v1/{database=projects/*/databases/*}/documents:commit", + "body": "*" + } + }, + { + "(google.api.method_signature)": "database,writes" + } + ] }, - "end": { - "type": "int32", - "id": 4 - } - } - } - } - }, - "Struct": { - "fields": { - "fields": { - "keyType": "string", - "type": "Value", - "id": 1 - } - } - }, - "Value": { - "oneofs": { - "kind": { - "oneof": [ - "nullValue", - "numberValue", - "stringValue", - "boolValue", - "structValue", - "listValue" - ] - } - }, - "fields": { - "nullValue": { - "type": "NullValue", - "id": 1 - }, - "numberValue": { - "type": "double", - "id": 2 - }, - "stringValue": { - "type": "string", - "id": 3 - }, - "boolValue": { - "type": "bool", - "id": 4 - }, - "structValue": { - "type": "Struct", - "id": 5 - }, - "listValue": { - "type": "ListValue", - "id": 6 - } - } - }, - "NullValue": { - "values": { - "NULL_VALUE": 0 - } - }, - "ListValue": { - "fields": { - "values": { - "rule": "repeated", - "type": "Value", - "id": 1 - } - } - }, - "Empty": { - "fields": {} - }, - "DoubleValue": { - "fields": { - "value": { - "type": "double", - "id": 1 - } - } - }, - "FloatValue": { - "fields": { - "value": { - "type": "float", - "id": 1 - } - } - }, - "Int64Value": { - "fields": { - "value": { - "type": "int64", - "id": 1 - } - } - }, - "UInt64Value": { - "fields": { - "value": { - "type": "uint64", - "id": 1 - } - } - }, - "Int32Value": { - "fields": { - "value": { - "type": "int32", - "id": 1 - } - } - }, - "UInt32Value": { - "fields": { - "value": { - "type": "uint32", - "id": 1 - } - } - }, - "BoolValue": { - "fields": { - "value": { - "type": "bool", - "id": 1 - } - } - }, - "StringValue": { - "fields": { - "value": { - "type": "string", - "id": 1 - } - } - }, - "BytesValue": { - "fields": { - "value": { - "type": "bytes", - "id": 1 - } - } - }, - "Any": { - "fields": { - "typeUrl": { - "type": "string", - "id": 1 - }, - "value": { - "type": "bytes", - "id": 2 - } - } - } - } - }, - "firestore": { - "nested": { - "v1": { - "options": { - "csharp_namespace": "Google.Cloud.Firestore.V1", - "go_package": "google.golang.org/genproto/googleapis/firestore/v1;firestore", - "java_multiple_files": true, - "java_outer_classname": "WriteProto", - "java_package": "com.google.firestore.v1", - "objc_class_prefix": "GCFS", - "php_namespace": "Google\\Cloud\\Firestore\\V1", - "ruby_package": "Google::Cloud::Firestore::V1" - }, - "nested": { - "AggregationResult": { - "fields": { - "aggregateFields": { - "keyType": "string", - "type": "Value", - "id": 2 - } - } - }, - "BitSequence": { - "fields": { - "bitmap": { - "type": "bytes", - "id": 1 - }, - "padding": { - "type": "int32", - "id": 2 - } - } - }, - "BloomFilter": { - "fields": { - "bits": { - "type": "BitSequence", - "id": 1 + "Rollback": { + "requestType": "RollbackRequest", + "responseType": "google.protobuf.Empty", + "options": { + "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:rollback", + "(google.api.http).body": "*", + "(google.api.method_signature)": "database,transaction" + }, + "parsedOptions": [ + { + "(google.api.http)": { + "post": "/v1/{database=projects/*/databases/*}/documents:rollback", + "body": "*" + } + }, + { + "(google.api.method_signature)": "database,transaction" + } + ] }, - "hashCount": { - "type": "int32", - "id": 2 - } - } - }, - "DocumentMask": { - "fields": { - "fieldPaths": { - "rule": "repeated", - "type": "string", - "id": 1 - } - } - }, - "Precondition": { - "oneofs": { - "conditionType": { - "oneof": [ - "exists", - "updateTime" + "RunQuery": { + "requestType": "RunQueryRequest", + "responseType": "RunQueryResponse", + "responseStream": true, + "options": { + "(google.api.http).post": "/v1/{parent=projects/*/databases/*/documents}:runQuery", + "(google.api.http).body": "*", + "(google.api.http).additional_bindings.post": "/v1/{parent=projects/*/databases/*/documents/*/**}:runQuery", + "(google.api.http).additional_bindings.body": "*" + }, + "parsedOptions": [ + { + "(google.api.http)": { + "post": "/v1/{parent=projects/*/databases/*/documents}:runQuery", + "body": "*", + "additional_bindings": { + "post": "/v1/{parent=projects/*/databases/*/documents/*/**}:runQuery", + "body": "*" + } + } + } ] - } - }, - "fields": { - "exists": { - "type": "bool", - "id": 1 }, - "updateTime": { - "type": "google.protobuf.Timestamp", - "id": 2 - } - } - }, - "TransactionOptions": { - "oneofs": { - "mode": { - "oneof": [ - "readOnly", - "readWrite" - ] - } - }, - "fields": { - "readOnly": { - "type": "ReadOnly", - "id": 2 - }, - "readWrite": { - "type": "ReadWrite", - "id": 3 - } - }, - "nested": { - "ReadWrite": { - "fields": { - "retryTransaction": { - "type": "bytes", - "id": 1 - } - } - }, - "ReadOnly": { - "oneofs": { - "consistencySelector": { - "oneof": [ - "readTime" - ] - } + "RunAggregationQuery": { + "requestType": "RunAggregationQueryRequest", + "responseType": "RunAggregationQueryResponse", + "responseStream": true, + "options": { + "(google.api.http).post": "/v1/{parent=projects/*/databases/*/documents}:runAggregationQuery", + "(google.api.http).body": "*", + "(google.api.http).additional_bindings.post": "/v1/{parent=projects/*/databases/*/documents/*/**}:runAggregationQuery", + "(google.api.http).additional_bindings.body": "*" }, - "fields": { - "readTime": { - "type": "google.protobuf.Timestamp", - "id": 2 + "parsedOptions": [ + { + "(google.api.http)": { + "post": "/v1/{parent=projects/*/databases/*/documents}:runAggregationQuery", + "body": "*", + "additional_bindings": { + "post": "/v1/{parent=projects/*/databases/*/documents/*/**}:runAggregationQuery", + "body": "*" + } + } } - } - } - } - }, - "Document": { - "fields": { - "name": { - "type": "string", - "id": 1 - }, - "fields": { - "keyType": "string", - "type": "Value", - "id": 2 - }, - "createTime": { - "type": "google.protobuf.Timestamp", - "id": 3 - }, - "updateTime": { - "type": "google.protobuf.Timestamp", - "id": 4 - } - } - }, - "Value": { - "oneofs": { - "valueType": { - "oneof": [ - "nullValue", - "booleanValue", - "integerValue", - "doubleValue", - "timestampValue", - "stringValue", - "bytesValue", - "referenceValue", - "geoPointValue", - "arrayValue", - "mapValue" ] - } - }, - "fields": { - "nullValue": { - "type": "google.protobuf.NullValue", - "id": 11 - }, - "booleanValue": { - "type": "bool", - "id": 1 - }, - "integerValue": { - "type": "int64", - "id": 2 - }, - "doubleValue": { - "type": "double", - "id": 3 - }, - "timestampValue": { - "type": "google.protobuf.Timestamp", - "id": 10 - }, - "stringValue": { - "type": "string", - "id": 17 }, - "bytesValue": { - "type": "bytes", - "id": 18 - }, - "referenceValue": { - "type": "string", - "id": 5 - }, - "geoPointValue": { - "type": "google.type.LatLng", - "id": 8 - }, - "arrayValue": { - "type": "ArrayValue", - "id": 9 - }, - "mapValue": { - "type": "MapValue", - "id": 6 - } - } - }, - "ArrayValue": { - "fields": { - "values": { - "rule": "repeated", - "type": "Value", - "id": 1 - } - } - }, - "MapValue": { - "fields": { - "fields": { - "keyType": "string", - "type": "Value", - "id": 1 - } - } - }, - "Firestore": { - "options": { - "(google.api.default_host)": "firestore.googleapis.com", - "(google.api.oauth_scopes)": "https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/datastore" - }, - "methods": { - "GetDocument": { - "requestType": "GetDocumentRequest", - "responseType": "Document", + "PartitionQuery": { + "requestType": "PartitionQueryRequest", + "responseType": "PartitionQueryResponse", "options": { - "(google.api.http).get": "/v1/{name=projects/*/databases/*/documents/*/**}" + "(google.api.http).post": "/v1/{parent=projects/*/databases/*/documents}:partitionQuery", + "(google.api.http).body": "*", + "(google.api.http).additional_bindings.post": "/v1/{parent=projects/*/databases/*/documents/*/**}:partitionQuery", + "(google.api.http).additional_bindings.body": "*" }, "parsedOptions": [ { "(google.api.http)": { - "get": "/v1/{name=projects/*/databases/*/documents/*/**}" + "post": "/v1/{parent=projects/*/databases/*/documents}:partitionQuery", + "body": "*", + "additional_bindings": { + "post": "/v1/{parent=projects/*/databases/*/documents/*/**}:partitionQuery", + "body": "*" + } } } ] }, - "ListDocuments": { - "requestType": "ListDocumentsRequest", - "responseType": "ListDocumentsResponse", + "Write": { + "requestType": "WriteRequest", + "requestStream": true, + "responseType": "WriteResponse", + "responseStream": true, "options": { - "(google.api.http).get": "/v1/{parent=projects/*/databases/*/documents/*/**}/{collection_id}" + "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:write", + "(google.api.http).body": "*" }, "parsedOptions": [ { "(google.api.http)": { - "get": "/v1/{parent=projects/*/databases/*/documents/*/**}/{collection_id}" + "post": "/v1/{database=projects/*/databases/*}/documents:write", + "body": "*" } } ] }, - "UpdateDocument": { - "requestType": "UpdateDocumentRequest", - "responseType": "Document", + "Listen": { + "requestType": "ListenRequest", + "requestStream": true, + "responseType": "ListenResponse", + "responseStream": true, "options": { - "(google.api.http).patch": "/v1/{document.name=projects/*/databases/*/documents/*/**}", - "(google.api.http).body": "document", - "(google.api.method_signature)": "document,update_mask" + "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:listen", + "(google.api.http).body": "*" }, "parsedOptions": [ { "(google.api.http)": { - "patch": "/v1/{document.name=projects/*/databases/*/documents/*/**}", - "body": "document" + "post": "/v1/{database=projects/*/databases/*}/documents:listen", + "body": "*" } - }, - { - "(google.api.method_signature)": "document,update_mask" } ] }, - "DeleteDocument": { - "requestType": "DeleteDocumentRequest", - "responseType": "google.protobuf.Empty", + "ListCollectionIds": { + "requestType": "ListCollectionIdsRequest", + "responseType": "ListCollectionIdsResponse", "options": { - "(google.api.http).delete": "/v1/{name=projects/*/databases/*/documents/*/**}", - "(google.api.method_signature)": "name" + "(google.api.http).post": "/v1/{parent=projects/*/databases/*/documents}:listCollectionIds", + "(google.api.http).body": "*", + "(google.api.http).additional_bindings.post": "/v1/{parent=projects/*/databases/*/documents/*/**}:listCollectionIds", + "(google.api.http).additional_bindings.body": "*", + "(google.api.method_signature)": "parent" }, "parsedOptions": [ { "(google.api.http)": { - "delete": "/v1/{name=projects/*/databases/*/documents/*/**}" + "post": "/v1/{parent=projects/*/databases/*/documents}:listCollectionIds", + "body": "*", + "additional_bindings": { + "post": "/v1/{parent=projects/*/databases/*/documents/*/**}:listCollectionIds", + "body": "*" + } } }, { - "(google.api.method_signature)": "name" + "(google.api.method_signature)": "parent" } ] }, - "BatchGetDocuments": { - "requestType": "BatchGetDocumentsRequest", - "responseType": "BatchGetDocumentsResponse", - "responseStream": true, + "BatchWrite": { + "requestType": "BatchWriteRequest", + "responseType": "BatchWriteResponse", "options": { - "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:batchGet", - "(google.api.http).body": "*" - }, - "parsedOptions": [ - { - "(google.api.http)": { - "post": "/v1/{database=projects/*/databases/*}/documents:batchGet", - "body": "*" - } - } - ] - }, - "BeginTransaction": { - "requestType": "BeginTransactionRequest", - "responseType": "BeginTransactionResponse", - "options": { - "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:beginTransaction", - "(google.api.http).body": "*", - "(google.api.method_signature)": "database" - }, - "parsedOptions": [ - { - "(google.api.http)": { - "post": "/v1/{database=projects/*/databases/*}/documents:beginTransaction", - "body": "*" - } - }, - { - "(google.api.method_signature)": "database" - } - ] - }, - "Commit": { - "requestType": "CommitRequest", - "responseType": "CommitResponse", - "options": { - "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:commit", - "(google.api.http).body": "*", - "(google.api.method_signature)": "database,writes" - }, - "parsedOptions": [ - { - "(google.api.http)": { - "post": "/v1/{database=projects/*/databases/*}/documents:commit", - "body": "*" - } - }, - { - "(google.api.method_signature)": "database,writes" - } - ] - }, - "Rollback": { - "requestType": "RollbackRequest", - "responseType": "google.protobuf.Empty", - "options": { - "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:rollback", - "(google.api.http).body": "*", - "(google.api.method_signature)": "database,transaction" - }, - "parsedOptions": [ - { - "(google.api.http)": { - "post": "/v1/{database=projects/*/databases/*}/documents:rollback", - "body": "*" - } - }, - { - "(google.api.method_signature)": "database,transaction" - } - ] - }, - "RunQuery": { - "requestType": "RunQueryRequest", - "responseType": "RunQueryResponse", - "responseStream": true, - "options": { - "(google.api.http).post": "/v1/{parent=projects/*/databases/*/documents}:runQuery", - "(google.api.http).body": "*", - "(google.api.http).additional_bindings.post": "/v1/{parent=projects/*/databases/*/documents/*/**}:runQuery", - "(google.api.http).additional_bindings.body": "*" - }, - "parsedOptions": [ - { - "(google.api.http)": { - "post": "/v1/{parent=projects/*/databases/*/documents}:runQuery", - "body": "*", - "additional_bindings": { - "post": "/v1/{parent=projects/*/databases/*/documents/*/**}:runQuery", - "body": "*" - } - } - } - ] - }, - "RunAggregationQuery": { - "requestType": "RunAggregationQueryRequest", - "responseType": "RunAggregationQueryResponse", - "responseStream": true, - "options": { - "(google.api.http).post": "/v1/{parent=projects/*/databases/*/documents}:runAggregationQuery", - "(google.api.http).body": "*", - "(google.api.http).additional_bindings.post": "/v1/{parent=projects/*/databases/*/documents/*/**}:runAggregationQuery", - "(google.api.http).additional_bindings.body": "*" - }, - "parsedOptions": [ - { - "(google.api.http)": { - "post": "/v1/{parent=projects/*/databases/*/documents}:runAggregationQuery", - "body": "*", - "additional_bindings": { - "post": "/v1/{parent=projects/*/databases/*/documents/*/**}:runAggregationQuery", - "body": "*" - } - } - } - ] - }, - "PartitionQuery": { - "requestType": "PartitionQueryRequest", - "responseType": "PartitionQueryResponse", - "options": { - "(google.api.http).post": "/v1/{parent=projects/*/databases/*/documents}:partitionQuery", - "(google.api.http).body": "*", - "(google.api.http).additional_bindings.post": "/v1/{parent=projects/*/databases/*/documents/*/**}:partitionQuery", - "(google.api.http).additional_bindings.body": "*" - }, - "parsedOptions": [ - { - "(google.api.http)": { - "post": "/v1/{parent=projects/*/databases/*/documents}:partitionQuery", - "body": "*", - "additional_bindings": { - "post": "/v1/{parent=projects/*/databases/*/documents/*/**}:partitionQuery", - "body": "*" - } - } - } - ] - }, - "Write": { - "requestType": "WriteRequest", - "requestStream": true, - "responseType": "WriteResponse", - "responseStream": true, - "options": { - "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:write", - "(google.api.http).body": "*" - }, - "parsedOptions": [ - { - "(google.api.http)": { - "post": "/v1/{database=projects/*/databases/*}/documents:write", - "body": "*" - } - } - ] - }, - "Listen": { - "requestType": "ListenRequest", - "requestStream": true, - "responseType": "ListenResponse", - "responseStream": true, - "options": { - "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:listen", - "(google.api.http).body": "*" - }, - "parsedOptions": [ - { - "(google.api.http)": { - "post": "/v1/{database=projects/*/databases/*}/documents:listen", - "body": "*" - } - } - ] - }, - "ListCollectionIds": { - "requestType": "ListCollectionIdsRequest", - "responseType": "ListCollectionIdsResponse", - "options": { - "(google.api.http).post": "/v1/{parent=projects/*/databases/*/documents}:listCollectionIds", - "(google.api.http).body": "*", - "(google.api.http).additional_bindings.post": "/v1/{parent=projects/*/databases/*/documents/*/**}:listCollectionIds", - "(google.api.http).additional_bindings.body": "*", - "(google.api.method_signature)": "parent" - }, - "parsedOptions": [ - { - "(google.api.http)": { - "post": "/v1/{parent=projects/*/databases/*/documents}:listCollectionIds", - "body": "*", - "additional_bindings": { - "post": "/v1/{parent=projects/*/databases/*/documents/*/**}:listCollectionIds", - "body": "*" - } - } - }, - { - "(google.api.method_signature)": "parent" - } - ] - }, - "BatchWrite": { - "requestType": "BatchWriteRequest", - "responseType": "BatchWriteResponse", - "options": { - "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:batchWrite", + "(google.api.http).post": "/v1/{database=projects/*/databases/*}/documents:batchWrite", "(google.api.http).body": "*" }, "parsedOptions": [ @@ -1495,24 +596,36 @@ "type": "string", "id": 2, "options": { - "(google.api.field_behavior)": "REQUIRED" + "(google.api.field_behavior)": "OPTIONAL" } }, "pageSize": { "type": "int32", - "id": 3 + "id": 3, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } }, "pageToken": { "type": "string", - "id": 4 + "id": 4, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } }, "orderBy": { "type": "string", - "id": 6 + "id": 6, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } }, "mask": { "type": "DocumentMask", - "id": 7 + "id": 7, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } }, "transaction": { "type": "bytes", @@ -1793,10 +906,24 @@ "readTime": { "type": "google.protobuf.Timestamp", "id": 7 + }, + "explainOptions": { + "type": "ExplainOptions", + "id": 10, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } } } }, "RunQueryResponse": { + "oneofs": { + "continuationSelector": { + "oneof": [ + "done" + ] + } + }, "fields": { "transaction": { "type": "bytes", @@ -1813,6 +940,14 @@ "skippedResults": { "type": "int32", "id": 4 + }, + "done": { + "type": "bool", + "id": 6 + }, + "explainMetrics": { + "type": "ExplainMetrics", + "id": 11 } } }, @@ -1854,6 +989,13 @@ "readTime": { "type": "google.protobuf.Timestamp", "id": 6 + }, + "explainOptions": { + "type": "ExplainOptions", + "id": 8, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } } } }, @@ -1870,6 +1012,10 @@ "readTime": { "type": "google.protobuf.Timestamp", "id": 3 + }, + "explainMetrics": { + "type": "ExplainMetrics", + "id": 10 } } }, @@ -1879,6 +1025,11 @@ "oneof": [ "structuredQuery" ] + }, + "consistencySelector": { + "oneof": [ + "readTime" + ] } }, "fields": { @@ -1904,6 +1055,10 @@ "pageSize": { "type": "int32", "id": 5 + }, + "readTime": { + "type": "google.protobuf.Timestamp", + "id": 6 } } }, @@ -2150,6 +1305,13 @@ } }, "ListCollectionIdsRequest": { + "oneofs": { + "consistencySelector": { + "oneof": [ + "readTime" + ] + } + }, "fields": { "parent": { "type": "string", @@ -2165,9 +1327,13 @@ "pageToken": { "type": "string", "id": 3 - } - } - }, + }, + "readTime": { + "type": "google.protobuf.Timestamp", + "id": 4 + } + } + }, "ListCollectionIdsResponse": { "fields": { "collectionIds": { @@ -2251,6 +1417,13 @@ "limit": { "type": "google.protobuf.Int32Value", "id": 5 + }, + "findNearest": { + "type": "FindNearest", + "id": 9, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } } }, "nested": { @@ -2388,6 +1561,13 @@ } } }, + "Direction": { + "values": { + "DIRECTION_UNSPECIFIED": 0, + "ASCENDING": 1, + "DESCENDING": 2 + } + }, "FieldReference": { "fields": { "fieldPath": { @@ -2405,11 +1585,60 @@ } } }, - "Direction": { - "values": { - "DIRECTION_UNSPECIFIED": 0, - "ASCENDING": 1, - "DESCENDING": 2 + "FindNearest": { + "fields": { + "vectorField": { + "type": "FieldReference", + "id": 1, + "options": { + "(google.api.field_behavior)": "REQUIRED" + } + }, + "queryVector": { + "type": "Value", + "id": 2, + "options": { + "(google.api.field_behavior)": "REQUIRED" + } + }, + "distanceMeasure": { + "type": "DistanceMeasure", + "id": 3, + "options": { + "(google.api.field_behavior)": "REQUIRED" + } + }, + "limit": { + "type": "google.protobuf.Int32Value", + "id": 4, + "options": { + "(google.api.field_behavior)": "REQUIRED" + } + }, + "distanceResultField": { + "type": "string", + "id": 5, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } + }, + "distanceThreshold": { + "type": "google.protobuf.DoubleValue", + "id": 6, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } + } + }, + "nested": { + "DistanceMeasure": { + "values": { + "DISTANCE_MEASURE_UNSPECIFIED": 0, + "EUCLIDEAN": 1, + "COSINE": 2, + "DOT_PRODUCT": 3 + } + } } } } @@ -2430,7 +1659,10 @@ "aggregations": { "rule": "repeated", "type": "Aggregation", - "id": 3 + "id": 3, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } } }, "nested": { @@ -2459,7 +1691,10 @@ }, "alias": { "type": "string", - "id": 7 + "id": 7, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } } }, "nested": { @@ -2467,14 +1702,17 @@ "fields": { "upTo": { "type": "google.protobuf.Int64Value", - "id": 1 + "id": 1, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } } } }, "Sum": { "fields": { "field": { - "type": "FieldReference", + "type": "StructuredQuery.FieldReference", "id": 1 } } @@ -2482,7 +1720,7 @@ "Avg": { "fields": { "field": { - "type": "FieldReference", + "type": "StructuredQuery.FieldReference", "id": 1 } } @@ -2491,335 +1729,1768 @@ } } }, - "Cursor": { - "fields": { - "values": { - "rule": "repeated", - "type": "Value", - "id": 1 - }, - "before": { - "type": "bool", - "id": 2 - } + "Cursor": { + "fields": { + "values": { + "rule": "repeated", + "type": "Value", + "id": 1 + }, + "before": { + "type": "bool", + "id": 2 + } + } + }, + "ExplainOptions": { + "fields": { + "analyze": { + "type": "bool", + "id": 1, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } + } + } + }, + "ExplainMetrics": { + "fields": { + "planSummary": { + "type": "PlanSummary", + "id": 1 + }, + "executionStats": { + "type": "ExecutionStats", + "id": 2 + } + } + }, + "PlanSummary": { + "fields": { + "indexesUsed": { + "rule": "repeated", + "type": "google.protobuf.Struct", + "id": 1 + } + } + }, + "ExecutionStats": { + "fields": { + "resultsReturned": { + "type": "int64", + "id": 1 + }, + "executionDuration": { + "type": "google.protobuf.Duration", + "id": 3 + }, + "readOperations": { + "type": "int64", + "id": 4 + }, + "debugStats": { + "type": "google.protobuf.Struct", + "id": 5 + } + } + }, + "Write": { + "oneofs": { + "operation": { + "oneof": [ + "update", + "delete", + "verify", + "transform" + ] + } + }, + "fields": { + "update": { + "type": "Document", + "id": 1 + }, + "delete": { + "type": "string", + "id": 2 + }, + "verify": { + "type": "string", + "id": 5 + }, + "transform": { + "type": "DocumentTransform", + "id": 6 + }, + "updateMask": { + "type": "DocumentMask", + "id": 3 + }, + "updateTransforms": { + "rule": "repeated", + "type": "DocumentTransform.FieldTransform", + "id": 7 + }, + "currentDocument": { + "type": "Precondition", + "id": 4 + } + } + }, + "DocumentTransform": { + "fields": { + "document": { + "type": "string", + "id": 1 + }, + "fieldTransforms": { + "rule": "repeated", + "type": "FieldTransform", + "id": 2 + } + }, + "nested": { + "FieldTransform": { + "oneofs": { + "transformType": { + "oneof": [ + "setToServerValue", + "increment", + "maximum", + "minimum", + "appendMissingElements", + "removeAllFromArray" + ] + } + }, + "fields": { + "fieldPath": { + "type": "string", + "id": 1 + }, + "setToServerValue": { + "type": "ServerValue", + "id": 2 + }, + "increment": { + "type": "Value", + "id": 3 + }, + "maximum": { + "type": "Value", + "id": 4 + }, + "minimum": { + "type": "Value", + "id": 5 + }, + "appendMissingElements": { + "type": "ArrayValue", + "id": 6 + }, + "removeAllFromArray": { + "type": "ArrayValue", + "id": 7 + } + }, + "nested": { + "ServerValue": { + "values": { + "SERVER_VALUE_UNSPECIFIED": 0, + "REQUEST_TIME": 1 + } + } + } + } + } + }, + "WriteResult": { + "fields": { + "updateTime": { + "type": "google.protobuf.Timestamp", + "id": 1 + }, + "transformResults": { + "rule": "repeated", + "type": "Value", + "id": 2 + } + } + }, + "DocumentChange": { + "fields": { + "document": { + "type": "Document", + "id": 1 + }, + "targetIds": { + "rule": "repeated", + "type": "int32", + "id": 5 + }, + "removedTargetIds": { + "rule": "repeated", + "type": "int32", + "id": 6 + } + } + }, + "DocumentDelete": { + "fields": { + "document": { + "type": "string", + "id": 1 + }, + "removedTargetIds": { + "rule": "repeated", + "type": "int32", + "id": 6 + }, + "readTime": { + "type": "google.protobuf.Timestamp", + "id": 4 + } + } + }, + "DocumentRemove": { + "fields": { + "document": { + "type": "string", + "id": 1 + }, + "removedTargetIds": { + "rule": "repeated", + "type": "int32", + "id": 2 + }, + "readTime": { + "type": "google.protobuf.Timestamp", + "id": 4 + } + } + }, + "ExistenceFilter": { + "fields": { + "targetId": { + "type": "int32", + "id": 1 + }, + "count": { + "type": "int32", + "id": 2 + }, + "unchangedNames": { + "type": "BloomFilter", + "id": 3 + } + } + } + } + } + } + }, + "api": { + "options": { + "go_package": "google.golang.org/genproto/googleapis/api;api", + "java_multiple_files": true, + "java_outer_classname": "LaunchStageProto", + "java_package": "com.google.api", + "objc_class_prefix": "GAPI", + "cc_enable_arenas": true + }, + "nested": { + "fieldBehavior": { + "rule": "repeated", + "type": "google.api.FieldBehavior", + "id": 1052, + "extend": "google.protobuf.FieldOptions", + "options": { + "packed": false + } + }, + "FieldBehavior": { + "values": { + "FIELD_BEHAVIOR_UNSPECIFIED": 0, + "OPTIONAL": 1, + "REQUIRED": 2, + "OUTPUT_ONLY": 3, + "INPUT_ONLY": 4, + "IMMUTABLE": 5, + "UNORDERED_LIST": 6, + "NON_EMPTY_DEFAULT": 7, + "IDENTIFIER": 8 + } + }, + "http": { + "type": "HttpRule", + "id": 72295728, + "extend": "google.protobuf.MethodOptions" + }, + "Http": { + "fields": { + "rules": { + "rule": "repeated", + "type": "HttpRule", + "id": 1 + }, + "fullyDecodeReservedExpansion": { + "type": "bool", + "id": 2 + } + } + }, + "HttpRule": { + "oneofs": { + "pattern": { + "oneof": [ + "get", + "put", + "post", + "delete", + "patch", + "custom" + ] + } + }, + "fields": { + "selector": { + "type": "string", + "id": 1 + }, + "get": { + "type": "string", + "id": 2 + }, + "put": { + "type": "string", + "id": 3 + }, + "post": { + "type": "string", + "id": 4 + }, + "delete": { + "type": "string", + "id": 5 + }, + "patch": { + "type": "string", + "id": 6 + }, + "custom": { + "type": "CustomHttpPattern", + "id": 8 + }, + "body": { + "type": "string", + "id": 7 + }, + "responseBody": { + "type": "string", + "id": 12 + }, + "additionalBindings": { + "rule": "repeated", + "type": "HttpRule", + "id": 11 + } + } + }, + "CustomHttpPattern": { + "fields": { + "kind": { + "type": "string", + "id": 1 + }, + "path": { + "type": "string", + "id": 2 + } + } + }, + "methodSignature": { + "rule": "repeated", + "type": "string", + "id": 1051, + "extend": "google.protobuf.MethodOptions" + }, + "defaultHost": { + "type": "string", + "id": 1049, + "extend": "google.protobuf.ServiceOptions" + }, + "oauthScopes": { + "type": "string", + "id": 1050, + "extend": "google.protobuf.ServiceOptions" + }, + "apiVersion": { + "type": "string", + "id": 525000001, + "extend": "google.protobuf.ServiceOptions" + }, + "CommonLanguageSettings": { + "fields": { + "referenceDocsUri": { + "type": "string", + "id": 1, + "options": { + "deprecated": true + } + }, + "destinations": { + "rule": "repeated", + "type": "ClientLibraryDestination", + "id": 2 + } + } + }, + "ClientLibrarySettings": { + "fields": { + "version": { + "type": "string", + "id": 1 + }, + "launchStage": { + "type": "LaunchStage", + "id": 2 + }, + "restNumericEnums": { + "type": "bool", + "id": 3 + }, + "javaSettings": { + "type": "JavaSettings", + "id": 21 + }, + "cppSettings": { + "type": "CppSettings", + "id": 22 + }, + "phpSettings": { + "type": "PhpSettings", + "id": 23 + }, + "pythonSettings": { + "type": "PythonSettings", + "id": 24 + }, + "nodeSettings": { + "type": "NodeSettings", + "id": 25 + }, + "dotnetSettings": { + "type": "DotnetSettings", + "id": 26 + }, + "rubySettings": { + "type": "RubySettings", + "id": 27 + }, + "goSettings": { + "type": "GoSettings", + "id": 28 + } + } + }, + "Publishing": { + "fields": { + "methodSettings": { + "rule": "repeated", + "type": "MethodSettings", + "id": 2 + }, + "newIssueUri": { + "type": "string", + "id": 101 + }, + "documentationUri": { + "type": "string", + "id": 102 + }, + "apiShortName": { + "type": "string", + "id": 103 + }, + "githubLabel": { + "type": "string", + "id": 104 + }, + "codeownerGithubTeams": { + "rule": "repeated", + "type": "string", + "id": 105 + }, + "docTagPrefix": { + "type": "string", + "id": 106 + }, + "organization": { + "type": "ClientLibraryOrganization", + "id": 107 + }, + "librarySettings": { + "rule": "repeated", + "type": "ClientLibrarySettings", + "id": 109 + }, + "protoReferenceDocumentationUri": { + "type": "string", + "id": 110 + }, + "restReferenceDocumentationUri": { + "type": "string", + "id": 111 + } + } + }, + "JavaSettings": { + "fields": { + "libraryPackage": { + "type": "string", + "id": 1 + }, + "serviceClassNames": { + "keyType": "string", + "type": "string", + "id": 2 + }, + "common": { + "type": "CommonLanguageSettings", + "id": 3 + } + } + }, + "CppSettings": { + "fields": { + "common": { + "type": "CommonLanguageSettings", + "id": 1 + } + } + }, + "PhpSettings": { + "fields": { + "common": { + "type": "CommonLanguageSettings", + "id": 1 + } + } + }, + "PythonSettings": { + "fields": { + "common": { + "type": "CommonLanguageSettings", + "id": 1 + }, + "experimentalFeatures": { + "type": "ExperimentalFeatures", + "id": 2 + } + }, + "nested": { + "ExperimentalFeatures": { + "fields": { + "restAsyncIoEnabled": { + "type": "bool", + "id": 1 + } + } + } + } + }, + "NodeSettings": { + "fields": { + "common": { + "type": "CommonLanguageSettings", + "id": 1 + } + } + }, + "DotnetSettings": { + "fields": { + "common": { + "type": "CommonLanguageSettings", + "id": 1 + }, + "renamedServices": { + "keyType": "string", + "type": "string", + "id": 2 + }, + "renamedResources": { + "keyType": "string", + "type": "string", + "id": 3 + }, + "ignoredResources": { + "rule": "repeated", + "type": "string", + "id": 4 + }, + "forcedNamespaceAliases": { + "rule": "repeated", + "type": "string", + "id": 5 + }, + "handwrittenSignatures": { + "rule": "repeated", + "type": "string", + "id": 6 + } + } + }, + "RubySettings": { + "fields": { + "common": { + "type": "CommonLanguageSettings", + "id": 1 + } + } + }, + "GoSettings": { + "fields": { + "common": { + "type": "CommonLanguageSettings", + "id": 1 + } + } + }, + "MethodSettings": { + "fields": { + "selector": { + "type": "string", + "id": 1 + }, + "longRunning": { + "type": "LongRunning", + "id": 2 + }, + "autoPopulatedFields": { + "rule": "repeated", + "type": "string", + "id": 3 + } + }, + "nested": { + "LongRunning": { + "fields": { + "initialPollDelay": { + "type": "google.protobuf.Duration", + "id": 1 + }, + "pollDelayMultiplier": { + "type": "float", + "id": 2 + }, + "maxPollDelay": { + "type": "google.protobuf.Duration", + "id": 3 + }, + "totalPollTimeout": { + "type": "google.protobuf.Duration", + "id": 4 + } + } + } + } + }, + "ClientLibraryOrganization": { + "values": { + "CLIENT_LIBRARY_ORGANIZATION_UNSPECIFIED": 0, + "CLOUD": 1, + "ADS": 2, + "PHOTOS": 3, + "STREET_VIEW": 4, + "SHOPPING": 5, + "GEO": 6, + "GENERATIVE_AI": 7 + } + }, + "ClientLibraryDestination": { + "values": { + "CLIENT_LIBRARY_DESTINATION_UNSPECIFIED": 0, + "GITHUB": 10, + "PACKAGE_MANAGER": 20 + } + }, + "LaunchStage": { + "values": { + "LAUNCH_STAGE_UNSPECIFIED": 0, + "UNIMPLEMENTED": 6, + "PRELAUNCH": 7, + "EARLY_ACCESS": 1, + "ALPHA": 2, + "BETA": 3, + "GA": 4, + "DEPRECATED": 5 + } + } + } + }, + "protobuf": { + "options": { + "go_package": "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor", + "java_package": "com.google.protobuf", + "java_outer_classname": "DescriptorProtos", + "csharp_namespace": "Google.Protobuf.Reflection", + "objc_class_prefix": "GPB", + "cc_enable_arenas": true, + "optimize_for": "SPEED" + }, + "nested": { + "FileDescriptorSet": { + "fields": { + "file": { + "rule": "repeated", + "type": "FileDescriptorProto", + "id": 1 + } + } + }, + "FileDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "package": { + "type": "string", + "id": 2 + }, + "dependency": { + "rule": "repeated", + "type": "string", + "id": 3 + }, + "publicDependency": { + "rule": "repeated", + "type": "int32", + "id": 10, + "options": { + "packed": false + } + }, + "weakDependency": { + "rule": "repeated", + "type": "int32", + "id": 11, + "options": { + "packed": false + } + }, + "messageType": { + "rule": "repeated", + "type": "DescriptorProto", + "id": 4 + }, + "enumType": { + "rule": "repeated", + "type": "EnumDescriptorProto", + "id": 5 + }, + "service": { + "rule": "repeated", + "type": "ServiceDescriptorProto", + "id": 6 + }, + "extension": { + "rule": "repeated", + "type": "FieldDescriptorProto", + "id": 7 + }, + "options": { + "type": "FileOptions", + "id": 8 + }, + "sourceCodeInfo": { + "type": "SourceCodeInfo", + "id": 9 + }, + "syntax": { + "type": "string", + "id": 12 + } + } + }, + "DescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "field": { + "rule": "repeated", + "type": "FieldDescriptorProto", + "id": 2 + }, + "extension": { + "rule": "repeated", + "type": "FieldDescriptorProto", + "id": 6 + }, + "nestedType": { + "rule": "repeated", + "type": "DescriptorProto", + "id": 3 + }, + "enumType": { + "rule": "repeated", + "type": "EnumDescriptorProto", + "id": 4 + }, + "extensionRange": { + "rule": "repeated", + "type": "ExtensionRange", + "id": 5 + }, + "oneofDecl": { + "rule": "repeated", + "type": "OneofDescriptorProto", + "id": 8 + }, + "options": { + "type": "MessageOptions", + "id": 7 + }, + "reservedRange": { + "rule": "repeated", + "type": "ReservedRange", + "id": 9 + }, + "reservedName": { + "rule": "repeated", + "type": "string", + "id": 10 + } + }, + "nested": { + "ExtensionRange": { + "fields": { + "start": { + "type": "int32", + "id": 1 + }, + "end": { + "type": "int32", + "id": 2 + }, + "options": { + "type": "ExtensionRangeOptions", + "id": 3 + } + } + }, + "ReservedRange": { + "fields": { + "start": { + "type": "int32", + "id": 1 + }, + "end": { + "type": "int32", + "id": 2 + } + } + } + } + }, + "ExtensionRangeOptions": { + "fields": { + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ] + }, + "FieldDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "number": { + "type": "int32", + "id": 3 + }, + "label": { + "type": "Label", + "id": 4 + }, + "type": { + "type": "Type", + "id": 5 + }, + "typeName": { + "type": "string", + "id": 6 + }, + "extendee": { + "type": "string", + "id": 2 + }, + "defaultValue": { + "type": "string", + "id": 7 + }, + "oneofIndex": { + "type": "int32", + "id": 9 + }, + "jsonName": { + "type": "string", + "id": 10 + }, + "options": { + "type": "FieldOptions", + "id": 8 + } + }, + "nested": { + "Type": { + "values": { + "TYPE_DOUBLE": 1, + "TYPE_FLOAT": 2, + "TYPE_INT64": 3, + "TYPE_UINT64": 4, + "TYPE_INT32": 5, + "TYPE_FIXED64": 6, + "TYPE_FIXED32": 7, + "TYPE_BOOL": 8, + "TYPE_STRING": 9, + "TYPE_GROUP": 10, + "TYPE_MESSAGE": 11, + "TYPE_BYTES": 12, + "TYPE_UINT32": 13, + "TYPE_ENUM": 14, + "TYPE_SFIXED32": 15, + "TYPE_SFIXED64": 16, + "TYPE_SINT32": 17, + "TYPE_SINT64": 18 + } + }, + "Label": { + "values": { + "LABEL_OPTIONAL": 1, + "LABEL_REQUIRED": 2, + "LABEL_REPEATED": 3 + } + } + } + }, + "OneofDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "options": { + "type": "OneofOptions", + "id": 2 + } + } + }, + "EnumDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "value": { + "rule": "repeated", + "type": "EnumValueDescriptorProto", + "id": 2 + }, + "options": { + "type": "EnumOptions", + "id": 3 + }, + "reservedRange": { + "rule": "repeated", + "type": "EnumReservedRange", + "id": 4 + }, + "reservedName": { + "rule": "repeated", + "type": "string", + "id": 5 + } + }, + "nested": { + "EnumReservedRange": { + "fields": { + "start": { + "type": "int32", + "id": 1 + }, + "end": { + "type": "int32", + "id": 2 + } + } + } + } + }, + "EnumValueDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "number": { + "type": "int32", + "id": 2 + }, + "options": { + "type": "EnumValueOptions", + "id": 3 + } + } + }, + "ServiceDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "method": { + "rule": "repeated", + "type": "MethodDescriptorProto", + "id": 2 + }, + "options": { + "type": "ServiceOptions", + "id": 3 + } + } + }, + "MethodDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "inputType": { + "type": "string", + "id": 2 + }, + "outputType": { + "type": "string", + "id": 3 + }, + "options": { + "type": "MethodOptions", + "id": 4 + }, + "clientStreaming": { + "type": "bool", + "id": 5, + "options": { + "default": false + } + }, + "serverStreaming": { + "type": "bool", + "id": 6, + "options": { + "default": false + } + } + } + }, + "FileOptions": { + "fields": { + "javaPackage": { + "type": "string", + "id": 1 + }, + "javaOuterClassname": { + "type": "string", + "id": 8 + }, + "javaMultipleFiles": { + "type": "bool", + "id": 10, + "options": { + "default": false + } + }, + "javaGenerateEqualsAndHash": { + "type": "bool", + "id": 20, + "options": { + "deprecated": true + } + }, + "javaStringCheckUtf8": { + "type": "bool", + "id": 27, + "options": { + "default": false + } + }, + "optimizeFor": { + "type": "OptimizeMode", + "id": 9, + "options": { + "default": "SPEED" + } + }, + "goPackage": { + "type": "string", + "id": 11 + }, + "ccGenericServices": { + "type": "bool", + "id": 16, + "options": { + "default": false + } + }, + "javaGenericServices": { + "type": "bool", + "id": 17, + "options": { + "default": false + } + }, + "pyGenericServices": { + "type": "bool", + "id": 18, + "options": { + "default": false + } + }, + "phpGenericServices": { + "type": "bool", + "id": 42, + "options": { + "default": false + } + }, + "deprecated": { + "type": "bool", + "id": 23, + "options": { + "default": false + } + }, + "ccEnableArenas": { + "type": "bool", + "id": 31, + "options": { + "default": false + } + }, + "objcClassPrefix": { + "type": "string", + "id": 36 + }, + "csharpNamespace": { + "type": "string", + "id": 37 + }, + "swiftPrefix": { + "type": "string", + "id": 39 + }, + "phpClassPrefix": { + "type": "string", + "id": 40 + }, + "phpNamespace": { + "type": "string", + "id": 41 + }, + "phpMetadataNamespace": { + "type": "string", + "id": 44 + }, + "rubyPackage": { + "type": "string", + "id": 45 + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ], + "reserved": [ + [ + 38, + 38 + ] + ], + "nested": { + "OptimizeMode": { + "values": { + "SPEED": 1, + "CODE_SIZE": 2, + "LITE_RUNTIME": 3 + } + } + } + }, + "MessageOptions": { + "fields": { + "messageSetWireFormat": { + "type": "bool", + "id": 1, + "options": { + "default": false + } + }, + "noStandardDescriptorAccessor": { + "type": "bool", + "id": 2, + "options": { + "default": false + } + }, + "deprecated": { + "type": "bool", + "id": 3, + "options": { + "default": false + } + }, + "mapEntry": { + "type": "bool", + "id": 7 + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ], + "reserved": [ + [ + 8, + 8 + ], + [ + 9, + 9 + ] + ] + }, + "FieldOptions": { + "fields": { + "ctype": { + "type": "CType", + "id": 1, + "options": { + "default": "STRING" + } + }, + "packed": { + "type": "bool", + "id": 2 + }, + "jstype": { + "type": "JSType", + "id": 6, + "options": { + "default": "JS_NORMAL" + } + }, + "lazy": { + "type": "bool", + "id": 5, + "options": { + "default": false + } + }, + "deprecated": { + "type": "bool", + "id": 3, + "options": { + "default": false + } + }, + "weak": { + "type": "bool", + "id": 10, + "options": { + "default": false + } + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ], + "reserved": [ + [ + 4, + 4 + ] + ], + "nested": { + "CType": { + "values": { + "STRING": 0, + "CORD": 1, + "STRING_PIECE": 2 + } + }, + "JSType": { + "values": { + "JS_NORMAL": 0, + "JS_STRING": 1, + "JS_NUMBER": 2 + } + } + } + }, + "OneofOptions": { + "fields": { + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ] + }, + "EnumOptions": { + "fields": { + "allowAlias": { + "type": "bool", + "id": 2 + }, + "deprecated": { + "type": "bool", + "id": 3, + "options": { + "default": false + } + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ], + "reserved": [ + [ + 5, + 5 + ] + ] + }, + "EnumValueOptions": { + "fields": { + "deprecated": { + "type": "bool", + "id": 1, + "options": { + "default": false + } + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ] + }, + "ServiceOptions": { + "fields": { + "deprecated": { + "type": "bool", + "id": 33, + "options": { + "default": false + } + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ] + }, + "MethodOptions": { + "fields": { + "deprecated": { + "type": "bool", + "id": 33, + "options": { + "default": false } }, - "Write": { - "oneofs": { - "operation": { - "oneof": [ - "update", - "delete", - "verify", - "transform" - ] - } - }, - "fields": { - "update": { - "type": "Document", - "id": 1 - }, - "delete": { - "type": "string", - "id": 2 - }, - "verify": { - "type": "string", - "id": 5 - }, - "transform": { - "type": "DocumentTransform", - "id": 6 - }, - "updateMask": { - "type": "DocumentMask", - "id": 3 - }, - "updateTransforms": { - "rule": "repeated", - "type": "DocumentTransform.FieldTransform", - "id": 7 - }, - "currentDocument": { - "type": "Precondition", - "id": 4 - } + "idempotencyLevel": { + "type": "IdempotencyLevel", + "id": 34, + "options": { + "default": "IDEMPOTENCY_UNKNOWN" } }, - "DocumentTransform": { - "fields": { - "document": { - "type": "string", - "id": 1 - }, - "fieldTransforms": { - "rule": "repeated", - "type": "FieldTransform", - "id": 2 - } - }, - "nested": { - "FieldTransform": { - "oneofs": { - "transformType": { - "oneof": [ - "setToServerValue", - "increment", - "maximum", - "minimum", - "appendMissingElements", - "removeAllFromArray" - ] - } - }, - "fields": { - "fieldPath": { - "type": "string", - "id": 1 - }, - "setToServerValue": { - "type": "ServerValue", - "id": 2 - }, - "increment": { - "type": "Value", - "id": 3 - }, - "maximum": { - "type": "Value", - "id": 4 - }, - "minimum": { - "type": "Value", - "id": 5 - }, - "appendMissingElements": { - "type": "ArrayValue", - "id": 6 - }, - "removeAllFromArray": { - "type": "ArrayValue", - "id": 7 - } - }, - "nested": { - "ServerValue": { - "values": { - "SERVER_VALUE_UNSPECIFIED": 0, - "REQUEST_TIME": 1 - } - } - } - } + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ], + "nested": { + "IdempotencyLevel": { + "values": { + "IDEMPOTENCY_UNKNOWN": 0, + "NO_SIDE_EFFECTS": 1, + "IDEMPOTENT": 2 } + } + } + }, + "UninterpretedOption": { + "fields": { + "name": { + "rule": "repeated", + "type": "NamePart", + "id": 2 }, - "WriteResult": { - "fields": { - "updateTime": { - "type": "google.protobuf.Timestamp", - "id": 1 - }, - "transformResults": { - "rule": "repeated", - "type": "Value", - "id": 2 - } - } + "identifierValue": { + "type": "string", + "id": 3 }, - "DocumentChange": { - "fields": { - "document": { - "type": "Document", - "id": 1 - }, - "targetIds": { - "rule": "repeated", - "type": "int32", - "id": 5 - }, - "removedTargetIds": { - "rule": "repeated", - "type": "int32", - "id": 6 - } - } + "positiveIntValue": { + "type": "uint64", + "id": 4 }, - "DocumentDelete": { + "negativeIntValue": { + "type": "int64", + "id": 5 + }, + "doubleValue": { + "type": "double", + "id": 6 + }, + "stringValue": { + "type": "bytes", + "id": 7 + }, + "aggregateValue": { + "type": "string", + "id": 8 + } + }, + "nested": { + "NamePart": { "fields": { - "document": { + "namePart": { + "rule": "required", "type": "string", "id": 1 }, - "removedTargetIds": { - "rule": "repeated", - "type": "int32", - "id": 6 - }, - "readTime": { - "type": "google.protobuf.Timestamp", - "id": 4 + "isExtension": { + "rule": "required", + "type": "bool", + "id": 2 } } - }, - "DocumentRemove": { + } + } + }, + "SourceCodeInfo": { + "fields": { + "location": { + "rule": "repeated", + "type": "Location", + "id": 1 + } + }, + "nested": { + "Location": { "fields": { - "document": { - "type": "string", + "path": { + "rule": "repeated", + "type": "int32", "id": 1 }, - "removedTargetIds": { + "span": { "rule": "repeated", "type": "int32", "id": 2 }, - "readTime": { - "type": "google.protobuf.Timestamp", + "leadingComments": { + "type": "string", + "id": 3 + }, + "trailingComments": { + "type": "string", "id": 4 + }, + "leadingDetachedComments": { + "rule": "repeated", + "type": "string", + "id": 6 } } - }, - "ExistenceFilter": { + } + } + }, + "GeneratedCodeInfo": { + "fields": { + "annotation": { + "rule": "repeated", + "type": "Annotation", + "id": 1 + } + }, + "nested": { + "Annotation": { "fields": { - "targetId": { + "path": { + "rule": "repeated", "type": "int32", "id": 1 }, - "count": { - "type": "int32", + "sourceFile": { + "type": "string", "id": 2 }, - "unchangedNames": { - "type": "BloomFilter", + "begin": { + "type": "int32", "id": 3 + }, + "end": { + "type": "int32", + "id": 4 } } } } - } - } - }, - "api": { - "options": { - "go_package": "google.golang.org/genproto/googleapis/api/annotations;annotations", - "java_multiple_files": true, - "java_outer_classname": "HttpProto", - "java_package": "com.google.api", - "objc_class_prefix": "GAPI", - "cc_enable_arenas": true - }, - "nested": { - "http": { - "type": "HttpRule", - "id": 72295728, - "extend": "google.protobuf.MethodOptions" }, - "Http": { + "Struct": { "fields": { - "rules": { - "rule": "repeated", - "type": "HttpRule", + "fields": { + "keyType": "string", + "type": "Value", "id": 1 } } }, - "HttpRule": { + "Value": { "oneofs": { - "pattern": { + "kind": { "oneof": [ - "get", - "put", - "post", - "delete", - "patch", - "custom" + "nullValue", + "numberValue", + "stringValue", + "boolValue", + "structValue", + "listValue" ] } }, "fields": { - "get": { - "type": "string", + "nullValue": { + "type": "NullValue", + "id": 1 + }, + "numberValue": { + "type": "double", "id": 2 }, - "put": { + "stringValue": { "type": "string", "id": 3 }, - "post": { - "type": "string", + "boolValue": { + "type": "bool", "id": 4 }, - "delete": { - "type": "string", + "structValue": { + "type": "Struct", "id": 5 }, - "patch": { - "type": "string", + "listValue": { + "type": "ListValue", "id": 6 - }, - "custom": { - "type": "CustomHttpPattern", - "id": 8 - }, - "selector": { - "type": "string", + } + } + }, + "NullValue": { + "values": { + "NULL_VALUE": 0 + } + }, + "ListValue": { + "fields": { + "values": { + "rule": "repeated", + "type": "Value", + "id": 1 + } + } + }, + "Timestamp": { + "fields": { + "seconds": { + "type": "int64", "id": 1 }, - "body": { - "type": "string", - "id": 7 - }, - "additionalBindings": { - "rule": "repeated", - "type": "HttpRule", - "id": 11 + "nanos": { + "type": "int32", + "id": 2 } } }, - "CustomHttpPattern": { + "Duration": { "fields": { - "kind": { - "type": "string", + "seconds": { + "type": "int64", "id": 1 }, - "path": { - "type": "string", + "nanos": { + "type": "int32", "id": 2 } } }, - "methodSignature": { - "rule": "repeated", - "type": "string", - "id": 1051, - "extend": "google.protobuf.MethodOptions" + "DoubleValue": { + "fields": { + "value": { + "type": "double", + "id": 1 + } + } }, - "defaultHost": { - "type": "string", - "id": 1049, - "extend": "google.protobuf.ServiceOptions" + "FloatValue": { + "fields": { + "value": { + "type": "float", + "id": 1 + } + } }, - "oauthScopes": { - "type": "string", - "id": 1050, - "extend": "google.protobuf.ServiceOptions" + "Int64Value": { + "fields": { + "value": { + "type": "int64", + "id": 1 + } + } }, - "fieldBehavior": { - "rule": "repeated", - "type": "google.api.FieldBehavior", - "id": 1052, - "extend": "google.protobuf.FieldOptions" + "UInt64Value": { + "fields": { + "value": { + "type": "uint64", + "id": 1 + } + } }, - "FieldBehavior": { - "values": { - "FIELD_BEHAVIOR_UNSPECIFIED": 0, - "OPTIONAL": 1, - "REQUIRED": 2, - "OUTPUT_ONLY": 3, - "INPUT_ONLY": 4, - "IMMUTABLE": 5, - "UNORDERED_LIST": 6, - "NON_EMPTY_DEFAULT": 7 + "Int32Value": { + "fields": { + "value": { + "type": "int32", + "id": 1 + } + } + }, + "UInt32Value": { + "fields": { + "value": { + "type": "uint32", + "id": 1 + } + } + }, + "BoolValue": { + "fields": { + "value": { + "type": "bool", + "id": 1 + } + } + }, + "StringValue": { + "fields": { + "value": { + "type": "string", + "id": 1 + } + } + }, + "BytesValue": { + "fields": { + "value": { + "type": "bytes", + "id": 1 + } + } + }, + "Empty": { + "fields": {} + }, + "Any": { + "fields": { + "type_url": { + "type": "string", + "id": 1 + }, + "value": { + "type": "bytes", + "id": 2 + } } } } @@ -2880,4 +3551,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/firestore/src/protos/update.sh b/packages/firestore/src/protos/update.sh index 9f2ea2bce05..db22e8ab907 100755 --- a/packages/firestore/src/protos/update.sh +++ b/packages/firestore/src/protos/update.sh @@ -20,7 +20,8 @@ IFS=$'\n\t' # Variables PROTOS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" WORK_DIR=`mktemp -d` -PBJS="$(npm bin)/pbjs" +PBJS="$(pwd)/../../node_modules/.bin/pbjs" +PBTS="$(pwd)/../../node_modules/.bin/pbts" # deletes the temp directory on exit function cleanup { @@ -40,7 +41,7 @@ git clone --depth 1 https://github.com/google/protobuf.git # Copy necessary protos. mkdir -p "${PROTOS_DIR}/google/api" -cp googleapis/google/api/{annotations.proto,http.proto,client.proto,field_behavior.proto} \ +cp googleapis/google/api/{annotations.proto,http.proto,client.proto,field_behavior.proto,launch_stage.proto} \ "${PROTOS_DIR}/google/api/" mkdir -p "${PROTOS_DIR}/google/firestore/v1" @@ -67,10 +68,18 @@ ex "${PROTOS_DIR}/google/firestore/v1/write.proto" < { + const datastoreImpl = debugCast(datastore, DatastoreImpl); + const { queryTarget, parent } = toVectorQueryTarget( + datastoreImpl.serializer, + vectorQuery, + queryToAggregateTarget(vectorQuery.query) + ); + return invokeRunQueryRpcRequest(datastoreImpl, queryTarget, parent); +} + +async function invokeRunQueryRpcRequest( + datastoreImpl: DatastoreImpl, + queryTarget: ProtoRunQueryRequest, + parent: ResourcePath +): Promise { + const runQueryRequest: firestoreV1ApiClientInterfaces.RunQueryRequest = { + structuredQuery: queryTarget.structuredQuery + }; + + if (datastoreImpl.connection.shouldResourcePathBeIncludedInRequest) { + runQueryRequest.parent = queryTarget.parent; + } + const response = await datastoreImpl.invokeStreamingRPC< ProtoRunQueryRequest, ProtoRunQueryResponse - >('RunQuery', datastoreImpl.serializer.databaseId, parent, { - structuredQuery: queryTarget.structuredQuery - }); + >('RunQuery', datastoreImpl.serializer.databaseId, parent, runQueryRequest); + return ( response // Omit RunQueryResponses that only contain readTimes. @@ -274,6 +305,7 @@ export async function invokeRunAggregationQueryRpc( if (!datastoreImpl.connection.shouldResourcePathBeIncludedInRequest) { delete request.parent; } + const response = await datastoreImpl.invokeStreamingRPC< ProtoRunAggregationQueryRequest, ProtoRunAggregationQueryResponse diff --git a/packages/firestore/src/remote/serializer.ts b/packages/firestore/src/remote/serializer.ts index 811c2ac4df6..dc0c2c4989e 100644 --- a/packages/firestore/src/remote/serializer.ts +++ b/packages/firestore/src/remote/serializer.ts @@ -37,6 +37,7 @@ import { import { SnapshotVersion } from '../core/snapshot_version'; import { targetIsDocumentTarget, Target } from '../core/target'; import { TargetId } from '../core/types'; +import { VectorQuery } from '../core/vector_query'; import { Timestamp } from '../lite-api/timestamp'; import { TargetData, TargetPurpose } from '../local/target_data'; import { MutableDocument } from '../model/document'; @@ -87,7 +88,8 @@ import { TargetChangeTargetChangeType as ProtoTargetChangeTargetChangeType, Timestamp as ProtoTimestamp, Write as ProtoWrite, - WriteResult as ProtoWriteResult + WriteResult as ProtoWriteResult, + FindNearest as ProtoFindNearest } from '../protos/firestore_proto_api'; import { debugAssert, fail, hardAssert } from '../util/assert'; import { ByteString } from '../util/byte_string'; @@ -844,6 +846,39 @@ export function fromDocumentsTarget( const name = documentsTarget.documents![0]; return queryToTarget(newQueryForPath(fromQueryPath(name))); } +export function toVectorQueryTarget( + serializer: JsonProtoSerializer, + vectorQuery: VectorQuery, + target: Target +): { queryTarget: ProtoQueryTarget; parent: ResourcePath } { + const { queryTarget, parent } = toQueryTarget(serializer, target); + + const findNearest: ProtoFindNearest = {}; + const limit = toInt32Proto(serializer, vectorQuery.limit); + + if (limit != null) { + findNearest.limit = limit; + } + + findNearest.distanceMeasure = vectorQuery.distanceMeasure; + findNearest.vectorField = toFieldPathReference(vectorQuery.vectorField); + findNearest.queryVector = vectorQuery.queryVector.value; + + if (vectorQuery.distanceResultField) { + findNearest.distanceResultField = + vectorQuery.distanceResultField.canonicalString(); + } + + if (vectorQuery.distanceThreshold !== undefined) { + findNearest.distanceThreshold = toInt32Proto( + serializer, + vectorQuery.distanceThreshold + )!; + } + queryTarget.structuredQuery!.findNearest = findNearest; + + return { queryTarget, parent }; +} export function toQueryTarget( serializer: JsonProtoSerializer, diff --git a/packages/firestore/test/integration/api/aggregation.test.ts b/packages/firestore/test/integration/api/aggregation.test.ts index ba44dddf514..b5c223da9fd 100644 --- a/packages/firestore/test/integration/api/aggregation.test.ts +++ b/packages/firestore/test/integration/api/aggregation.test.ts @@ -34,7 +34,8 @@ import { count, sum, average, - addDoc + addDoc, + setLogLevel } from '../util/firebase_export'; import { apiDescribe, diff --git a/packages/firestore/test/integration/api/vector_query.test.ts b/packages/firestore/test/integration/api/vector_query.test.ts new file mode 100644 index 00000000000..6110bd5c7d2 --- /dev/null +++ b/packages/firestore/test/integration/api/vector_query.test.ts @@ -0,0 +1,82 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'chai'; + +import { setDoc } from '../../../src/lite-api/reference_impl'; +import { AutoId } from '../../../src/util/misc'; +import { + query, + where, + vector, + findNearest, + getDocsFromServer, + collection, + DocumentData, + doc, + ensureFirestoreConfigured +} from '../util/firebase_export'; +import { apiDescribe, withTestDb } from '../util/helpers'; + +apiDescribe('vector search', persistence => { + it('supports findNearest by EUCLIDEAN distance', async () => { + const testId = AutoId.newId(); + + return withTestDb(persistence, async firestore => { + ensureFirestoreConfigured(firestore); + + const collectionReference = collection( + firestore, + 'index-test-collection' + ); + const docs: Record = { + a: { foo: 'bar', testId }, + b: { foo: 'xxx', testId, embedding: vector([10, 10]) }, + c: { foo: 'bar', testId, embedding: vector([1, 1]) }, + d: { foo: 'bar', testId, embedding: vector([10, 0]) }, + e: { foo: 'bar', testId, embedding: vector([20, 0]) }, + f: { foo: 'bar', testId, embedding: vector([100, 100]) } + }; + + for (const docId in docs) { + if (!docs.hasOwnProperty(docId)) { + continue; + } + await setDoc(doc(collectionReference, docId), docs[docId]); + } + + const baseQuery = query( + collectionReference, + where('foo', '==', 'bar'), + where('testId', '==', testId) + ); + + const vectorQuery = findNearest(baseQuery, { + vectorField: 'embedding', + queryVector: [10, 10], + limit: 3, + distanceMeasure: 'EUCLIDEAN' + }); + + const res = await getDocsFromServer(vectorQuery); + expect(res.size).to.equal(3); + expect(res.docs[0].id).to.equal('d'); + expect(res.docs[1].id).to.equal('c'); + expect(res.docs[2].id).to.equal('e'); + }); + }); +}); diff --git a/packages/firestore/test/lite/helpers.ts b/packages/firestore/test/lite/helpers.ts index 4dbd43ab955..ae7c7ef0c30 100644 --- a/packages/firestore/test/lite/helpers.ts +++ b/packages/firestore/test/lite/helpers.ts @@ -94,6 +94,22 @@ export function withTestCollectionAndInitialData( }); } +export function withTestCollectionAndNamedDocuments( + data: Record, + fn: (collRef: CollectionReference) => void | Promise +): Promise { + return withTestDb(async db => { + const coll = collection(db, AutoId.newId()); + for (const name in data) { + if (data.hasOwnProperty(name)) { + const ref = doc(coll, name); + await setDoc(ref, data[name]); + } + } + return fn(coll); + }); +} + export function withTestCollection( fn: (collRef: CollectionReference) => void | Promise ): Promise { diff --git a/packages/firestore/test/lite/integration.test.ts b/packages/firestore/test/lite/integration.test.ts index 780db5f4f9c..06141c7e428 100644 --- a/packages/firestore/test/lite/integration.test.ts +++ b/packages/firestore/test/lite/integration.test.ts @@ -45,6 +45,7 @@ import { serverTimestamp, vector } from '../../src/lite-api/field_value_impl'; +import { findNearest } from '../../src/lite-api/find_nearest'; import { endAt, endBefore, @@ -87,6 +88,7 @@ import { import { Timestamp } from '../../src/lite-api/timestamp'; import { runTransaction } from '../../src/lite-api/transaction'; import { writeBatch } from '../../src/lite-api/write_batch'; +import { AutoId } from '../../src/util/misc'; import { apiDescribe } from '../integration/util/helpers'; import { DEFAULT_PROJECT_ID, @@ -434,21 +436,25 @@ interface MutationTester { documentRef: DocumentReference, data: WithFieldValue ): Promise; + set( documentRef: DocumentReference, data: PartialWithFieldValue, options: SetOptions ): Promise; + update( documentRef: DocumentReference, data: UpdateData ): Promise; + update( documentRef: DocumentReference, field: string | FieldPath, value: unknown, ...moreFieldsAndValues: unknown[] ): Promise; + delete( documentRef: DocumentReference ): Promise; @@ -1765,6 +1771,7 @@ describe('withConverter() support', () => { id: string; foo: number; } + const foo = new ObjectWrapper(); foo.withFieldValueT({ id: '', foo: increment(1) }); foo.withPartialFieldValueT({ foo: increment(1) }); @@ -2960,3 +2967,48 @@ describe('Vectors', () => { }); }); }); + +apiDescribe('Vector Query', persistence => { + it('supports findNearest by EUCLIDEAN distance', async () => { + const testId = AutoId.newId(); + return withTestDb(async firestore => { + const collectionReference = collection( + firestore, + 'index-test-collection' + ); + const docs: Record = { + a: { foo: 'bar', testId }, + b: { foo: 'xxx', testId, embedding: vector([10, 10]) }, + c: { foo: 'bar', testId, embedding: vector([1, 1]) }, + d: { foo: 'bar', testId, embedding: vector([10, 0]) }, + e: { foo: 'bar', testId, embedding: vector([20, 0]) }, + f: { foo: 'bar', testId, embedding: vector([100, 100]) } + }; + + for (const docId in docs) { + if (!docs.hasOwnProperty(docId)) { + continue; + } + await setDoc(doc(collectionReference, docId), docs[docId]); + } + + const baseQuery = query( + collectionReference, + where('foo', '==', 'bar'), + where('testId', '==', testId) + ); + + const vectorQuery = findNearest(baseQuery, { + vectorField: 'embedding', + queryVector: [10, 10], + limit: 3, + distanceMeasure: 'EUCLIDEAN' + }); + const res = await getDocs(vectorQuery); + expect(res.size).to.equal(3); + expect(res.docs[0].id).to.equal('d'); + expect(res.docs[1].id).to.equal('c'); + expect(res.docs[2].id).to.equal('e'); + }); + }).timeout(100000); +}); diff --git a/yarn.lock b/yarn.lock index 477e784871e..e227b4e057e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -430,6 +430,11 @@ resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== +"@babel/helper-string-parser@^7.24.8": + version "7.24.8" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" + integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== + "@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.22.20", "@babel/helper-validator-identifier@^7.22.5": version "7.22.20" resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" @@ -450,6 +455,11 @@ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz#918b1a7fa23056603506370089bd990d8720db62" integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA== +"@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + "@babel/helper-validator-option@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz" @@ -525,6 +535,13 @@ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz" integrity sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g== +"@babel/parser@^7.20.15": + version "7.25.6" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f" + integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q== + dependencies: + "@babel/types" "^7.25.6" + "@babel/parser@^7.24.0", "@babel/parser@^7.24.1": version "7.24.1" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz#1e416d3627393fab1cb5b0f2f1796a100ae9133a" @@ -1364,6 +1381,15 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@babel/types@^7.25.6": + version "7.25.6" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6" + integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw== + dependencies: + "@babel/helper-string-parser" "^7.24.8" + "@babel/helper-validator-identifier" "^7.24.7" + to-fast-properties "^2.0.0" + "@changesets/apply-release-plan@^6.1.4": version "6.1.4" resolved "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-6.1.4.tgz" @@ -1928,6 +1954,13 @@ resolved "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz" integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== +"@jsdoc/salty@^0.2.1": + version "0.2.8" + resolved "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.8.tgz#8d29923a9429694a437a50ab75004b576131d597" + integrity sha512-5e+SFVavj1ORKlKaKr2BmTOekmXbelU7dC0cDkQLqag7xfuTPuGMUFx7KWJuv4bYZrTsoL2Z18VVCOKYxzoHcg== + dependencies: + lodash "^4.17.21" + "@kwsites/file-exists@^1.1.1": version "1.1.1" resolved "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz" @@ -3435,6 +3468,11 @@ dependencies: "@types/node" "*" +"@types/linkify-it@^5": + version "5.0.0" + resolved "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz#21413001973106cda1c3a9b91eedd4ccd5469d76" + integrity sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q== + "@types/listr@0.14.9": version "0.14.9" resolved "https://registry.npmjs.org/@types/listr/-/listr-0.14.9.tgz#736581cfdfcdb821bace0a3e5b05e91182e00c85" @@ -3448,6 +3486,19 @@ resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== +"@types/markdown-it@^14.1.1": + version "14.1.2" + resolved "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz#57f2532a0800067d9b934f3521429a2e8bfb4c61" + integrity sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog== + dependencies: + "@types/linkify-it" "^5" + "@types/mdurl" "^2" + +"@types/mdurl@^2": + version "2.0.0" + resolved "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz#d43878b5b20222682163ae6f897b20447233bdfd" + integrity sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg== + "@types/mime@*": version "3.0.1" resolved "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz" @@ -5057,7 +5108,7 @@ blocking-proxy@^1.0.0: dependencies: minimist "^1.2.0" -bluebird@3.7.2: +bluebird@3.7.2, bluebird@^3.7.2: version "3.7.2" resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== @@ -5542,6 +5593,13 @@ caseless@~0.12.0: resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +catharsis@^0.9.0: + version "0.9.0" + resolved "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz#40382a168be0e6da308c277d3a2b3eb40c7d2121" + integrity sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A== + dependencies: + lodash "^4.17.15" + chai-as-promised@7.1.1: version "7.1.1" resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz" @@ -7260,6 +7318,11 @@ ent@~2.2.0: resolved "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz" integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= +entities@^4.4.0: + version "4.5.0" + resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + env-paths@^2.2.0: version "2.2.1" resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" @@ -7545,7 +7608,7 @@ escape-string-regexp@^2.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escodegen@^1.8.1: +escodegen@^1.13.0, escodegen@^1.8.1: version "1.14.3" resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== @@ -7684,7 +7747,7 @@ esniff@^2.0.1: event-emitter "^0.3.5" type "^2.7.2" -espree@^9.6.0, espree@^9.6.1: +espree@^9.0.0, espree@^9.6.0, espree@^9.6.1: version "9.6.1" resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== @@ -9056,7 +9119,7 @@ glob@7.2.3, glob@~7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^8.0.1: +glob@^8.0.0, glob@^8.0.1: version "8.1.0" resolved "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz" integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== @@ -9277,7 +9340,7 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0: resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz" integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== -graceful-fs@^4.2.10, graceful-fs@^4.2.9: +graceful-fs@^4.1.9, graceful-fs@^4.2.10, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -11067,11 +11130,39 @@ js-yaml@~3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js2xmlparser@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz#2a1fdf01e90585ef2ae872a01bc169c6a8d5e60a" + integrity sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA== + dependencies: + xmlcreate "^2.0.4" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= +jsdoc@^4.0.0: + version "4.0.3" + resolved "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.3.tgz#bfee86c6a82f6823e12b5e8be698fd99ae46c061" + integrity sha512-Nu7Sf35kXJ1MWDZIMAuATRQTg1iIPdzh7tqJ6jjvaU/GfDf+qi5UV8zJR3Mo+/pYFvm8mzay4+6O5EWigaQBQw== + dependencies: + "@babel/parser" "^7.20.15" + "@jsdoc/salty" "^0.2.1" + "@types/markdown-it" "^14.1.1" + bluebird "^3.7.2" + catharsis "^0.9.0" + escape-string-regexp "^2.0.0" + js2xmlparser "^4.0.2" + klaw "^3.0.0" + markdown-it "^14.1.0" + markdown-it-anchor "^8.6.7" + marked "^4.0.10" + mkdirp "^1.0.4" + requizzle "^0.2.3" + strip-json-comments "^3.1.0" + underscore "~1.13.2" + jsesc@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz" @@ -11484,6 +11575,13 @@ klaw-sync@^6.0.0: dependencies: graceful-fs "^4.1.11" +klaw@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" + integrity sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g== + dependencies: + graceful-fs "^4.1.9" + kleur@^4.1.4: version "4.1.5" resolved "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz" @@ -11642,6 +11740,13 @@ lines-and-columns@^1.1.6: resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= +linkify-it@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421" + integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ== + dependencies: + uc.micro "^2.0.0" + listr-silent-renderer@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz" @@ -12186,6 +12291,23 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +markdown-it-anchor@^8.6.7: + version "8.6.7" + resolved "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz#ee6926daf3ad1ed5e4e3968b1740eef1c6399634" + integrity sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA== + +markdown-it@^14.1.0: + version "14.1.0" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45" + integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg== + dependencies: + argparse "^2.0.1" + entities "^4.4.0" + linkify-it "^5.0.0" + mdurl "^2.0.0" + punycode.js "^2.3.1" + uc.micro "^2.1.0" + marked-terminal@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/marked-terminal/-/marked-terminal-5.1.1.tgz" @@ -12203,6 +12325,11 @@ marked@^0.8.0: resolved "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz" integrity sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw== +marked@^4.0.10: + version "4.3.0" + resolved "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" + integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== + marked@^4.0.14: version "4.0.18" resolved "https://registry.npmjs.org/marked/-/marked-4.0.18.tgz" @@ -12227,6 +12354,11 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" +mdurl@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0" + integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" @@ -14278,6 +14410,22 @@ proto3-json-serializer@^1.0.0: dependencies: protobufjs "^6.11.3" +protobufjs-cli@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/protobufjs-cli/-/protobufjs-cli-1.1.3.tgz#c58b8566784f0fa1aff11e8d875a31de999637fe" + integrity sha512-MqD10lqF+FMsOayFiNOdOGNlXc4iKDCf0ZQPkPR+gizYh9gqUeGTWulABUCdI+N67w5RfJ6xhgX4J8pa8qmMXQ== + dependencies: + chalk "^4.0.0" + escodegen "^1.13.0" + espree "^9.0.0" + estraverse "^5.1.0" + glob "^8.0.0" + jsdoc "^4.0.0" + minimist "^1.2.0" + semver "^7.1.2" + tmp "^0.2.1" + uglify-js "^3.7.7" + protobufjs@6.11.3: version "6.11.3" resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74" @@ -14439,6 +14587,11 @@ pumpify@^1.3.5: inherits "^2.0.3" pump "^2.0.0" +punycode.js@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" + integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== + punycode@1.3.2: version "1.3.2" resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz" @@ -15072,6 +15225,13 @@ requires-port@^1.0.0: resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +requizzle@^0.2.3: + version "0.2.4" + resolved "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz#319eb658b28c370f0c20f968fa8ceab98c13d27c" + integrity sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw== + dependencies: + lodash "^4.17.21" + resolve-alpn@^1.0.0: version "1.2.1" resolved "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz" @@ -15567,7 +15727,7 @@ semver@^7.0.0, semver@^7.1.1, semver@^7.1.3, semver@^7.3.2, semver@^7.3.4, semve dependencies: lru-cache "^6.0.0" -semver@^7.5.4, semver@^7.6.0: +semver@^7.1.2, semver@^7.5.4, semver@^7.6.0: version "7.6.3" resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== @@ -16495,7 +16655,7 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@3.1.1, strip-json-comments@^3.1.1, strip-json-comments@~3.1.1: +strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1, strip-json-comments@~3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -17317,11 +17477,21 @@ ua-parser-js@^0.7.30: resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz#e464e66dac2d33a7a1251d7d7a99d6157ec27832" integrity sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA== +uc.micro@^2.0.0, uc.micro@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" + integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== + uglify-js@^3.1.4, uglify-js@^3.4.9: version "3.14.2" resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz" integrity sha512-rtPMlmcO4agTUfz10CbgJ1k6UAoXM2gWb3GoMPPZB/+/Ackf8lNWk11K4rYi2D0apgoFRLtQOZhb+/iGNJq26A== +uglify-js@^3.7.7: + version "3.19.3" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== + uid-number@0.0.6: version "0.0.6" resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz" @@ -17362,6 +17532,11 @@ underscore@>=1.8.3, underscore@^1.9.1: resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz" integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g== +underscore@~1.13.2: + version "1.13.7" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz#970e33963af9a7dda228f17ebe8399e5fbe63a10" + integrity sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g== + undertaker-registry@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz" @@ -18308,6 +18483,11 @@ xmlbuilder@~11.0.0: resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== +xmlcreate@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz#0c5ab0f99cdd02a81065fa9cd8f8ae87624889be" + integrity sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg== + xregexp@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz"