UNPKG

@firebase/firestore

Version:

The Cloud Firestore component of the Firebase JS SDK.

1,175 lines (1,164 loc) • 139 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var app = require('@firebase/app'); var component = require('@firebase/component'); var common948f0202_node = require('./common-60e0349e.node.cjs.js'); var util = require('@firebase/util'); require('@firebase/webchannel-wrapper/bloom-blob'); require('@firebase/logger'); require('util'); require('crypto'); require('@grpc/grpc-js'); require('@grpc/proto-loader'); const name$1 = "@firebase/firestore"; const version = "4.10.0"; /** * @license * Copyright 2020 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. */ function registerFirestore(variant, useFetchStreams = true) { common948f0202_node.setSDKVersion(app.SDK_VERSION); app._registerComponent(new component.Component('firestore', (container, { instanceIdentifier: databaseId, options: settings }) => { const app = container.getProvider('app').getImmediate(); const firestoreInstance = new common948f0202_node.Firestore(new common948f0202_node.FirebaseAuthCredentialsProvider(container.getProvider('auth-internal')), new common948f0202_node.FirebaseAppCheckTokenProvider(app, container.getProvider('app-check-internal')), common948f0202_node.databaseIdFromApp(app, databaseId), app); settings = { useFetchStreams, ...settings }; firestoreInstance._setSettings(settings); return firestoreInstance; }, 'PUBLIC').setMultipleInstances(true)); app.registerVersion(name$1, version, variant); // BUILD_TARGET will be replaced by values like esm, cjs, etc during the compilation app.registerVersion(name$1, version, 'cjs2020'); } /** * @license * Copyright 2022 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. */ /** * Represents an aggregation that can be performed by Firestore. */ // eslint-disable-next-line @typescript-eslint/no-unused-vars class AggregateField { /** * Create a new AggregateField<T> * @param aggregateType - Specifies the type of aggregation operation to perform. * @param _internalFieldPath - Optionally specifies the field that is aggregated. * @internal */ constructor(aggregateType = 'count', _internalFieldPath) { this._internalFieldPath = _internalFieldPath; /** A type string to uniquely identify instances of this class. */ this.type = 'AggregateField'; this.aggregateType = aggregateType; } } /** * The results of executing an aggregation query. */ class AggregateQuerySnapshot { /** @hideconstructor */ constructor(query, _userDataWriter, _data) { this._userDataWriter = _userDataWriter; this._data = _data; /** A type string to uniquely identify instances of this class. */ this.type = 'AggregateQuerySnapshot'; this.query = query; } /** * Returns the results of the aggregations performed over the underlying * query. * * The keys of the returned object will be the same as those of the * `AggregateSpec` object specified to the aggregation method, and the values * will be the corresponding aggregation result. * * @returns The results of the aggregations performed over the underlying * query. */ data() { return this._userDataWriter.convertObjectMap(this._data); } /** * @internal * @private * * Retrieves all fields in the snapshot as a proto value. * * @returns An `Object` containing all fields in the snapshot. */ _fieldsProto() { // Wrap data in an ObjectValue to clone it. const dataClone = new common948f0202_node.ObjectValue({ mapValue: { fields: this._data } }).clone(); // Return the cloned value to prevent manipulation of the Snapshot's data return dataClone.value.mapValue.fields; } } /** * @license * Copyright 2020 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. */ /** * A `DocumentSnapshot` contains data read from a document in your Firestore * database. The data can be extracted with `.data()` or `.get(<field>)` to * get a specific field. * * For a `DocumentSnapshot` that points to a non-existing document, any data * access will return 'undefined'. You can use the `exists()` method to * explicitly verify a document's existence. */ class DocumentSnapshot$1 { // Note: This class is stripped down version of the DocumentSnapshot in // the legacy SDK. The changes are: // - No support for SnapshotMetadata. // - No support for SnapshotOptions. /** @hideconstructor protected */ constructor(_firestore, _userDataWriter, _key, _document, _converter) { this._firestore = _firestore; this._userDataWriter = _userDataWriter; this._key = _key; this._document = _document; this._converter = _converter; } /** Property of the `DocumentSnapshot` that provides the document's ID. */ get id() { return this._key.path.lastSegment(); } /** * The `DocumentReference` for the document included in the `DocumentSnapshot`. */ get ref() { return new common948f0202_node.DocumentReference(this._firestore, this._converter, this._key); } /** * Signals whether or not the document at the snapshot's location exists. * * @returns true if the document exists. */ exists() { return this._document !== null; } /** * Retrieves all fields in the document as an `Object`. Returns `undefined` if * the document doesn't exist. * * @returns An `Object` containing all fields in the document or `undefined` * if the document doesn't exist. */ data() { if (!this._document) { return undefined; } else if (this._converter) { // We only want to use the converter and create a new DocumentSnapshot // if a converter has been provided. const snapshot = new QueryDocumentSnapshot$1(this._firestore, this._userDataWriter, this._key, this._document, /* converter= */ null); return this._converter.fromFirestore(snapshot); } else { return this._userDataWriter.convertValue(this._document.data.value); } } /** * @internal * @private * * Retrieves all fields in the document as a proto Value. Returns `undefined` if * the document doesn't exist. * * @returns An `Object` containing all fields in the document or `undefined` * if the document doesn't exist. */ _fieldsProto() { // Return a cloned value to prevent manipulation of the Snapshot's data return this._document?.data.clone().value.mapValue.fields ?? undefined; } /** * Retrieves the field specified by `fieldPath`. Returns `undefined` if the * document or field doesn't exist. * * @param fieldPath - The path (for example 'foo' or 'foo.bar') to a specific * field. * @returns The data at the specified field location or undefined if no such * field exists in the document. */ // We are using `any` here to avoid an explicit cast by our users. // eslint-disable-next-line @typescript-eslint/no-explicit-any get(fieldPath) { if (this._document) { const value = this._document.data.field(common948f0202_node.fieldPathFromArgument('DocumentSnapshot.get', fieldPath)); if (value !== null) { return this._userDataWriter.convertValue(value); } } return undefined; } } /** * A `QueryDocumentSnapshot` contains data read from a document in your * Firestore database as part of a query. The document is guaranteed to exist * and its data can be extracted with `.data()` or `.get(<field>)` to get a * specific field. * * A `QueryDocumentSnapshot` offers the same API surface as a * `DocumentSnapshot`. Since query results contain only existing documents, the * `exists` property will always be true and `data()` will never return * 'undefined'. */ class QueryDocumentSnapshot$1 extends DocumentSnapshot$1 { /** * Retrieves all fields in the document as an `Object`. * * @override * @returns An `Object` containing all fields in the document. */ data() { return super.data(); } } /** * @license * Copyright 2020 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. */ function validateHasExplicitOrderByForLimitToLast(query) { if (query.limitType === "L" /* LimitType.Last */ && query.explicitOrderBy.length === 0) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.UNIMPLEMENTED, 'limitToLast() queries require specifying at least one orderBy() clause'); } } /** * An `AppliableConstraint` is an abstraction of a constraint that can be applied * to a Firestore query. */ class AppliableConstraint { } /** * A `QueryConstraint` is used to narrow the set of documents returned by a * Firestore query. `QueryConstraint`s are created by invoking {@link where}, * {@link orderBy}, {@link (startAt:1)}, {@link (startAfter:1)}, {@link * (endBefore:1)}, {@link (endAt:1)}, {@link limit}, {@link limitToLast} and * can then be passed to {@link (query:1)} to create a new query instance that * also contains this `QueryConstraint`. */ class QueryConstraint extends AppliableConstraint { } function query(query, queryConstraint, ...additionalQueryConstraints) { let queryConstraints = []; if (queryConstraint instanceof AppliableConstraint) { queryConstraints.push(queryConstraint); } queryConstraints = queryConstraints.concat(additionalQueryConstraints); validateQueryConstraintArray(queryConstraints); for (const constraint of queryConstraints) { query = constraint._apply(query); } return query; } /** * A `QueryFieldFilterConstraint` is used to narrow the set of documents returned by * a Firestore query by filtering on one or more document fields. * `QueryFieldFilterConstraint`s are created by invoking {@link where} and can then * be passed to {@link (query:1)} to create a new query instance that also contains * this `QueryFieldFilterConstraint`. */ class QueryFieldFilterConstraint extends QueryConstraint { /** * @internal */ constructor(_field, _op, _value) { super(); this._field = _field; this._op = _op; this._value = _value; /** The type of this query constraint */ this.type = 'where'; } static _create(_field, _op, _value) { return new QueryFieldFilterConstraint(_field, _op, _value); } _apply(query) { const filter = this._parse(query); validateNewFieldFilter(query._query, filter); return new common948f0202_node.Query(query.firestore, query.converter, common948f0202_node.queryWithAddedFilter(query._query, filter)); } _parse(query) { const reader = common948f0202_node.newUserDataReader(query.firestore); const filter = newQueryFilter(query._query, 'where', reader, query.firestore._databaseId, this._field, this._op, this._value); return filter; } } /** * Creates a {@link QueryFieldFilterConstraint} that enforces that documents * must contain the specified field and that the value should satisfy the * relation constraint provided. * * @param fieldPath - The path to compare * @param opStr - The operation string (e.g "&lt;", "&lt;=", "==", "&lt;", * "&lt;=", "!="). * @param value - The value for comparison * @returns The created {@link QueryFieldFilterConstraint}. */ function where(fieldPath, opStr, value) { const op = opStr; const field = common948f0202_node.fieldPathFromArgument('where', fieldPath); return QueryFieldFilterConstraint._create(field, op, value); } /** * A `QueryCompositeFilterConstraint` is used to narrow the set of documents * returned by a Firestore query by performing the logical OR or AND of multiple * {@link QueryFieldFilterConstraint}s or {@link QueryCompositeFilterConstraint}s. * `QueryCompositeFilterConstraint`s are created by invoking {@link or} or * {@link and} and can then be passed to {@link (query:1)} to create a new query * instance that also contains the `QueryCompositeFilterConstraint`. */ class QueryCompositeFilterConstraint extends AppliableConstraint { /** * @internal */ constructor( /** The type of this query constraint */ type, _queryConstraints) { super(); this.type = type; this._queryConstraints = _queryConstraints; } static _create(type, _queryConstraints) { return new QueryCompositeFilterConstraint(type, _queryConstraints); } _parse(query) { const parsedFilters = this._queryConstraints .map(queryConstraint => { return queryConstraint._parse(query); }) .filter(parsedFilter => parsedFilter.getFilters().length > 0); if (parsedFilters.length === 1) { return parsedFilters[0]; } return common948f0202_node.CompositeFilter.create(parsedFilters, this._getOperator()); } _apply(query) { const parsedFilter = this._parse(query); if (parsedFilter.getFilters().length === 0) { // Return the existing query if not adding any more filters (e.g. an empty // composite filter). return query; } validateNewFilter(query._query, parsedFilter); return new common948f0202_node.Query(query.firestore, query.converter, common948f0202_node.queryWithAddedFilter(query._query, parsedFilter)); } _getQueryConstraints() { return this._queryConstraints; } _getOperator() { return this.type === 'and' ? "and" /* CompositeOperator.AND */ : "or" /* CompositeOperator.OR */; } } /** * Creates a new {@link QueryCompositeFilterConstraint} that is a disjunction of * the given filter constraints. A disjunction filter includes a document if it * satisfies any of the given filters. * * @param queryConstraints - Optional. The list of * {@link QueryFilterConstraint}s to perform a disjunction for. These must be * created with calls to {@link where}, {@link or}, or {@link and}. * @returns The newly created {@link QueryCompositeFilterConstraint}. */ function or(...queryConstraints) { // Only support QueryFilterConstraints queryConstraints.forEach(queryConstraint => validateQueryFilterConstraint('or', queryConstraint)); return QueryCompositeFilterConstraint._create("or" /* CompositeOperator.OR */, queryConstraints); } /** * Creates a new {@link QueryCompositeFilterConstraint} that is a conjunction of * the given filter constraints. A conjunction filter includes a document if it * satisfies all of the given filters. * * @param queryConstraints - Optional. The list of * {@link QueryFilterConstraint}s to perform a conjunction for. These must be * created with calls to {@link where}, {@link or}, or {@link and}. * @returns The newly created {@link QueryCompositeFilterConstraint}. */ function and(...queryConstraints) { // Only support QueryFilterConstraints queryConstraints.forEach(queryConstraint => validateQueryFilterConstraint('and', queryConstraint)); return QueryCompositeFilterConstraint._create("and" /* CompositeOperator.AND */, queryConstraints); } /** * A `QueryOrderByConstraint` is used to sort the set of documents returned by a * Firestore query. `QueryOrderByConstraint`s are created by invoking * {@link orderBy} and can then be passed to {@link (query:1)} to create a new query * instance that also contains this `QueryOrderByConstraint`. * * Note: Documents that do not contain the orderBy field will not be present in * the query result. */ class QueryOrderByConstraint extends QueryConstraint { /** * @internal */ constructor(_field, _direction) { super(); this._field = _field; this._direction = _direction; /** The type of this query constraint */ this.type = 'orderBy'; } static _create(_field, _direction) { return new QueryOrderByConstraint(_field, _direction); } _apply(query) { const orderBy = newQueryOrderBy(query._query, this._field, this._direction); return new common948f0202_node.Query(query.firestore, query.converter, common948f0202_node.queryWithAddedOrderBy(query._query, orderBy)); } } /** * Creates a {@link QueryOrderByConstraint} that sorts the query result by the * specified field, optionally in descending order instead of ascending. * * Note: Documents that do not contain the specified field will not be present * in the query result. * * @param fieldPath - The field to sort by. * @param directionStr - Optional direction to sort by ('asc' or 'desc'). If * not specified, order will be ascending. * @returns The created {@link QueryOrderByConstraint}. */ function orderBy(fieldPath, directionStr = 'asc') { const direction = directionStr; const path = common948f0202_node.fieldPathFromArgument('orderBy', fieldPath); return QueryOrderByConstraint._create(path, direction); } /** * A `QueryLimitConstraint` is used to limit the number of documents returned by * a Firestore query. * `QueryLimitConstraint`s are created by invoking {@link limit} or * {@link limitToLast} and can then be passed to {@link (query:1)} to create a new * query instance that also contains this `QueryLimitConstraint`. */ class QueryLimitConstraint extends QueryConstraint { /** * @internal */ constructor( /** The type of this query constraint */ type, _limit, _limitType) { super(); this.type = type; this._limit = _limit; this._limitType = _limitType; } static _create(type, _limit, _limitType) { return new QueryLimitConstraint(type, _limit, _limitType); } _apply(query) { return new common948f0202_node.Query(query.firestore, query.converter, common948f0202_node.queryWithLimit(query._query, this._limit, this._limitType)); } } /** * Creates a {@link QueryLimitConstraint} that only returns the first matching * documents. * * @param limit - The maximum number of items to return. * @returns The created {@link QueryLimitConstraint}. */ function limit(limit) { common948f0202_node.validatePositiveNumber('limit', limit); return QueryLimitConstraint._create('limit', limit, "F" /* LimitType.First */); } /** * Creates a {@link QueryLimitConstraint} that only returns the last matching * documents. * * You must specify at least one `orderBy` clause for `limitToLast` queries, * otherwise an exception will be thrown during execution. * * @param limit - The maximum number of items to return. * @returns The created {@link QueryLimitConstraint}. */ function limitToLast(limit) { common948f0202_node.validatePositiveNumber('limitToLast', limit); return QueryLimitConstraint._create('limitToLast', limit, "L" /* LimitType.Last */); } /** * A `QueryStartAtConstraint` is used to exclude documents from the start of a * result set returned by a Firestore query. * `QueryStartAtConstraint`s are created by invoking {@link (startAt:1)} or * {@link (startAfter:1)} and can then be passed to {@link (query:1)} to create a * new query instance that also contains this `QueryStartAtConstraint`. */ class QueryStartAtConstraint extends QueryConstraint { /** * @internal */ constructor( /** The type of this query constraint */ type, _docOrFields, _inclusive) { super(); this.type = type; this._docOrFields = _docOrFields; this._inclusive = _inclusive; } static _create(type, _docOrFields, _inclusive) { return new QueryStartAtConstraint(type, _docOrFields, _inclusive); } _apply(query) { const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive); return new common948f0202_node.Query(query.firestore, query.converter, common948f0202_node.queryWithStartAt(query._query, bound)); } } function startAt(...docOrFields) { return QueryStartAtConstraint._create('startAt', docOrFields, /*inclusive=*/ true); } function startAfter(...docOrFields) { return QueryStartAtConstraint._create('startAfter', docOrFields, /*inclusive=*/ false); } /** * A `QueryEndAtConstraint` is used to exclude documents from the end of a * result set returned by a Firestore query. * `QueryEndAtConstraint`s are created by invoking {@link (endAt:1)} or * {@link (endBefore:1)} and can then be passed to {@link (query:1)} to create a new * query instance that also contains this `QueryEndAtConstraint`. */ class QueryEndAtConstraint extends QueryConstraint { /** * @internal */ constructor( /** The type of this query constraint */ type, _docOrFields, _inclusive) { super(); this.type = type; this._docOrFields = _docOrFields; this._inclusive = _inclusive; } static _create(type, _docOrFields, _inclusive) { return new QueryEndAtConstraint(type, _docOrFields, _inclusive); } _apply(query) { const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive); return new common948f0202_node.Query(query.firestore, query.converter, common948f0202_node.queryWithEndAt(query._query, bound)); } } function endBefore(...docOrFields) { return QueryEndAtConstraint._create('endBefore', docOrFields, /*inclusive=*/ false); } function endAt(...docOrFields) { return QueryEndAtConstraint._create('endAt', docOrFields, /*inclusive=*/ true); } /** Helper function to create a bound from a document or fields */ function newQueryBoundFromDocOrFields(query, methodName, docOrFields, inclusive) { docOrFields[0] = util.getModularInstance(docOrFields[0]); if (docOrFields[0] instanceof DocumentSnapshot$1) { return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document, inclusive); } else { const reader = common948f0202_node.newUserDataReader(query.firestore); return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields, inclusive); } } function newQueryFilter(query, methodName, dataReader, databaseId, fieldPath, op, value) { let fieldValue; if (fieldPath.isKeyField()) { if (op === "array-contains" /* Operator.ARRAY_CONTAINS */ || op === "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, `Invalid Query. You can't perform '${op}' queries on documentId().`); } else if (op === "in" /* Operator.IN */ || op === "not-in" /* Operator.NOT_IN */) { validateDisjunctiveFilterElements(value, op); const referenceList = []; for (const arrayValue of value) { referenceList.push(parseDocumentIdValue(databaseId, query, arrayValue)); } fieldValue = { arrayValue: { values: referenceList } }; } else { fieldValue = parseDocumentIdValue(databaseId, query, value); } } else { if (op === "in" /* Operator.IN */ || op === "not-in" /* Operator.NOT_IN */ || op === "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */) { validateDisjunctiveFilterElements(value, op); } fieldValue = common948f0202_node.parseQueryValue(dataReader, methodName, value, /* allowArrays= */ op === "in" /* Operator.IN */ || op === "not-in" /* Operator.NOT_IN */); } const filter = common948f0202_node.FieldFilter.create(fieldPath, op, fieldValue); return filter; } function newQueryOrderBy(query, fieldPath, direction) { if (query.startAt !== null) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, 'Invalid query. You must not call startAt() or startAfter() before ' + 'calling orderBy().'); } if (query.endAt !== null) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, 'Invalid query. You must not call endAt() or endBefore() before ' + 'calling orderBy().'); } const orderBy = new common948f0202_node.OrderBy(fieldPath, direction); return orderBy; } /** * Create a `Bound` from a query and a document. * * Note that the `Bound` will always include the key of the document * and so only the provided document will compare equal to the returned * position. * * Will throw if the document does not contain all fields of the order by * of the query or if any of the fields in the order by are an uncommitted * server timestamp. */ function newQueryBoundFromDocument(query, databaseId, methodName, doc, inclusive) { if (!doc) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.NOT_FOUND, `Can't use a DocumentSnapshot that doesn't exist for ` + `${methodName}().`); } const components = []; // Because people expect to continue/end a query at the exact document // provided, we need to use the implicit sort order rather than the explicit // sort order, because it's guaranteed to contain the document key. That way // the position becomes unambiguous and the query continues/ends exactly at // the provided document. Without the key (by using the explicit sort // orders), multiple documents could match the position, yielding duplicate // results. for (const orderBy of common948f0202_node.queryNormalizedOrderBy(query)) { if (orderBy.field.isKeyField()) { components.push(common948f0202_node.refValue(databaseId, doc.key)); } else { const value = doc.data.field(orderBy.field); if (common948f0202_node.isServerTimestamp(value)) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, 'Invalid query. You are trying to start or end a query using a ' + 'document for which the field "' + orderBy.field + '" is an uncommitted server timestamp. (Since the value of ' + 'this field is unknown, you cannot start/end a query with it.)'); } else if (value !== null) { components.push(value); } else { const field = orderBy.field.canonicalString(); throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, `Invalid query. You are trying to start or end a query using a ` + `document for which the field '${field}' (used as the ` + `orderBy) does not exist.`); } } } return new common948f0202_node.Bound(components, inclusive); } /** * Converts a list of field values to a `Bound` for the given query. */ function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values, inclusive) { // Use explicit order by's because it has to match the query the user made const orderBy = query.explicitOrderBy; if (values.length > orderBy.length) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, `Too many arguments provided to ${methodName}(). ` + `The number of arguments must be less than or equal to the ` + `number of orderBy() clauses`); } const components = []; for (let i = 0; i < values.length; i++) { const rawValue = values[i]; const orderByComponent = orderBy[i]; if (orderByComponent.field.isKeyField()) { if (typeof rawValue !== 'string') { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, `Invalid query. Expected a string for document ID in ` + `${methodName}(), but got a ${typeof rawValue}`); } if (!common948f0202_node.isCollectionGroupQuery(query) && rawValue.indexOf('/') !== -1) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, `Invalid query. When querying a collection and ordering by documentId(), ` + `the value passed to ${methodName}() must be a plain document ID, but ` + `'${rawValue}' contains a slash.`); } const path = query.path.child(common948f0202_node.ResourcePath.fromString(rawValue)); if (!common948f0202_node.DocumentKey.isDocumentKey(path)) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, `Invalid query. When querying a collection group and ordering by ` + `documentId(), the value passed to ${methodName}() must result in a ` + `valid document path, but '${path}' is not because it contains an odd number ` + `of segments.`); } const key = new common948f0202_node.DocumentKey(path); components.push(common948f0202_node.refValue(databaseId, key)); } else { const wrapped = common948f0202_node.parseQueryValue(dataReader, methodName, rawValue); components.push(wrapped); } } return new common948f0202_node.Bound(components, inclusive); } /** * Parses the given `documentIdValue` into a `ReferenceValue`, throwing * appropriate errors if the value is anything other than a `DocumentReference` * or `string`, or if the string is malformed. */ function parseDocumentIdValue(databaseId, query, documentIdValue) { documentIdValue = util.getModularInstance(documentIdValue); if (typeof documentIdValue === 'string') { if (documentIdValue === '') { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, 'Invalid query. When querying with documentId(), you ' + 'must provide a valid document ID, but it was an empty string.'); } if (!common948f0202_node.isCollectionGroupQuery(query) && documentIdValue.indexOf('/') !== -1) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, `Invalid query. When querying a collection by ` + `documentId(), you must provide a plain document ID, but ` + `'${documentIdValue}' contains a '/' character.`); } const path = query.path.child(common948f0202_node.ResourcePath.fromString(documentIdValue)); if (!common948f0202_node.DocumentKey.isDocumentKey(path)) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, `Invalid query. When querying a collection group by ` + `documentId(), the value provided must result in a valid document path, ` + `but '${path}' is not because it has an odd number of segments (${path.length}).`); } return common948f0202_node.refValue(databaseId, new common948f0202_node.DocumentKey(path)); } else if (documentIdValue instanceof common948f0202_node.DocumentReference) { return common948f0202_node.refValue(databaseId, documentIdValue._key); } else { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, `Invalid query. When querying with documentId(), you must provide a valid ` + `string or a DocumentReference, but it was: ` + `${common948f0202_node.valueDescription(documentIdValue)}.`); } } /** * Validates that the value passed into a disjunctive filter satisfies all * array requirements. */ function validateDisjunctiveFilterElements(value, operator) { if (!Array.isArray(value) || value.length === 0) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, 'Invalid Query. A non-empty array is required for ' + `'${operator.toString()}' filters.`); } } /** * Given an operator, returns the set of operators that cannot be used with it. * * This is not a comprehensive check, and this function should be removed in the * long term. Validations should occur in the Firestore backend. * * Operators in a query must adhere to the following set of rules: * 1. Only one inequality per query. * 2. `NOT_IN` cannot be used with array, disjunctive, or `NOT_EQUAL` operators. */ function conflictingOps(op) { switch (op) { case "!=" /* Operator.NOT_EQUAL */: return ["!=" /* Operator.NOT_EQUAL */, "not-in" /* Operator.NOT_IN */]; case "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */: case "in" /* Operator.IN */: return ["not-in" /* Operator.NOT_IN */]; case "not-in" /* Operator.NOT_IN */: return [ "array-contains-any" /* Operator.ARRAY_CONTAINS_ANY */, "in" /* Operator.IN */, "not-in" /* Operator.NOT_IN */, "!=" /* Operator.NOT_EQUAL */ ]; default: return []; } } function validateNewFieldFilter(query, fieldFilter) { const conflictingOp = findOpInsideFilters(query.filters, conflictingOps(fieldFilter.op)); if (conflictingOp !== null) { // Special case when it's a duplicate op to give a slightly clearer error message. if (conflictingOp === fieldFilter.op) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, 'Invalid query. You cannot use more than one ' + `'${fieldFilter.op.toString()}' filter.`); } else { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, `Invalid query. You cannot use '${fieldFilter.op.toString()}' filters ` + `with '${conflictingOp.toString()}' filters.`); } } } function validateNewFilter(query, filter) { let testQuery = query; const subFilters = filter.getFlattenedFilters(); for (const subFilter of subFilters) { validateNewFieldFilter(testQuery, subFilter); testQuery = common948f0202_node.queryWithAddedFilter(testQuery, subFilter); } } // Checks if any of the provided filter operators are included in the given list of filters and // returns the first one that is, or null if none are. function findOpInsideFilters(filters, operators) { for (const filter of filters) { for (const fieldFilter of filter.getFlattenedFilters()) { if (operators.indexOf(fieldFilter.op) >= 0) { return fieldFilter.op; } } } return null; } function validateQueryFilterConstraint(functionName, queryConstraint) { if (!(queryConstraint instanceof QueryFieldFilterConstraint) && !(queryConstraint instanceof QueryCompositeFilterConstraint)) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, `Function ${functionName}() requires AppliableConstraints created with a call to 'where(...)', 'or(...)', or 'and(...)'.`); } } function validateQueryConstraintArray(queryConstraint) { const compositeFilterCount = queryConstraint.filter(filter => filter instanceof QueryCompositeFilterConstraint).length; const fieldFilterCount = queryConstraint.filter(filter => filter instanceof QueryFieldFilterConstraint).length; if (compositeFilterCount > 1 || (compositeFilterCount > 0 && fieldFilterCount > 0)) { throw new common948f0202_node.FirestoreError(common948f0202_node.Code.INVALID_ARGUMENT, 'InvalidQuery. When using composite filters, you cannot use ' + 'more than one filter at the top level. Consider nesting the multiple ' + 'filters within an `and(...)` statement. For example: ' + 'change `query(query, where(...), or(...))` to ' + '`query(query, and(where(...), or(...)))`.'); } } /** * @license * Copyright 2020 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. */ /** * Converts custom model object of type T into `DocumentData` by applying the * converter if it exists. * * This function is used when converting user objects to `DocumentData` * because we want to provide the user with a more specific error message if * their `set()` or fails due to invalid data originating from a `toFirestore()` * call. */ function applyFirestoreDataConverter(converter, value, options) { let convertedValue; if (converter) { if (options && (options.merge || options.mergeFields)) { // Cast to `any` in order to satisfy the union type constraint on // toFirestore(). // eslint-disable-next-line @typescript-eslint/no-explicit-any convertedValue = converter.toFirestore(value, options); } else { convertedValue = converter.toFirestore(value); } } else { convertedValue = value; } return convertedValue; } class LiteUserDataWriter extends common948f0202_node.AbstractUserDataWriter { constructor(firestore) { super(); this.firestore = firestore; } convertBytes(bytes) { return new common948f0202_node.Bytes(bytes); } convertReference(name) { const key = this.convertDocumentKey(name, this.firestore._databaseId); return new common948f0202_node.DocumentReference(this.firestore, /* converter= */ null, key); } } /** * @license * Copyright 2022 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. */ /** * Create an AggregateField object that can be used to compute the sum of * a specified field over a range of documents in the result set of a query. * @param field - Specifies the field to sum across the result set. */ function sum(field) { return new AggregateField('sum', common948f0202_node.fieldPathFromArgument('sum', field)); } /** * Create an AggregateField object that can be used to compute the average of * a specified field over a range of documents in the result set of a query. * @param field - Specifies the field to average across the result set. */ function average(field) { return new AggregateField('avg', common948f0202_node.fieldPathFromArgument('average', field)); } /** * Create an AggregateField object that can be used to compute the count of * documents in the result set of a query. */ function count() { return new AggregateField('count'); } /** * Compares two 'AggregateField` instances for equality. * * @param left - Compare this AggregateField to the `right`. * @param right - Compare this AggregateField to the `left`. */ function aggregateFieldEqual(left, right) { return (left instanceof AggregateField && right instanceof AggregateField && left.aggregateType === right.aggregateType && left._internalFieldPath?.canonicalString() === right._internalFieldPath?.canonicalString()); } /** * Compares two `AggregateQuerySnapshot` instances for equality. * * Two `AggregateQuerySnapshot` instances are considered "equal" if they have * underlying queries that compare equal, and the same data. * * @param left - The first `AggregateQuerySnapshot` to compare. * @param right - The second `AggregateQuerySnapshot` to compare. * * @returns `true` if the objects are "equal", as defined above, or `false` * otherwise. */ function aggregateQuerySnapshotEqual(left, right) { return (common948f0202_node.queryEqual(left.query, right.query) && util.deepEqual(left.data(), right.data())); } /** * @license * Copyright 2022 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. */ /** * Calculates the number of documents in the result set of the given query * without actually downloading the documents. * * Using this function to count the documents is efficient because only the * final count, not the documents' data, is downloaded. This function can * count the documents in cases where the result set is prohibitively large to * download entirely (thousands of documents). * * The result received from the server is presented, unaltered, without * considering any local state. That is, documents in the local cache are not * taken into consideration, neither are local modifications not yet * synchronized with the server. Previously-downloaded results, if any, are not * used. Every invocation of this function necessarily involves a round trip to * the server. * * @param query - The query whose result set size is calculated. * @returns A Promise that will be resolved with the count; the count can be * retrieved from `snapshot.data().count`, where `snapshot` is the * `AggregateQuerySnapshot` to which the returned Promise resolves. */ function getCountFromServer(query) { const countQuerySpec = { count: count() }; return getAggregateFromServer(query, countQuerySpec); } /** * Calculates the specified aggregations over the documents in the result * set of the given query without actually downloading the documents. * * Using this function to perform aggregations is efficient because only the * final aggregation values, not the documents' data, are downloaded. This * function can perform aggregations of the documents in cases where the result * set is prohibitively large to download entirely (thousands of documents). * * The result received from the server is presented, unaltered, without * considering any local state. That is, documents in the local cache are not * taken into consideration, neither are local modifications not yet * synchronized with the server. Previously-downloaded results, if any, are not * used. Every invocation of this function necessarily involves a round trip to * the server. * * @param query - The query whose result set is aggregated over. * @param aggregateSpec - An `AggregateSpec` object that specifies the aggregates * to perform over the result set. The AggregateSpec specifies aliases for each * aggregate, which can be used to retrieve the aggregate result. * @example * ```typescript * const aggregateSnapshot = await getAggregateFromServer(query, { * countOfDocs: count(), * totalHours: sum('hours'), * averageScore: average('score') * }); * * const countOfDocs: number = aggregateSnapshot.data().countOfDocs; * const totalHours: number = aggregateSnapshot.data().totalHours; * const averageScore: number | null = aggregateSnapshot.data().averageScore; * ``` */ function getAggregateFromServer(query, aggregateSpec) { const firestore = common948f0202_node.cast(query.firestore, common948f0202_node.Firestore); const client = common948f0202_node.ensureFirestoreConfigured(firestore); const internalAggregates = common948f0202_node.mapToArray(aggregateSpec, (aggregate, alias) => { return new common948f0202_node.AggregateImpl(alias, aggregate.aggregateType, aggregate._internalFieldPath); }); // Run the aggregation and convert the results return common948f0202_node.firestoreClientRunAggregateQuery(client, query._query, internalAggregates).then(aggregateResult => convertToAggregateQuerySnapshot(firestore, query, aggregateResult)); } /** * Converts the core aggregation result to an `AggregateQuerySnapshot` * that can be returned to the consumer. * @param query * @param aggregateResult - Core aggregation result * @internal */ function convertToAggregateQuerySnapshot(firestore, query, aggregateResult) { const userDataWriter = new common948f0202_node.ExpUserDataWriter(firestore); const querySnapshot = new AggregateQuerySnapshot(query, userDataWriter, aggregateResult); return querySnapshot; } /** * @license * Copyright 2023 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. */ class MemoryLocalCacheImpl { constructor(settings) { this.kind = 'memory'; this._onlineComponentProvider = common948f0202_node.OnlineComponentProvider.provider; if (settings?.garbageCollector) { this._offlineComponentProvider = settings.garbageCollector._offlineComponentProvider; } else { this._offlineComponentProvider = { build: () => new common948f0202_node.LruGcMemoryOfflineComponentProvider(undefined) }; } } toJSON() { return { kind: this.kind }; } } class PersistentLocalCacheImpl { constructor(settings) { this.kind = 'persistent'; let tabManager; if (settings?.tabManager) { settings.tabManager._initialize(settings); tabManager = settings.tabManager; } else { tabManager = persistentSingleTabManager(undefined); tabManager._initialize(settings); } this._onlineComponentProvider = tabManager._onlineComponentProvider; this._offlineComponentProvider = tabManager._offlineComponentProvider; } toJSON() { return { kind: this.kind }; } } class MemoryEagerGarbageCollectorImpl { constructor() { this.kind = 'memoryEager'; this._offlineComponentProvider = common948f0202_node.MemoryOfflineComponentProvider.provider; } toJSON() { return { kind: this.kind }; } } class MemoryLruGarbageCollectorImpl { constructor(cacheSize) { this.kind = 'memoryLru'; this._offlineComponentProvider = { build: () => new common948f0202_node.LruGcMemoryOfflineComponentProvider(cacheSize) }; } toJSON() { return { kind: this.kind }; } } /** * Creates an instance of `MemoryEagerGarbageCollector`.