UNPKG

@firebase/firestore

Version:

The Cloud Firestore component of the Firebase JS SDK.

1,366 lines (1,362 loc) • 157 kB
import { O as ObjectValue, av as isPlainObject, aw as parseData, ax as FieldPath, m as mapToArray, o as FirestoreError, ay as isString, az as DOCUMENT_KEY_NAME, af as documentId$1, f as fieldPathFromArgument, aA as hardAssert, aB as toStringValue, aq as VectorValue, am as vector, aC as toMapValue, aD as isCollectionGroupQuery, aE as isDocumentQuery, M as doc, aF as queryNormalizedOrderBy, aG as FieldFilter, v as fail, aH as CompositeFilter, aI as toNumber, aJ as toPipelineValue, aK as isUserData, aL as isCollectionReference, H as DocumentReference, C as Code, I as CollectionReference, aM as isNumber, g as getDatastore, c as cast, n as newUserDataReader, b as LiteUserDataWriter, aN as invokeExecutePipeline, F as Firestore } from './common-6d85b8e5.node.mjs'; import '@firebase/util'; import 'crypto'; import '@firebase/logger'; import 'util'; import '@firebase/webchannel-wrapper/bloom-blob'; import '@firebase/app'; /** * @license * Copyright 2025 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 OptionsUtil { constructor(optionDefinitions) { this.optionDefinitions = optionDefinitions; } _getKnownOptions(options, context) { const knownOptions = ObjectValue.empty(); // SERIALIZE KNOWN OPTIONS for (const knownOptionKey in this.optionDefinitions) { if (this.optionDefinitions.hasOwnProperty(knownOptionKey)) { const optionDefinition = this.optionDefinitions[knownOptionKey]; if (knownOptionKey in options) { const optionValue = options[knownOptionKey]; let protoValue = undefined; if (optionDefinition.nestedOptions && isPlainObject(optionValue)) { const nestedUtil = new OptionsUtil(optionDefinition.nestedOptions); protoValue = { mapValue: { fields: nestedUtil.getOptionsProto(context, optionValue) } }; } else if (optionValue) { protoValue = parseData(optionValue, context) ?? undefined; } if (protoValue) { knownOptions.set(FieldPath.fromServerFormat(optionDefinition.serverName), protoValue); } } } } return knownOptions; } getOptionsProto(context, knownOptions, optionsOverride) { const result = this._getKnownOptions(knownOptions, context); // APPLY OPTIONS OVERRIDES if (optionsOverride) { const optionsMap = new Map(mapToArray(optionsOverride, (value, key) => [ FieldPath.fromServerFormat(key), value !== undefined ? parseData(value, context) : null ])); result.setAll(optionsMap); } // Return MapValue from `result` or empty map value return result.value.mapValue.fields ?? {}; } } /** * @license * Copyright 2025 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 StructuredPipelineOptions { constructor(_userOptions = {}, _optionsOverride = {}) { this._userOptions = _userOptions; this._optionsOverride = _optionsOverride; this.optionsUtil = new OptionsUtil({ indexMode: { serverName: 'index_mode' } }); } _readUserData(context) { this.proto = this.optionsUtil.getOptionsProto(context, this._userOptions, this._optionsOverride); } } class StructuredPipeline { constructor(pipeline, options) { this.pipeline = pipeline; this.options = options; } _toProto(serializer) { return { pipeline: this.pipeline._toProto(serializer), options: this.options.proto }; } } /** * @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. */ /* eslint @typescript-eslint/no-explicit-any: 0 */ function isITimestamp(obj) { if (typeof obj !== 'object' || obj === null) { return false; // Must be a non-null object } if ('seconds' in obj && (obj.seconds === null || typeof obj.seconds === 'number' || typeof obj.seconds === 'string') && 'nanos' in obj && (obj.nanos === null || typeof obj.nanos === 'number')) { return true; } return false; } function isILatLng(obj) { if (typeof obj !== 'object' || obj === null) { return false; // Must be a non-null object } if ('latitude' in obj && (obj.latitude === null || typeof obj.latitude === 'number') && 'longitude' in obj && (obj.longitude === null || typeof obj.longitude === 'number')) { return true; } return false; } function isIArrayValue(obj) { if (typeof obj !== 'object' || obj === null) { return false; // Must be a non-null object } if ('values' in obj && (obj.values === null || Array.isArray(obj.values))) { return true; } return false; } function isIMapValue(obj) { if (typeof obj !== 'object' || obj === null) { return false; // Must be a non-null object } if ('fields' in obj && (obj.fields === null || isPlainObject(obj.fields))) { return true; } return false; } function isIFunction(obj) { if (typeof obj !== 'object' || obj === null) { return false; // Must be a non-null object } if ('name' in obj && (obj.name === null || typeof obj.name === 'string') && 'args' in obj && (obj.args === null || Array.isArray(obj.args))) { return true; } return false; } function isIPipeline(obj) { if (typeof obj !== 'object' || obj === null) { return false; // Must be a non-null object } if ('stages' in obj && (obj.stages === null || Array.isArray(obj.stages))) { return true; } return false; } function isFirestoreValue(obj) { if (typeof obj !== 'object' || obj === null) { return false; // Must be a non-null object } // Check optional properties and their types if (('nullValue' in obj && (obj.nullValue === null || obj.nullValue === 'NULL_VALUE')) || ('booleanValue' in obj && (obj.booleanValue === null || typeof obj.booleanValue === 'boolean')) || ('integerValue' in obj && (obj.integerValue === null || typeof obj.integerValue === 'number' || typeof obj.integerValue === 'string')) || ('doubleValue' in obj && (obj.doubleValue === null || typeof obj.doubleValue === 'number')) || ('timestampValue' in obj && (obj.timestampValue === null || isITimestamp(obj.timestampValue))) || ('stringValue' in obj && (obj.stringValue === null || typeof obj.stringValue === 'string')) || ('bytesValue' in obj && (obj.bytesValue === null || obj.bytesValue instanceof Uint8Array)) || ('referenceValue' in obj && (obj.referenceValue === null || typeof obj.referenceValue === 'string')) || ('geoPointValue' in obj && (obj.geoPointValue === null || isILatLng(obj.geoPointValue))) || ('arrayValue' in obj && (obj.arrayValue === null || isIArrayValue(obj.arrayValue))) || ('mapValue' in obj && (obj.mapValue === null || isIMapValue(obj.mapValue))) || ('fieldReferenceValue' in obj && (obj.fieldReferenceValue === null || typeof obj.fieldReferenceValue === 'string')) || ('functionValue' in obj && (obj.functionValue === null || isIFunction(obj.functionValue))) || ('pipelineValue' in obj && (obj.pipelineValue === null || isIPipeline(obj.pipelineValue)))) { return true; } return false; } /** * @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. */ /** * Converts a value to an Expression, Returning either a Constant, MapFunction, * ArrayFunction, or the input itself (if it's already an expression). * * @private * @internal * @param value */ function valueToDefaultExpr$1(value) { let result; if (value instanceof Expression) { return value; } else if (isPlainObject(value)) { result = _map(value); } else if (value instanceof Array) { result = array(value); } else { result = _constant(value, undefined); } return result; } /** * Converts a value to an Expression, Returning either a Constant, MapFunction, * ArrayFunction, or the input itself (if it's already an expression). * * @private * @internal * @param value */ function vectorToExpr$1(value) { if (value instanceof Expression) { return value; } else if (value instanceof VectorValue) { return constant(value); } else if (Array.isArray(value)) { return constant(vector(value)); } else { throw new Error('Unsupported value: ' + typeof value); } } /** * Converts a value to an Expression, Returning either a Constant, MapFunction, * ArrayFunction, or the input itself (if it's already an expression). * If the input is a string, it is assumed to be a field name, and a * field(value) is returned. * * @private * @internal * @param value */ function fieldOrExpression$1(value) { if (isString(value)) { const result = field(value); return result; } else { return valueToDefaultExpr$1(value); } } /** * @beta * * Represents an expression that can be evaluated to a value within the execution of a {@link * @firebase/firestore/pipelines#Pipeline}. * * Expressions are the building blocks for creating complex queries and transformations in * Firestore pipelines. They can represent: * * - **Field references:** Access values from document fields. * - **Literals:** Represent constant values (strings, numbers, booleans). * - **Function calls:** Apply functions to one or more expressions. * * The `Expression` class provides a fluent API for building expressions. You can chain together * method calls to create complex expressions. */ class Expression { constructor() { this._protoValueType = 'ProtoValue'; } /** * Creates an expression that adds this expression to another expression. * * @example * ```typescript * // Add the value of the 'quantity' field and the 'reserve' field. * field("quantity").add(field("reserve")); * ``` * * @param second - The expression or literal to add to this expression. * @param others - Optional additional expressions or literals to add to this expression. * @returns A new `Expression` representing the addition operation. */ add(second) { return new FunctionExpression('add', [this, valueToDefaultExpr$1(second)], 'add'); } /** * @beta * Wraps the expression in a [BooleanExpression]. * * @returns A [BooleanExpression] representing the same expression. */ asBoolean() { if (this instanceof BooleanExpression) { return this; } else if (this instanceof Constant) { return new BooleanConstant(this); } else if (this instanceof Field) { return new BooleanField(this); } else if (this instanceof FunctionExpression) { return new BooleanFunctionExpression(this); } else { throw new FirestoreError('invalid-argument', `Conversion of type ${typeof this} to BooleanExpression not supported.`); } } subtract(subtrahend) { return new FunctionExpression('subtract', [this, valueToDefaultExpr$1(subtrahend)], 'subtract'); } /** * @beta * Creates an expression that multiplies this expression by another expression. * * @example * ```typescript * // Multiply the 'quantity' field by the 'price' field * field("quantity").multiply(field("price")); * ``` * * @param second - The second expression or literal to multiply by. * @param others - Optional additional expressions or literals to multiply by. * @returns A new `Expression` representing the multiplication operation. */ multiply(second) { return new FunctionExpression('multiply', [this, valueToDefaultExpr$1(second)], 'multiply'); } divide(divisor) { return new FunctionExpression('divide', [this, valueToDefaultExpr$1(divisor)], 'divide'); } mod(other) { return new FunctionExpression('mod', [this, valueToDefaultExpr$1(other)], 'mod'); } equal(other) { return new FunctionExpression('equal', [this, valueToDefaultExpr$1(other)], 'equal').asBoolean(); } notEqual(other) { return new FunctionExpression('not_equal', [this, valueToDefaultExpr$1(other)], 'notEqual').asBoolean(); } lessThan(other) { return new FunctionExpression('less_than', [this, valueToDefaultExpr$1(other)], 'lessThan').asBoolean(); } lessThanOrEqual(other) { return new FunctionExpression('less_than_or_equal', [this, valueToDefaultExpr$1(other)], 'lessThanOrEqual').asBoolean(); } greaterThan(other) { return new FunctionExpression('greater_than', [this, valueToDefaultExpr$1(other)], 'greaterThan').asBoolean(); } greaterThanOrEqual(other) { return new FunctionExpression('greater_than_or_equal', [this, valueToDefaultExpr$1(other)], 'greaterThanOrEqual').asBoolean(); } /** * @beta * Creates an expression that concatenates an array expression with one or more other arrays. * * @example * ```typescript * // Combine the 'items' array with another array field. * field("items").arrayConcat(field("otherItems")); * ``` * @param secondArray - Second array expression or array literal to concatenate. * @param otherArrays - Optional additional array expressions or array literals to concatenate. * @returns A new `Expression` representing the concatenated array. */ arrayConcat(secondArray, ...otherArrays) { const elements = [secondArray, ...otherArrays]; const exprValues = elements.map(value => valueToDefaultExpr$1(value)); return new FunctionExpression('array_concat', [this, ...exprValues], 'arrayConcat'); } arrayContains(element) { return new FunctionExpression('array_contains', [this, valueToDefaultExpr$1(element)], 'arrayContains').asBoolean(); } arrayContainsAll(values) { const normalizedExpr = Array.isArray(values) ? new ListOfExprs(values.map(valueToDefaultExpr$1), 'arrayContainsAll') : values; return new FunctionExpression('array_contains_all', [this, normalizedExpr], 'arrayContainsAll').asBoolean(); } arrayContainsAny(values) { const normalizedExpr = Array.isArray(values) ? new ListOfExprs(values.map(valueToDefaultExpr$1), 'arrayContainsAny') : values; return new FunctionExpression('array_contains_any', [this, normalizedExpr], 'arrayContainsAny').asBoolean(); } /** * @beta * Creates an expression that reverses an array. * * @example * ```typescript * // Reverse the value of the 'myArray' field. * field("myArray").arrayReverse(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the reversed array. */ arrayReverse() { return new FunctionExpression('array_reverse', [this]); } /** * @beta * Creates an expression that calculates the length of an array. * * @example * ```typescript * // Get the number of items in the 'cart' array * field("cart").arrayLength(); * ``` * * @returns A new `Expression` representing the length of the array. */ arrayLength() { return new FunctionExpression('array_length', [this], 'arrayLength'); } equalAny(others) { const exprOthers = Array.isArray(others) ? new ListOfExprs(others.map(valueToDefaultExpr$1), 'equalAny') : others; return new FunctionExpression('equal_any', [this, exprOthers], 'equalAny').asBoolean(); } notEqualAny(others) { const exprOthers = Array.isArray(others) ? new ListOfExprs(others.map(valueToDefaultExpr$1), 'notEqualAny') : others; return new FunctionExpression('not_equal_any', [this, exprOthers], 'notEqualAny').asBoolean(); } /** * @beta * Creates an expression that checks if a field exists in the document. * * @example * ```typescript * // Check if the document has a field named "phoneNumber" * field("phoneNumber").exists(); * ``` * * @returns A new `Expression` representing the 'exists' check. */ exists() { return new FunctionExpression('exists', [this], 'exists').asBoolean(); } /** * @beta * Creates an expression that calculates the character length of a string in UTF-8. * * @example * ```typescript * // Get the character length of the 'name' field in its UTF-8 form. * field("name").charLength(); * ``` * * @returns A new `Expression` representing the length of the string. */ charLength() { return new FunctionExpression('char_length', [this], 'charLength'); } like(stringOrExpr) { return new FunctionExpression('like', [this, valueToDefaultExpr$1(stringOrExpr)], 'like').asBoolean(); } regexContains(stringOrExpr) { return new FunctionExpression('regex_contains', [this, valueToDefaultExpr$1(stringOrExpr)], 'regexContains').asBoolean(); } regexFind(stringOrExpr) { return new FunctionExpression('regex_find', [this, valueToDefaultExpr$1(stringOrExpr)], 'regexFind'); } regexFindAll(stringOrExpr) { return new FunctionExpression('regex_find_all', [this, valueToDefaultExpr$1(stringOrExpr)], 'regexFindAll'); } regexMatch(stringOrExpr) { return new FunctionExpression('regex_match', [this, valueToDefaultExpr$1(stringOrExpr)], 'regexMatch').asBoolean(); } stringContains(stringOrExpr) { return new FunctionExpression('string_contains', [this, valueToDefaultExpr$1(stringOrExpr)], 'stringContains').asBoolean(); } startsWith(stringOrExpr) { return new FunctionExpression('starts_with', [this, valueToDefaultExpr$1(stringOrExpr)], 'startsWith').asBoolean(); } endsWith(stringOrExpr) { return new FunctionExpression('ends_with', [this, valueToDefaultExpr$1(stringOrExpr)], 'endsWith').asBoolean(); } /** * @beta * Creates an expression that converts a string to lowercase. * * @example * ```typescript * // Convert the 'name' field to lowercase * field("name").toLower(); * ``` * * @returns A new `Expression` representing the lowercase string. */ toLower() { return new FunctionExpression('to_lower', [this], 'toLower'); } /** * @beta * Creates an expression that converts a string to uppercase. * * @example * ```typescript * // Convert the 'title' field to uppercase * field("title").toUpper(); * ``` * * @returns A new `Expression` representing the uppercase string. */ toUpper() { return new FunctionExpression('to_upper', [this], 'toUpper'); } /** * @beta * Creates an expression that removes leading and trailing characters from a string or byte array. * * @example * ```typescript * // Trim whitespace from the 'userInput' field * field("userInput").trim(); * * // Trim quotes from the 'userInput' field * field("userInput").trim('"'); * ``` * @param valueToTrim - Optional This parameter is treated as a set of characters or bytes that will be * trimmed from the input. If not specified, then whitespace will be trimmed. * @returns A new `Expression` representing the trimmed string or byte array. */ trim(valueToTrim) { const args = [this]; if (valueToTrim) { args.push(valueToDefaultExpr$1(valueToTrim)); } return new FunctionExpression('trim', args, 'trim'); } /** * @beta * Trims whitespace or a specified set of characters/bytes from the beginning of a string or byte array. * * @example * ```typescript * // Trim whitespace from the beginning of the 'userInput' field * field("userInput").ltrim(); * * // Trim quotes from the beginning of the 'userInput' field * field("userInput").ltrim('"'); * ``` * * @param valueToTrim - Optional. A string or byte array containing the characters/bytes to trim. * If not specified, whitespace will be trimmed. * @returns A new `Expression` representing the trimmed string. */ ltrim(valueToTrim) { const args = [this]; if (valueToTrim) { args.push(valueToDefaultExpr$1(valueToTrim)); } return new FunctionExpression('ltrim', args, 'ltrim'); } /** * @beta * Trims whitespace or a specified set of characters/bytes from the end of a string or byte array. * * @example * ```typescript * // Trim whitespace from the end of the 'userInput' field * field("userInput").rtrim(); * * // Trim quotes from the end of the 'userInput' field * field("userInput").rtrim('"'); * ``` * * @param valueToTrim - Optional. A string or byte array containing the characters/bytes to trim. * If not specified, whitespace will be trimmed. * @returns A new `Expression` representing the trimmed string or byte array. */ rtrim(valueToTrim) { const args = [this]; if (valueToTrim) { args.push(valueToDefaultExpr$1(valueToTrim)); } return new FunctionExpression('rtrim', args, 'rtrim'); } /** * @beta * Creates an expression that returns the data type of this expression's result, as a string. * * @remarks * This is evaluated on the backend. This means: * 1. Generic typed elements (like `array<string>`) evaluate strictly to the primitive `'array'`. * 2. Any custom `FirestoreDataConverter` mappings are ignored. * 3. For numeric values, the backend does not yield the JavaScript `"number"` type; it evaluates * precisely as `"int64"` or `"float64"`. * 4. For date or timestamp objects, the backend evaluates to `"timestamp"`. * * @example * ```typescript * // Get the data type of the value in field 'title' * field('title').type() * ``` * * @returns A new `Expression` representing the data type. */ type() { return new FunctionExpression('type', [this]); } /** * @beta * Creates an expression that checks if the result of this expression is of the given type. * * @remarks Null or undefined fields evaluate to skip/error. Use `ifAbsent()` / `isAbsent()` to evaluate missing data. * * @example * ```typescript * // Check if the 'price' field is specifically an integer (not just 'number') * field('price').isType('int64'); * ``` * * @param type - The type to check for. * @returns A new `BooleanExpression` that evaluates to true if the expression's result is of the given type, false otherwise. */ isType(type) { return new FunctionExpression('is_type', [this, constant(type)], 'isType').asBoolean(); } /** * @beta * Creates an expression that concatenates string expressions together. * * @example * ```typescript * // Combine the 'firstName', " ", and 'lastName' fields into a single string * field("firstName").stringConcat(constant(" "), field("lastName")); * ``` * * @param secondString - The additional expression or string literal to concatenate. * @param otherStrings - Optional additional expressions or string literals to concatenate. * @returns A new `Expression` representing the concatenated string. */ stringConcat(secondString, ...otherStrings) { const elements = [secondString, ...otherStrings]; const exprs = elements.map(valueToDefaultExpr$1); return new FunctionExpression('string_concat', [this, ...exprs], 'stringConcat'); } /** * @beta * Creates an expression that finds the index of the first occurrence of a substring or byte sequence. * * @example * ```typescript * // Find the index of "foo" in the 'text' field * field("text").stringIndexOf("foo"); * ``` * * @param search - The substring or byte sequence to search for. * @returns A new `Expression` representing the index of the first occurrence. */ stringIndexOf(search) { return new FunctionExpression('string_index_of', [this, valueToDefaultExpr$1(search)], 'stringIndexOf'); } /** * @beta * Creates an expression that repeats a string or byte array a specified number of times. * * @example * ```typescript * // Repeat the 'label' field 3 times * field("label").stringRepeat(3); * ``` * * @param repetitions - The number of times to repeat the string or byte array. * @returns A new `Expression` representing the repeated string or byte array. */ stringRepeat(repetitions) { return new FunctionExpression('string_repeat', [this, valueToDefaultExpr$1(repetitions)], 'stringRepeat'); } /** * @beta * Creates an expression that replaces all occurrences of a substring or byte sequence with a replacement. * * @example * ```typescript * // Replace all occurrences of "foo" with "bar" in the 'text' field * field("text").stringReplaceAll("foo", "bar"); * ``` * * @param find - The substring or byte sequence to search for. * @param replacement - The replacement string or byte sequence. * @returns A new `Expression` representing the string or byte array with replacements. */ stringReplaceAll(find, replacement) { return new FunctionExpression('string_replace_all', [this, valueToDefaultExpr$1(find), valueToDefaultExpr$1(replacement)], 'stringReplaceAll'); } /** * @beta * Creates an expression that replaces the first occurrence of a substring or byte sequence with a replacement. * * @example * ```typescript * // Replace the first occurrence of "foo" with "bar" in the 'text' field * field("text").stringReplaceOne("foo", "bar"); * ``` * * @param find - The substring or byte sequence to search for. * @param replacement - The replacement string or byte sequence. * @returns A new `Expression` representing the string or byte array with the replacement. */ stringReplaceOne(find, replacement) { return new FunctionExpression('string_replace_one', [this, valueToDefaultExpr$1(find), valueToDefaultExpr$1(replacement)], 'stringReplaceOne'); } /** * @beta * Creates an expression that concatenates expression results together. * * @example * ```typescript * // Combine the 'firstName', ' ', and 'lastName' fields into a single value. * field("firstName").concat(constant(" "), field("lastName")); * ``` * * @param second - The additional expression or literal to concatenate. * @param others - Optional additional expressions or literals to concatenate. * @returns A new `Expression` representing the concatenated value. */ concat(second, ...others) { const elements = [second, ...others]; const exprs = elements.map(valueToDefaultExpr$1); return new FunctionExpression('concat', [this, ...exprs], 'concat'); } /** * @beta * Creates an expression that reverses this string expression. * * @example * ```typescript * // Reverse the value of the 'myString' field. * field("myString").reverse(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the reversed string. */ reverse() { return new FunctionExpression('reverse', [this], 'reverse'); } /** * @beta * Returns the first element of the array. * * @example * ```typescript * // Get the first element of the 'myArray' field. * field("myArray").arrayFirst(); * ``` * * @returns A new `Expression` representing the first element. */ arrayFirst() { return new FunctionExpression('array_first', [this], 'arrayFirst'); } arrayFirstN(n) { return new FunctionExpression('array_first_n', [this, valueToDefaultExpr$1(n)], 'arrayFirstN'); } /** * @beta * Returns the last element of the array. * * @example * ```typescript * // Get the last element of the 'myArray' field. * field("myArray").arrayLast(); * ``` * * @returns A new `Expression` representing the last element. */ arrayLast() { return new FunctionExpression('array_last', [this], 'arrayLast'); } arrayLastN(n) { return new FunctionExpression('array_last_n', [this, valueToDefaultExpr$1(n)], 'arrayLastN'); } /** * @beta * Returns the maximum value in the array. * * @example * ```typescript * // Get the maximum value of the 'myArray' field. * field("myArray").arrayMaximum(); * ``` * * @returns A new `Expression` representing the maximum value. */ arrayMaximum() { return new FunctionExpression('maximum', [this], 'arrayMaximum'); } arrayMaximumN(n) { return new FunctionExpression('maximum_n', [this, valueToDefaultExpr$1(n)], 'arrayMaximumN'); } /** * @beta * Returns the minimum value in the array. * * @example * ```typescript * // Get the minimum value of the 'myArray' field. * field("myArray").arrayMinimum(); * ``` * * @returns A new `Expression` representing the minimum value. */ arrayMinimum() { return new FunctionExpression('minimum', [this], 'arrayMinimum'); } arrayMinimumN(n) { return new FunctionExpression('minimum_n', [this, valueToDefaultExpr$1(n)], 'arrayMinimumN'); } arrayIndexOf(search) { return new FunctionExpression('array_index_of', [this, valueToDefaultExpr$1(search), valueToDefaultExpr$1('first')], 'arrayIndexOf'); } arrayLastIndexOf(search) { return new FunctionExpression('array_index_of', [this, valueToDefaultExpr$1(search), valueToDefaultExpr$1('last')], 'arrayLastIndexOf'); } arrayIndexOfAll(search) { return new FunctionExpression('array_index_of_all', [this, valueToDefaultExpr$1(search)], 'arrayIndexOfAll'); } /** * @beta * Creates an expression that calculates the length of this string expression in bytes. * * @example * ```typescript * // Calculate the length of the 'myString' field in bytes. * field("myString").byteLength(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the length of the string in bytes. */ byteLength() { return new FunctionExpression('byte_length', [this], 'byteLength'); } /** * @beta * Creates an expression that computes the ceiling of a numeric value. * * @example * ```typescript * // Compute the ceiling of the 'price' field. * field("price").ceil(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the ceiling of the numeric value. */ ceil() { return new FunctionExpression('ceil', [this]); } /** * @beta * Creates an expression that computes the floor of a numeric value. * * @example * ```typescript * // Compute the floor of the 'price' field. * field("price").floor(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the floor of the numeric value. */ floor() { return new FunctionExpression('floor', [this]); } /** * @beta * Creates an expression that computes the absolute value of a numeric value. * * @example * ```typescript * // Compute the absolute value of the 'price' field. * field("price").abs(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the absolute value of the numeric value. */ abs() { return new FunctionExpression('abs', [this]); } /** * @beta * Creates an expression that computes e to the power of this expression. * * @example * ```typescript * // Compute e to the power of the 'value' field. * field("value").exp(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the exp of the numeric value. */ exp() { return new FunctionExpression('exp', [this]); } /** * @beta * Accesses a value from a map (object) field using the provided key. * * @example * ```typescript * // Get the 'city' value from the 'address' map field * field("address").mapGet("city"); * ``` * * @param subfield - The key to access in the map. * @returns A new `Expression` representing the value associated with the given key in the map. */ mapGet(subfield) { return new FunctionExpression('map_get', [this, constant(subfield)], 'mapGet'); } /** * @beta * Creates an expression that returns a new map with the specified entries added or updated. * * @remarks * Note that `mapSet` only performs shallow updates to the map. Setting a value to `null` * will retain the key with a `null` value. To remove a key entirely, use `mapRemove`. * * @example * ```typescript * // Set the 'city' to "San Francisco" in the 'address' map * field("address").mapSet("city", "San Francisco"); * ``` * * @param key - The key to set. Must be a string or a constant string expression. * @param value - The value to set. * @param moreKeyValues - Additional key-value pairs to set. * @returns A new `Expression` representing the map with the entries set. */ mapSet(key, value, ...moreKeyValues) { const args = [ this, valueToDefaultExpr$1(key), valueToDefaultExpr$1(value), ...moreKeyValues.map(valueToDefaultExpr$1) ]; return new FunctionExpression('map_set', args, 'mapSet'); } /** * @beta * Creates an expression that returns the keys of a map. * * @remarks * While the backend generally preserves insertion order, relying on the * order of the output array is not guaranteed and should be avoided. * * @example * ```typescript * // Get the keys of the 'address' map * field("address").mapKeys(); * ``` * * @returns A new `Expression` representing the keys of the map. */ mapKeys() { return new FunctionExpression('map_keys', [this], 'mapKeys'); } /** * @beta * Creates an expression that returns the values of a map. * * @remarks * While the backend generally preserves insertion order, relying on the * order of the output array is not guaranteed and should be avoided. * * @example * ```typescript * // Get the values of the 'address' map * field("address").mapValues(); * ``` * * @returns A new `Expression` representing the values of the map. */ mapValues() { return new FunctionExpression('map_values', [this], 'mapValues'); } /** * @beta * Creates an expression that returns the entries of a map as an array of maps, * where each map contains a `"k"` property for the key and a `"v"` property for the value. * For example: `[{ k: "key1", v: "value1" }, ...]`. * * @example * ```typescript * // Get the entries of the 'address' map * field("address").mapEntries(); * ``` * * @returns A new `Expression` representing the entries of the map. */ mapEntries() { return new FunctionExpression('map_entries', [this], 'mapEntries'); } /** * @beta * Creates an aggregation that counts the number of stage inputs with valid evaluations of the * expression or field. * * @example * ```typescript * // Count the total number of products * field("productId").count().as("totalProducts"); * ``` * * @returns A new `AggregateFunction` representing the 'count' aggregation. */ count() { return AggregateFunction._create('count', [this], 'count'); } /** * @beta * Creates an aggregation that calculates the sum of a numeric field across multiple stage inputs. * * @example * ```typescript * // Calculate the total revenue from a set of orders * field("orderAmount").sum().as("totalRevenue"); * ``` * * @returns A new `AggregateFunction` representing the 'sum' aggregation. */ sum() { return AggregateFunction._create('sum', [this], 'sum'); } /** * @beta * Creates an aggregation that calculates the average (mean) of a numeric field across multiple * stage inputs. * * @example * ```typescript * // Calculate the average age of users * field("age").average().as("averageAge"); * ``` * * @returns A new `AggregateFunction` representing the 'average' aggregation. */ average() { return AggregateFunction._create('average', [this], 'average'); } /** * @beta * Creates an aggregation that finds the minimum value of a field across multiple stage inputs. * * @example * ```typescript * // Find the lowest price of all products * field("price").minimum().as("lowestPrice"); * ``` * * @returns A new `AggregateFunction` representing the 'minimum' aggregation. */ minimum() { return AggregateFunction._create('minimum', [this], 'minimum'); } /** * @beta * Creates an aggregation that finds the maximum value of a field across multiple stage inputs. * * @example * ```typescript * // Find the highest score in a leaderboard * field("score").maximum().as("highestScore"); * ``` * * @returns A new `AggregateFunction` representing the 'maximum' aggregation. */ maximum() { return AggregateFunction._create('maximum', [this], 'maximum'); } /** * @beta * Creates an aggregation that finds the first value of an expression across multiple stage inputs. * * @example * ```typescript * // Find the first value of the 'rating' field * field("rating").first().as("firstRating"); * ``` * * @returns A new `AggregateFunction` representing the 'first' aggregation. */ first() { return AggregateFunction._create('first', [this], 'first'); } /** * @beta * Creates an aggregation that finds the last value of an expression across multiple stage inputs. * * @example * ```typescript * // Find the last value of the 'rating' field * field("rating").last().as("lastRating"); * ``` * * @returns A new `AggregateFunction` representing the 'last' aggregation. */ last() { return AggregateFunction._create('last', [this], 'last'); } /** * @beta * Creates an aggregation that collects all values of an expression across multiple stage inputs * into an array. * * @remarks * If the expression resolves to an absent value, it is converted to `null`. * The order of elements in the output array is not stable and shouldn't be relied upon. * * @example * ```typescript * // Collect all tags from books into an array * field("tags").arrayAgg().as("allTags"); * ``` * * @returns A new `AggregateFunction` representing the 'array_agg' aggregation. */ arrayAgg() { return AggregateFunction._create('array_agg', [this], 'arrayAgg'); } /** * @beta * Creates an aggregation that collects all distinct values of an expression across multiple stage * inputs into an array. * * @remarks * If the expression resolves to an absent value, it is converted to `null`. * The order of elements in the output array is not stable and shouldn't be relied upon. * * @example * ```typescript * // Collect all distinct tags from books into an array * field("tags").arrayAggDistinct().as("allDistinctTags"); * ``` * * @returns A new `AggregateFunction` representing the 'array_agg_distinct' aggregation. */ arrayAggDistinct() { return AggregateFunction._create('array_agg_distinct', [this], 'arrayAggDistinct'); } /** * @beta * Creates an aggregation that counts the number of distinct values of the expression or field. * * @example * ```typescript * // Count the distinct number of products * field("productId").countDistinct().as("distinctProducts"); * ``` * * @returns A new `AggregateFunction` representing the 'count_distinct' aggregation. */ countDistinct() { return AggregateFunction._create('count_distinct', [this], 'countDistinct'); } /** * @beta * Creates an expression that returns the larger value between this expression and another expression, based on Firestore's value type ordering. * * @example * ```typescript * // Returns the larger value between the 'timestamp' field and the current timestamp. * field("timestamp").logicalMaximum(currentTimestamp()); * ``` * * @param second - The second expression or literal to compare with. * @param others - Optional additional expressions or literals to compare with. * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the logical maximum operation. */ logicalMaximum(second, ...others) { const values = [second, ...others]; return new FunctionExpression('maximum', [this, ...values.map(valueToDefaultExpr$1)], 'logicalMaximum'); } /** * @beta * Creates an expression that returns the smaller value between this expression and another expression, based on Firestore's value type ordering. * * @example * ```typescript * // Returns the smaller value between the 'timestamp' field and the current timestamp. * field("timestamp").logicalMinimum(currentTimestamp()); * ``` * * @param second - The second expression or literal to compare with. * @param others - Optional additional expressions or literals to compare with. * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the logical minimum operation. */ logicalMinimum(second, ...others) { const values = [second, ...others]; return new FunctionExpression('minimum', [this, ...values.map(valueToDefaultExpr$1)], 'minimum'); } /** * @beta * Creates an expression that calculates the length (number of dimensions) of this Firestore Vector expression. * * @example * ```typescript * // Get the vector length (dimension) of the field 'embedding'. * field("embedding").vectorLength(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the length of the vector. */ vectorLength() { return new FunctionExpression('vector_length', [this], 'vectorLength'); } cosineDistance(other) { return new FunctionExpression('cosine_distance', [this, vectorToExpr$1(other)], 'cosineDistance'); } dotProduct(other) { return new FunctionExpression('dot_product', [this, vectorToExpr$1(other)], 'dotProduct'); } euclideanDistance(other) { return new FunctionExpression('euclidean_distance', [this, vectorToExpr$1(other)], 'euclideanDistance'); } /** * @beta * Creates an expression that interprets this expression as the number of microseconds since the Unix epoch (1970-01-01 00:00:00 UTC) * and returns a timestamp. * * @example * ```typescript * // Interpret the 'microseconds' field as microseconds since epoch. * field("microseconds").unixMicrosToTimestamp(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the timestamp. */ unixMicrosToTimestamp() { return new FunctionExpression('unix_micros_to_timestamp', [this], 'unixMicrosToTimestamp'); } /** * @beta * Creates an expression that converts this timestamp expression to the number of microseconds since the Unix epoch (1970-01-01 00:00:00 UTC). * * @example * ```typescript * // Convert the 'timestamp' field to microseconds since epoch. * field("timestamp").timestampToUnixMicros(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the number of microseconds since epoch. */ timestampToUnixMicros() { return new FunctionExpression('timestamp_to_unix_micros', [this], 'timestampToUnixMicros'); } /** * @beta * Creates an expression that interprets this expression as the number of milliseconds since the Unix epoch (1970-01-01 00:00:00 UTC) * and returns a timestamp. * * @example * ```typescript * // Interpret the 'milliseconds' field as milliseconds since epoch. * field("milliseconds").unixMillisToTimestamp(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the timestamp. */ unixMillisToTimestamp() { return new FunctionExpression('unix_millis_to_timestamp', [this], 'unixMillisToTimestamp'); } /** * @beta * Creates an expression that converts this timestamp expression to the number of milliseconds since the Unix epoch (1970-01-01 00:00:00 UTC). * * @example * ```typescript * // Convert the 'timestamp' field to milliseconds since epoch. * field("timestamp").timestampToUnixMillis(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the number of milliseconds since epoch. */ timestampToUnixMillis() { return new FunctionExpression('timestamp_to_unix_millis', [this], 'timestampToUnixMillis'); } /** * @beta * Creates an expression that interprets this expression as the number of seconds since the Unix epoch (1970-01-01 00:00:00 UTC) * and returns a timestamp. * * @example * ```typescript * // Interpret the 'seconds' field as seconds since epoch. * field("seconds").unixSecondsToTimestamp(); * ``` * * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the timestamp. */ unixSecondsToTimestamp() { return new FunctionExpression('unix_seconds_to_timestamp', [this], 'unixSeco