From f25b9e53e9d77a3f92e36ff62218bbcf24aae857 Mon Sep 17 00:00:00 2001 From: Ehsan Date: Thu, 2 May 2024 16:10:02 -0700 Subject: [PATCH] [internal] Query/AggregateQuery to proto representation (#8177) * WIP: [internal] Query/AggregateQuery to proto representation. * using api classes. * move to a separate file. * Only return the QueryTarget object. * declare interface to avoid minification. * lint fix. * attempt to avoid minification of ToRunAggregationQueryRequestReturnType. * allow skipping aliasing. --- packages/firestore/src/api.ts | 4 + .../src/remote/internal_serializer.ts | 89 +++++++++++++++++++ packages/firestore/src/remote/serializer.ts | 7 +- 3 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 packages/firestore/src/remote/internal_serializer.ts diff --git a/packages/firestore/src/api.ts b/packages/firestore/src/api.ts index bcfa6dc5f34..5f5b078fbd6 100644 --- a/packages/firestore/src/api.ts +++ b/packages/firestore/src/api.ts @@ -219,6 +219,10 @@ export { */ export { isBase64Available as _isBase64Available } from './platform/base64'; export { DatabaseId as _DatabaseId } from './core/database_info'; +export { + _internalQueryToProtoQueryTarget, + _internalAggregationQueryToProtoRunAggregationQueryRequest +} from './remote/internal_serializer'; export { cast as _cast, validateIsNotUsedTogether as _validateIsNotUsedTogether diff --git a/packages/firestore/src/remote/internal_serializer.ts b/packages/firestore/src/remote/internal_serializer.ts new file mode 100644 index 00000000000..8f278247581 --- /dev/null +++ b/packages/firestore/src/remote/internal_serializer.ts @@ -0,0 +1,89 @@ +/** + * @license + * Copyright 2017 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 { ensureFirestoreConfigured, Firestore } from '../api/database'; +import { AggregateImpl } from '../core/aggregate'; +import { queryToAggregateTarget, queryToTarget } from '../core/query'; +import { AggregateSpec } from '../lite-api/aggregate_types'; +import { Query } from '../lite-api/reference'; +import { cast } from '../util/input_validation'; +import { mapToArray } from '../util/obj'; + +import { toQueryTarget, toRunAggregationQueryRequest } from './serializer'; + +/** + * @internal + * @private + * + * This function is for internal use only. + * + * Returns the `QueryTarget` representation of the given query. Returns `null` + * if the Firestore client associated with the given query has not been + * initialized or has been terminated. + * + * @param query - The Query to convert to proto representation. + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function _internalQueryToProtoQueryTarget(query: Query): any { + const firestore = cast(query.firestore, Firestore); + const client = ensureFirestoreConfigured(firestore); + const serializer = client._onlineComponents?.datastore.serializer; + if (serializer === undefined) { + return null; + } + return toQueryTarget(serializer!, queryToTarget(query._query)).queryTarget; +} + +/** + * @internal + * @private + * + * This function is for internal use only. + * + * Returns `RunAggregationQueryRequest` which contains the proto representation + * of the given aggregation query request. Returns null if the Firestore client + * associated with the given query has not been initialized or has been + * terminated. + * + * @param query - The Query to convert to proto representation. + * @param aggregateSpec - The set of aggregations and their aliases. + */ +export function _internalAggregationQueryToProtoRunAggregationQueryRequest< + AggregateSpecType extends AggregateSpec + // eslint-disable-next-line @typescript-eslint/no-explicit-any +>(query: Query, aggregateSpec: AggregateSpecType): any { + const aggregates = mapToArray(aggregateSpec, (aggregate, alias) => { + return new AggregateImpl( + alias, + aggregate.aggregateType, + aggregate._internalFieldPath + ); + }); + const firestore = cast(query.firestore, Firestore); + const client = ensureFirestoreConfigured(firestore); + const serializer = client._onlineComponents?.datastore.serializer; + if (serializer === undefined) { + return null; + } + + return toRunAggregationQueryRequest( + serializer!, + queryToAggregateTarget(query._query), + aggregates, + /* skipAliasing= */ true + ).request; +} diff --git a/packages/firestore/src/remote/serializer.ts b/packages/firestore/src/remote/serializer.ts index 63860a88972..811c2ac4df6 100644 --- a/packages/firestore/src/remote/serializer.ts +++ b/packages/firestore/src/remote/serializer.ts @@ -903,7 +903,8 @@ export function toQueryTarget( export function toRunAggregationQueryRequest( serializer: JsonProtoSerializer, target: Target, - aggregates: Aggregate[] + aggregates: Aggregate[], + skipAliasing?: boolean ): { request: ProtoRunAggregationQueryRequest; aliasMap: Record; @@ -919,7 +920,9 @@ export function toRunAggregationQueryRequest( // Map all client-side aliases to a unique short-form // alias. This avoids issues with client-side aliases that // exceed the 1500-byte string size limit. - const serverAlias = `aggregate_${aggregationNum++}`; + const serverAlias = skipAliasing + ? aggregate.alias + : `aggregate_${aggregationNum++}`; aliasMap[serverAlias] = aggregate.alias; if (aggregate.aggregateType === 'count') {