@firebase/firestore
Version:
The Cloud Firestore component of the Firebase JS SDK.
1,458 lines (1,456 loc) • 141 kB
JavaScript
import { bd as isPlainObject, i as FirestoreError, be as isString, bf as DOCUMENT_KEY_NAME, aE as documentId$1, f as fieldPathFromArgument, bg as hardAssert, bh as parseData, bi as toStringValue, a$ as VectorValue, a_ as vector, bj as toMapValue, t as isCollectionGroupQuery, bk as isDocumentQuery, an as doc, m as queryNormalizedOrderBy, k as FieldFilter, ab as fail, C as CompositeFilter, bl as OptionsUtil, bm as toNumber, bn as toPipelineValue, bo as isUserData, bp as isCollectionReference, D as DocumentReference, j as Code, aS as CollectionReference, bq as isOptionalEqual, aT as refEqual, br as isNumber, z as cast, F as Firestore, E as ensureFirestoreConfigured, V as UserDataReader, bs as StructuredPipelineOptions, bt as StructuredPipeline, bu as firestoreClientExecutePipeline, n as newUserDataReader, I as ExpUserDataWriter } from './common-948f0202.node.mjs';
export { bv as _internalPipelineToExecutePipelineRequestProto } from './common-948f0202.node.mjs';
import '@firebase/app';
import '@firebase/util';
import '@firebase/webchannel-wrapper/bloom-blob';
import '@firebase/logger';
import 'util';
import 'crypto';
import '@grpc/grpc-js';
import '@grpc/proto-loader';
/**
* @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();
}
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
* 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 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
* 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 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 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(Function.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(Function.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], 'unixSecondsToTimestamp');
}
/**
* @beta
* Creates an expression that converts this timestamp expression to the number of seconds since the Unix epoch (1970-01-01 00:00:00 UTC).
*
* @example
* ```typescript
* // Convert the 'timestamp' field to seconds since epoch.
* field("timestamp").timestampToUnixSeconds();
* ```
*
* @returns A new {@link @firebase/firestore/pipelines#Expression} representing the number of seconds since epoch.
*/
timestampToUnixSeconds() {
return new FunctionExpression('timestamp_to_unix_seconds', [this], 'timestampToUnixSeconds');
}
timestampAdd(unit, amount) {
return new FunctionExpression('timestamp_add', [this, valueToDefaultExpr$1(unit), valueToDefaultExpr$1(amount)], 'timestampAdd');
}
timestampSubtract(unit, amount) {
return new FunctionExpression('timestamp_subtract', [this, valueToDefaultExpr$1(unit), valueToDefaultExpr$1(amount)], 'timestampSubtract');
}
/**
* @beta
*
* Creates an expression that returns the document ID from a path.
*
* @example
* ```typescript
* // Get the document ID from a path.
* field("__path__").documentId();
* ```
*
* @returns A new {@link @firebase/firestore/pipelines#Expression} representing the documentId operation.
*/
documentId() {
return new FunctionExpression('document_id', [this], 'documentId');
}
substring(position, length) {
const positionExpr = valueToDefaultExpr$1(position);
if (length === undefined) {
return new FunctionExpression('substring', [this, positionExpr], 'substring');
}
else {
return new FunctionExpression('substring', [this, positionExpr, valueToDefaultExpr$1(length)], 'substring');
}
}
arrayGet(offset) {
return new FunctionExpression('array_get', [this, valueToDefaultExpr$1(offset)], 'arrayGet');
}
/**
* @beta
*
* Creates an expression that checks if a given expression produces an error.
*
* @example
* ```typescript
* // Check if the result of a calculation is an error
* field("title").arrayContains(1).isError();
* ```
*
* @returns A new {@link @firebase/firestore/pipelines#BooleanExpression} representing the 'isError' check.
*/
isError() {
return new FunctionExpression('is_error', [this], 'isError').asBoolean();
}
ifError(catchValue) {
const result = new FunctionExpression('if_error', [this, valueToDefaultExpr$1(catchValue)], 'ifError');
return catchValue instanceof BooleanExpression
? result.asBoolean()
: result;
}
/**
* @beta
*
* Creates an expression that returns `true` if the result of this expression
* is absent. Otherwise, returns `false` even if the value is `null`.
*
* @example
* ```typescript
* // Check if the field `value` is absent.
* field("value").isAbsent();
* @example
* ```
*
* @returns A new {@link @firebase/firestore/pipelines#BooleanExpression} representing the 'isAbsent' check.
*/
isAbsent() {
return new FunctionExpression('is_absent', [this], 'isAbsent').asBoolean();
}
mapRemove(stringExpr) {
return new FunctionExpression('map_remove', [this, valueToDefaultExpr$1(stringExpr)], 'mapRemove');
}
/**
* @beta
*
* Creates an expression that merges multiple map values.
*
* @example
* ```
* // Merges the map in the settings field with, a map literal, and a map in
* // that is conditionally returned by another expression
* field('settings').mapMerge({ enabled: true }, conditional(field('isAdmin'), { admin: true}, {})
* ```
*
* @param secondMap - A required second map to merge. Represented as a literal or
* an expression that returns a map.
* @param otherMaps - Optional additional maps to merge. Each map is represented
* as a literal or an expression that returns a map.
*
* @returns A new {@link @firebase/firestore/pipelines#Expression} representing the 'mapMerge' operation.
*/
mapMerge(secondMap, ...otherMaps) {
const secondMapExpr = valueToDefaultExpr$1(secondMap);
const otherMapExprs = otherMaps.map(valueToDefaultExpr$1);
return new FunctionExpression('map_merge', [this, secondMapExpr, ...otherMapExprs], 'mapMerge');
}
pow(exponent) {
return new FunctionExpression('pow', [this, valueToDefaultExpr$1(exponent)]);
}
round(decimalPlaces) {
if (decimalPlaces === undefined) {
return new FunctionExpression('round', [this]);
}
else {
return new FunctionExpression('round', [this, valueToDefaultExpr$1(decimalPlaces)], 'round');
}
}
/**
* @beta
* Creates an expression that returns the collection ID from a path.
*
* @example
* ```typescript
* // Get the collection ID from a path.
* field("__path__").collectionId();
* ```
*
* @returns A new {@link @firebase/firestore/pipelines#Expression} representing the collectionId operation.
*/
collectionId() {
return new FunctionExpression('collection_id', [this]);
}
/**
* @beta
* Creates an expression that calculates the length of a string, array, map, vector, or bytes.
*
* @example
* ```typescript
* // Get the length of the 'name' field.
* field("name").length();
*
* // Get the number of items in the 'cart' array.
* field("cart").length();
* ```
*
* @returns A new `Expression` representing the length of the string, array, map, vector, or bytes.
*/
length() {
return new FunctionExpression('length', [this]);
}
/**
* @beta
* Creates an expression that computes the natural logarithm of a numeric value.
*
* @example
* ```typescript
* // Compute the natural logarithm of the 'value' field.
* field("value").ln();
* ```
*
* @returns A new {@link @firebase/firestore/pipelines#Expression} representing the natural logarithm of the numeric value.
*/
ln() {
return new FunctionExpression('ln', [this]);
}
/**
* @beta
* Creates an expression that computes the square root of a numeric value.
*
* @example
* ```typescript
* // Compute the square root of the 'value' field.
* field("value").sqrt();
* ```
*
* @returns A new {@link @firebase/firestore/pipelines#Expression} representing the square root of the numeric value.
*/
sqrt() {
return new FunctionExpression('sqrt', [this]);
}
/**
* @beta
* Creates an expression that reverses a string.
*
* @example
* ```typescript
* // Reverse the value of the 'myString' field.
* field("myString").stringReverse();
* ```
*
* @returns A new {@link @firebase/firestore/pipelines#Expression} representing the reversed string.
*/
stringReverse() {
return new FunctionExpression('string_reverse', [this]);
}
ifAbsent(elseValueOrExpression) {
return new FunctionExpression('if_absent', [this, valueToDefaultExpr$1(elseValueOrExpression)], 'ifAbsent');
}
join(delimeterValueOrExpression) {
return new FunctionExpression('join', [this, valueToDefaultExpr$1(delimeterValueOrExpression)], 'join');
}
/**
* @beta
* Creates an expression that computes the base-10 logarithm of a numeric value.
*
* @example
* ```typescript
* // Compute the base-10 logarithm of the 'value' field.
* field("value").log10();
* ```
*
* @returns A new {@link @firebase/firestore/pipelines#Expression} representing the base-10 logarithm of the numeric value.
*/
log10() {
return new FunctionExpression('log10', [this]);
}
/**
* @beta
* Creates an expression that computes the sum of the elements in an array.
*
* @example
* ```typescript
* // Compute the sum of the elements in the 'scores' field.
* field("scores").arraySum();
* ```
*
* @returns A new {@link @firebase/firestore/pipelines#Expression} representing the sum of the elements in the array.
*/
arraySum() {
return new FunctionExpression('sum', [this]);
}
split(delimiter) {
return new FunctionExpression('split', [
this,
valueToDefaultExpr$1(delimiter)
]);
}
timestampTruncate(granularity, timezone) {
const internalGranularity = isString(granularity)
? granularity.toLowerCase()
: granularity;
const args = [this, valueToDefaultExpr$1(internalGranularity)];
if (timezone) {
args.push(valueToDefaultExpr$1(timezone));
}
return new FunctionExpression('timestamp_trunc', args);
}
/**
* @beta
* Creates an expression that returns the data type of this expression's result, as a string.
*
* @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]);
}
// TODO(new-expression): Add new expression method definitions above this line
/**
* @beta
* Creates an {@link @firebase/firestore/pipelines#Ordering} that sorts documents in ascending order based on this expression.
*
* @example
* ```typescript
* // Sort documents by the 'name' field in ascending order
* pipeline().collection("users")
* .sort(field("name").ascending());
* ```
*
* @returns A new `Ordering` for ascending sorting.
*/
ascending() {
return ascending(this);
}
/**
* @beta
* Creates an {@link @firebase/firestore/pipelines#Ordering} that sorts documents in descending order based on this expression.
*
* @example
* ```typescript
* // Sort documents by the 'createdAt' field in descending order
* firestore.pipeline().collection("users")
* .sort(field("createdAt").descending());
* ```
*
* @returns A new `Ordering` for descending sorting.
*/
descending() {
return descending(this);
}
/**
* @beta
* Assigns an alias to this expression.
*
* Aliases are useful for renaming fields in the output of a stage or for giving meaningful
* names to calculated values.
*
* @example
* ```typescript
* // Calculate the total price and assign it the alias "totalPrice" and add it to the output.
* firestore.pipeline().collection("items")
* .addFields(field("price").multiply(field("quantity")).as("totalPrice"));
* ```
*
* @param name - The alias to assign to this expression.
* @returns A new {@link @firebase/firestore/pipelines#AliasedExpression} that wraps this
* expression and associates it with the provided alias.
*/
as(name) {
return new AliasedExpression(this, name, 'as');
}
}
/**
* @beta
*
* A class that represents an aggregate function.
*/
class AggregateFunction {
constructor(name, params) {
this.name = name;
this.params = params;
this.exprType = 'AggregateFunction';
this._protoValueType = 'ProtoValue';
}
/**
* @internal
* @private
*/
static _create(name, params, methodName) {
const af = new AggregateFunction(name, params);
af._methodName = methodName;
return af;
}
/**
* @beta
* Assigns an alias to this AggregateFunction. The alias specifies the name that
* the aggregated value will have in the output document.
*
* @example
* ```typescript
* // Calculate the average price of all items and assign it the alias "averagePrice".
* firestore.pipeline().collection("items")
* .aggregate(field("price").average().as("averagePrice"));
* ```
*
* @param name - The alias to assign to this AggregateFunction.
* @returns A new {@link @firebase/firestore/pipelines#AliasedAggregate} that wraps this
* AggregateFunction and associates it with the provided alias.
*/
as(name) {
return new AliasedAggregate(this, name, 'as');
}
/**
* @private
* @internal
*/
_toProto(serializer) {
return {
functionValue: {
name: this.name,
args: this.params.map(p => p._toProto(serializer))
}
};
}
/**
* @private
* @internal
*/
_readUserData(context) {
context = this._methodName
? context.contextWith({ methodName: this._methodName })
: context;
this.params.forEach(expr => {
return expr._readUserData(context);
});
}
}
/**
* @beta
*
* An AggregateFunction with alias.
*/
class AliasedAggregate {
constructor(aggregate, alias, _methodName) {
this.aggregate = aggregate;
this.alias = alias;
this._methodName = _methodName;
}
/**
* @private
* @internal
*/
_readUserData(context) {
this.aggregate._readUserData(context);
}
}
/**
* @beta
*/
class AliasedExpression {
constructor(expr, alias, _methodName) {
this.expr = expr;
this.alias = alias;
this._methodName = _methodName;
this.exprType = 'AliasedExpression';
this.selectable = true;
}
/**
* @private
* @internal
*/
_readUserData(context) {
this.expr._readUserData(context);
}
}
/**
* @internal
*/
class ListOfExprs extends Expression {
constructor(exprs, _methodName) {
super();
this.exprs = exprs;
this._methodName = _methodName;
this.expressionType = 'ListOfExpressions';
}
/**
* @private
* @internal
*/
_toProto(serializer) {
return {
arrayValue: {
values: this.exprs.map(p => p._toProto(serializer))
}
};
}
/**
* @private
* @internal
*/
_readUserData(context) {
this.exprs.forEach((expr) => expr._readUserData(context));
}
}
/**
* @beta
*
* Represents a reference to a field in a Firestore document, or outputs of a {@link @firebase/firestore/pipelines#Pipeline} stage.
*
* <p>Field references are used to access document field values in expressions and to specify fields
* for sorting, filtering, and projecting data in Firestore pipelines.
*
* <p>You can create a `Field` instance using the static {@link @firebase/firestore/pipelines#field} method:
*
* @example
* ```typescript
* // Create a Field instance for the 'name' field
* const nameField = field("name");
*
* // Create a Field instance for a nested field 'address.city'
* const cityField = field("address.city");
* ```
*/
class Field extends Expression {
/**
* @internal
* @private
* @hideconstructor
* @param fieldPath
*/
constructor(fieldPath, _methodName) {
super();
this.fieldPath = fieldPath;
this._methodName = _methodName;
this.expressionType = 'Field';
this.selectable = true;
}
get fieldName() {
return this.fieldPath.canonicalString();
}
get alias() {
return this.fieldName;
}
get expr() {
return this;
}
/**
* @private
* @internal
*/
_toProto(serializer) {
return {
fieldReferenceValue: this.fieldPath.canonicalString()
};
}
/**
* @private
* @internal
*/
_readUserData(context) { }
}
function field(nameOrPath) {
return _field(nameOrPath, 'field');
}
function _field(nameOrPath, methodName) {
if (typeof nameOrPath === 'string') {
if (DOCUMENT_KEY_NAME === nameOrPath) {
return new Field(documentId$1()._internalPath, methodName);
}
return new Field(fieldPathFromArgument('field', nameOrPath), methodName);
}
else {
return new Field(nameOrPath._internalPath, methodName);
}
}
/**
* @internal
*
* Represents a constant value that can be used in a Firestore pipeline expression.
*
* You can create a `Constant` instance using the static {@link @firebase/firestore/pipelines#field} method:
*
* @example
* ```typescript
* // Create a Constant instance for the number 10
* const ten = constant(10);
*
* // Create a Constant instance for the string "hello"
* const hello = constant("hello");
* ```
*/
class Constant extends Expression {
/**
* @private
* @internal
* @hideconstructor
* @param value - The value of the constant.
*/
constructor(value, _methodName) {
super();
this.value = value;
this._methodName = _methodName;
this.expressionType = 'Constant';
}
/**
* @private
* @internal
*/
static _fromProto(value) {
const result = new Constant(value, undefined);
result._protoValue = value;
return result;
}
/**
* @private
* @internal
*/
_toProto(_) {
hardAssert(this._protoValue !== undefined, 0x00ed);
return this._protoValue;
}
/**
* @private
* @internal
*/
_readUserData(context) {
context = this._methodName
? context.contextWith({ methodName: this._methodName })
: context;
if (isFirestoreValue(this._protoValue)) {
return;
}
else {
this._protoValue = parseDat