From 3f47f69d055a514aa79644465dbd43eca07ad735 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Wed, 18 Feb 2026 13:09:10 -0500 Subject: [PATCH 01/12] add new expressions --- api-report/firestore.api.md | 238 +++++++ dev/src/pipelines/expression.ts | 1101 +++++++++++++++++++++++++++++++ dev/src/pipelines/index.ts | 13 + dev/system-test/pipeline.ts | 572 +++++++++++++++- 4 files changed, 1923 insertions(+), 1 deletion(-) diff --git a/api-report/firestore.api.md b/api-report/firestore.api.md index aeab4db41..980148e44 100644 --- a/api-report/firestore.api.md +++ b/api-report/firestore.api.md @@ -211,6 +211,54 @@ function arrayContainsAny(array: Expression, values: Expression): BooleanExpress // @beta function arrayContainsAny(fieldName: string, values: Expression): BooleanExpression; +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayFilter(fieldName: string, variable: string, predicate: BooleanExpression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayFilter(arrayExpression: Expression, variable: string, predicate: BooleanExpression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayFirst(fieldName: string): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayFirst(arrayExpression: Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayFirstN(fieldName: string, n: number): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayFirstN(fieldName: string, n: Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayFirstN(arrayExpression: Expression, n: number): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayFirstN(arrayExpression: Expression, n: Expression): FunctionExpression; + // @beta function arrayGet(arrayField: string, index: number): FunctionExpression; @@ -223,18 +271,174 @@ function arrayGet(arrayExpression: Expression, index: number): FunctionExpressio // @beta function arrayGet(arrayExpression: Expression, indexExpr: Expression): FunctionExpression; +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayIndexOf(fieldName: string, search: unknown | Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayIndexOf(arrayExpression: Expression, search: unknown | Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayIndexOfAll(fieldName: string, search: unknown | Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayIndexOfAll(arrayExpression: Expression, search: unknown | Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayLast(fieldName: string): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayLast(arrayExpression: Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayLastIndexOf(fieldName: string, search: unknown | Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayLastIndexOf(arrayExpression: Expression, search: unknown | Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayLastN(fieldName: string, n: number): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayLastN(fieldName: string, n: Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayLastN(arrayExpression: Expression, n: number): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayLastN(arrayExpression: Expression, n: Expression): FunctionExpression; + // @beta function arrayLength(fieldName: string): FunctionExpression; // @beta function arrayLength(array: Expression): FunctionExpression; +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayMaximum(fieldName: string): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayMaximum(arrayExpression: Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayMaximumN(fieldName: string, n: number): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayMaximumN(fieldName: string, n: Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayMaximumN(arrayExpression: Expression, n: number): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayMaximumN(arrayExpression: Expression, n: Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayMinimum(fieldName: string): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayMinimum(arrayExpression: Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayMinimumN(fieldName: string, n: number): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayMinimumN(fieldName: string, n: Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayMinimumN(arrayExpression: Expression, n: number): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arrayMinimumN(arrayExpression: Expression, n: Expression): FunctionExpression; + // @beta function arrayReverse(fieldName: string): FunctionExpression; // @beta function arrayReverse(arrayExpression: Expression): FunctionExpression; +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arraySlice(fieldName: string, start: number | Expression, end?: number | Expression): FunctionExpression; + +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// +// @beta +function arraySlice(arrayExpression: Expression, start: number | Expression, end?: number | Expression): FunctionExpression; + // @beta function arraySum(fieldName: string): FunctionExpression; @@ -965,10 +1169,31 @@ abstract class Expression implements firestore.Pipelines.Expression, HasUserData arrayContainsAll(arrayExpression: Expression): BooleanExpression; arrayContainsAny(values: Array): BooleanExpression; arrayContainsAny(arrayExpression: Expression): BooleanExpression; + arrayFilter(variable: string, predicate: BooleanExpression): FunctionExpression; + arrayFirst(): FunctionExpression; + arrayFirstN(n: number): FunctionExpression; + arrayFirstN(n: Expression): FunctionExpression; arrayGet(index: number): FunctionExpression; arrayGet(indexExpr: Expression): FunctionExpression; + arrayIndexOf(search: unknown): FunctionExpression; + arrayIndexOf(search: Expression): FunctionExpression; + arrayIndexOfAll(search: unknown): FunctionExpression; + arrayIndexOfAll(search: Expression): FunctionExpression; + arrayLast(): FunctionExpression; + arrayLastIndexOf(search: unknown): FunctionExpression; + arrayLastIndexOf(search: Expression): FunctionExpression; + arrayLastN(n: number): FunctionExpression; + arrayLastN(n: Expression): FunctionExpression; arrayLength(): FunctionExpression; + arrayMaximum(): FunctionExpression; + arrayMaximumN(n: number): FunctionExpression; + arrayMaximumN(n: Expression): FunctionExpression; + arrayMinimum(): FunctionExpression; + arrayMinimumN(n: number): FunctionExpression; + arrayMinimumN(n: Expression): FunctionExpression; arrayReverse(): FunctionExpression; + arraySlice(start: number, end?: number): FunctionExpression; + arraySlice(start: Expression, end?: Expression): FunctionExpression; arraySum(): FunctionExpression; as(name: string): AliasedExpression; asBoolean(): BooleanExpression; @@ -1829,6 +2054,19 @@ declare namespace Pipelines { equalAny, map, array, + arrayFilter, + arrayFirst, + arrayLast, + arrayFirstN, + arrayLastN, + arrayIndexOf, + arrayIndexOfAll, + arrayLastIndexOf, + arrayMaximum, + arrayMinimum, + arrayMaximumN, + arrayMinimumN, + arraySlice, field, xor, AggregateFunction, diff --git a/dev/src/pipelines/expression.ts b/dev/src/pipelines/expression.ts index 081b822bb..5a0cc7191 100644 --- a/dev/src/pipelines/expression.ts +++ b/dev/src/pipelines/expression.ts @@ -641,6 +641,387 @@ export abstract class Expression return new FunctionExpression('array_length', [this]); } + /** + * @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(): FunctionExpression { + return new FunctionExpression('array_first', [this]); + } + + /** + * @beta + * Returns the first `n` elements of the array. + * + * @example + * ```typescript + * // Get the first 3 elements of the 'myArray' field. + * field("myArray").arrayFirstN(3); + * ``` + * + * @param n The number of elements to return. + * @returns A new `Expression` representing the first `n` elements. + */ + arrayFirstN(n: number): FunctionExpression; + + /** + * @beta + * Returns the first `n` elements of the array. + * + * @example + * ```typescript + * // Get the first n elements of the 'myArray' field. + * field("myArray").arrayFirstN(field("count")); + * ``` + * + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the first `n` elements. + */ + arrayFirstN(n: Expression): FunctionExpression; + arrayFirstN(n: number | Expression): FunctionExpression { + return new FunctionExpression('array_first_n', [ + this, + valueToDefaultExpr(n), + ]); + } + + /** + * @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(): FunctionExpression { + return new FunctionExpression('array_last', [this]); + } + + /** + * @beta + * Returns the last `n` elements of the array. + * + * @example + * ```typescript + * // Get the last 3 elements of the 'myArray' field. + * field("myArray").arrayLastN(3); + * ``` + * + * @param n The number of elements to return. + * @returns A new `Expression` representing the last `n` elements. + */ + arrayLastN(n: number): FunctionExpression; + + /** + * @beta + * Returns the last `n` elements of the array. + * + * @example + * ```typescript + * // Get the last n elements of the 'myArray' field. + * field("myArray").arrayLastN(field("count")); + * ``` + * + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the last `n` elements. + */ + arrayLastN(n: Expression): FunctionExpression; + arrayLastN(n: number | Expression): FunctionExpression { + return new FunctionExpression('array_last_n', [ + this, + valueToDefaultExpr(n), + ]); + } + + /** + * @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(): FunctionExpression { + return new FunctionExpression('maximum', [this]); + } + + /** + * @beta + * Returns the largest `n` elements of the array. + * + * @example + * ```typescript + * // Get the largest 3 elements of the 'myArray' field. + * field("myArray").arrayMaximumN(3); + * ``` + * + * @param n The number of elements to return. + * @returns A new `Expression` representing the largest `n` elements. + */ + arrayMaximumN(n: number): FunctionExpression; + + /** + * @beta + * Returns the largest `n` elements of the array. + * + * @example + * ```typescript + * // Get the largest n elements of the 'myArray' field. + * field("myArray").arrayMaximumN(field("count")); + * ``` + * + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the largest `n` elements. + */ + arrayMaximumN(n: Expression): FunctionExpression; + arrayMaximumN(n: number | Expression): FunctionExpression { + return new FunctionExpression('maximum_n', [this, valueToDefaultExpr(n)]); + } + + /** + * @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(): FunctionExpression { + return new FunctionExpression('minimum', [this]); + } + + /** + * @beta + * Returns the smallest `n` elements of the array. + * + * @example + * ```typescript + * // Get the smallest 3 elements of the 'myArray' field. + * field("myArray").arrayMinimumN(3); + * ``` + * + * @param n The number of elements to return. + * @returns A new `Expression` representing the smallest `n` elements. + */ + arrayMinimumN(n: number): FunctionExpression; + + /** + * @beta + * Returns the smallest `n` elements of the array. + * + * @example + * ```typescript + * // Get the smallest n elements of the 'myArray' field. + * field("myArray").arrayMinimumN(field("count")); + * ``` + * + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the smallest `n` elements. + */ + arrayMinimumN(n: Expression): FunctionExpression; + arrayMinimumN(n: number | Expression): FunctionExpression { + return new FunctionExpression('minimum_n', [this, valueToDefaultExpr(n)]); + } + + /** + * @beta + * Returns a slice of the array. + * + * @example + * ```typescript + * // Get a slice of the 'myArray' field from index 1 to 3 (inclusive). + * field("myArray").arraySlice(1, 3); + * ``` + * + * @param start The index to start the slice. + * @param end The index to end the slice (inclusive). + * @returns A new `Expression` representing the slice. + */ + arraySlice(start: number, end?: number): FunctionExpression; + + /** + * @beta + * Returns a slice of the array. + * + * @example + * ```typescript + * // Get a slice of the 'myArray' field from index value in 'start' field to + * // index value in 'end' field (inclusive). + * field("myArray").arraySlice(field("start"), field("end")); + * ``` + * + * @param start An expression evaluating to the index to start the slice. + * @param end An expression evaluating to the index to end the slice (inclusive). + * @returns A new `Expression` representing the slice. + */ + arraySlice(start: Expression, end?: Expression): FunctionExpression; + arraySlice( + start: number | Expression, + end?: number | Expression, + ): FunctionExpression { + const args = [this, valueToDefaultExpr(start)]; + if (end !== undefined) { + args.push(valueToDefaultExpr(end)); + } + return new FunctionExpression('array_slice', args); + } + + /** + * @beta + * Returns the first index of the search value in the array, or -1 if not found. + * + * @example + * ```typescript + * // Get the first index of the value 3 in the 'myArray' field. + * field("myArray").arrayIndexOf(3); + * ``` + * + * @param search The value to search for. + * @returns A new `Expression` representing the index. + */ + arrayIndexOf(search: unknown): FunctionExpression; + + /** + * @beta + * Returns the first index of the search value in the array, or -1 if not found. + * + * @example + * ```typescript + * // Get the first index of the value in 'searchVal' field in the 'myArray' field. + * field("myArray").arrayIndexOf(field("searchVal")); + * ``` + * + * @param search An expression evaluating to the value to search for. + * @returns A new `Expression` representing the index. + */ + arrayIndexOf(search: Expression): FunctionExpression; + arrayIndexOf(search: unknown | Expression): FunctionExpression { + return new FunctionExpression('array_index_of', [ + this, + valueToDefaultExpr(search), + valueToDefaultExpr('first'), + ]); + } + + /** + * @beta + * Returns the last index of the search value in the array, or -1 if not found. + * + * @example + * ```typescript + * // Get the last index of the value 3 in the 'myArray' field. + * field("myArray").arrayLastIndexOf(3); + * ``` + * + * @param search The value to search for. + * @returns A new `Expression` representing the index. + */ + arrayLastIndexOf(search: unknown): FunctionExpression; + + /** + * @beta + * Returns the last index of the search value in the array, or -1 if not found. + * + * @example + * ```typescript + * // Get the last index of the value in 'searchVal' field in the 'myArray' field. + * field("myArray").arrayLastIndexOf(field("searchVal")); + * ``` + * + * @param search An expression evaluating to the value to search for. + * @returns A new `Expression` representing the index. + */ + arrayLastIndexOf(search: Expression): FunctionExpression; + arrayLastIndexOf(search: unknown | Expression): FunctionExpression { + return new FunctionExpression('array_index_of', [ + this, + valueToDefaultExpr(search), + valueToDefaultExpr('last'), + ]); + } + + /** + * @beta + * Returns all indices of the search value in the array. + * + * @example + * ```typescript + * // Get all indices of the value 3 in the 'myArray' field. + * field("myArray").arrayIndexOfAll(3); + * ``` + * + * @param search The value to search for. + * @returns A new `Expression` representing the indices. + */ + arrayIndexOfAll(search: unknown): FunctionExpression; + + /** + * @beta + * Returns all indices of the search value in the array. + * + * @example + * ```typescript + * // Get all indices of the value in 'searchVal' field in the 'myArray' field. + * field("myArray").arrayIndexOfAll(field("searchVal")); + * ``` + * + * @param search An expression evaluating to the value to search for. + * @returns A new `Expression` representing the indices. + */ + arrayIndexOfAll(search: Expression): FunctionExpression; + arrayIndexOfAll(search: unknown | Expression): FunctionExpression { + return new FunctionExpression('array_index_of_all', [ + this, + valueToDefaultExpr(search), + ]); + } + + /** + * @beta + * Returns a filtered array containing only elements that match the predicate. + * + * @example + * ```typescript + * // Get a filtered array of the 'scores' field containing only elements greater than 50. + * field("scores").arrayFilter("score", field("score").greaterThan(50)); + * ``` + * + * @param variable The variable name to bind to each element in the array. This variable name + * can be used in the `predicate` expression to refer to the current element. + * @param predicate The predicate boolean expression to filter by. + * @returns A new `Expression` representing the filtered array. + */ + arrayFilter( + variable: string, + predicate: BooleanExpression, + ): FunctionExpression { + return new FunctionExpression('array_filter', [ + this, + valueToDefaultExpr(variable), + predicate, + ]); + } + /** * @beta * Creates an expression that checks if this expression is equal to any of the provided values or @@ -8021,6 +8402,726 @@ export function type( return fieldOrExpression(fieldNameOrExpression).type(); } +/** + * @beta + * + * Creates an expression that returns the first element of an array. + * + * @example + * ```typescript + * // Get the first tag from the 'tags' array field + * arrayFirst("tags"); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @returns A new {Expression} representing the first element. + */ +export function arrayFirst(fieldName: string): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the first element of an array. + * + * @example + * ```typescript + * // Get the first tag from the 'tags' array field + * arrayFirst(field("tags")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @returns A new {Expression} representing the first element. + */ +export function arrayFirst(arrayExpression: Expression): FunctionExpression; +export function arrayFirst(array: Expression | string): FunctionExpression { + return fieldOrExpression(array).arrayFirst(); +} + +/** + * @beta + * + * Creates an expression that returns the first `n` elements of an array. + * + * @example + * ```typescript + * // Get the first 3 tags from the 'tags' array field + * arrayFirstN("tags", 3); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - The number of elements to return. + * @returns A new {Expression} representing the first `n` elements. + */ +export function arrayFirstN(fieldName: string, n: number): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the first `n` elements of an array. + * + * @example + * ```typescript + * // Get the first n tags from the 'tags' array field + * arrayFirstN("tags", field("count")); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {Expression} representing the first `n` elements. + */ +export function arrayFirstN( + fieldName: string, + n: Expression, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the first `n` elements of an array. + * + * @example + * ```typescript + * // Get the first 3 elements from an array expression + * arrayFirstN(field("tags"), 3); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - The number of elements to return. + * @returns A new {Expression} representing the first `n` elements. + */ +export function arrayFirstN( + arrayExpression: Expression, + n: number, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the first `n` elements of an array. + * + * @example + * ```typescript + * // Get the first n elements from an array expression + * arrayFirstN(field("tags"), field("count")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {Expression} representing the first `n` elements. + */ +export function arrayFirstN( + arrayExpression: Expression, + n: Expression, +): FunctionExpression; +export function arrayFirstN( + array: Expression | string, + n: Expression | number, +): FunctionExpression { + return fieldOrExpression(array).arrayFirstN(valueToDefaultExpr(n)); +} + +/** + * @beta + * + * Creates an expression that returns the last element of an array. + * + * @example + * ```typescript + * // Get the last tag from the 'tags' array field + * arrayLast("tags"); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @returns A new {Expression} representing the last element. + */ +export function arrayLast(fieldName: string): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the last element of an array. + * + * @example + * ```typescript + * // Get the last tag from the 'tags' array field + * arrayLast(field("tags")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @returns A new {Expression} representing the last element. + */ +export function arrayLast(arrayExpression: Expression): FunctionExpression; +export function arrayLast(array: Expression | string): FunctionExpression { + return fieldOrExpression(array).arrayLast(); +} + +/** + * @beta + * + * Creates an expression that returns the last `n` elements of an array. + * + * @example + * ```typescript + * // Get the last 3 tags from the 'tags' array field + * arrayLastN("tags", 3); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - The number of elements to return. + * @returns A new {Expression} representing the last `n` elements. + */ +export function arrayLastN(fieldName: string, n: number): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the last `n` elements of an array. + * + * @example + * ```typescript + * // Get the last n tags from the 'tags' array field + * arrayLastN("tags", field("count")); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {Expression} representing the last `n` elements. + */ +export function arrayLastN( + fieldName: string, + n: Expression, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the last `n` elements of an array. + * + * @example + * ```typescript + * // Get the last 3 elements from an array expression + * arrayLastN(field("tags"), 3); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - The number of elements to return. + * @returns A new {Expression} representing the last `n` elements. + */ +export function arrayLastN( + arrayExpression: Expression, + n: number, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the last `n` elements of an array. + * + * @example + * ```typescript + * // Get the last n elements from an array expression + * arrayLastN(field("tags"), field("count")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {Expression} representing the last `n` elements. + */ +export function arrayLastN( + arrayExpression: Expression, + n: Expression, +): FunctionExpression; +export function arrayLastN( + array: Expression | string, + n: Expression | number, +): FunctionExpression { + return fieldOrExpression(array).arrayLastN(valueToDefaultExpr(n)); +} + +/** + * @beta + * + * Creates an expression that returns the maximum value in an array. + * + * @example + * ```typescript + * // Get the maximum value from the 'scores' array field + * arrayMaximum("scores"); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @returns A new {Expression} representing the maximum value. + */ +export function arrayMaximum(fieldName: string): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the maximum value in an array. + * + * @example + * ```typescript + * // Get the maximum value from the 'scores' array field + * arrayMaximum(field("scores")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @returns A new {Expression} representing the maximum value. + */ +export function arrayMaximum(arrayExpression: Expression): FunctionExpression; +export function arrayMaximum(array: Expression | string): FunctionExpression { + return fieldOrExpression(array).arrayMaximum(); +} + +/** + * @beta + * + * Creates an expression that returns the largest `n` elements of an array. + * + * @example + * ```typescript + * // Get the top 3 scores from the 'scores' array field + * arrayMaximumN("scores", 3); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - The number of elements to return. + * @returns A new {Expression} representing the largest `n` elements. + */ +export function arrayMaximumN(fieldName: string, n: number): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the largest `n` elements of an array. + * + * @example + * ```typescript + * // Get the top n scores from the 'scores' array field + * arrayMaximumN("scores", field("count")); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {Expression} representing the largest `n` elements. + */ +export function arrayMaximumN( + fieldName: string, + n: Expression, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the largest `n` elements of an array. + * + * @example + * ```typescript + * // Get the top 3 elements from an array expression + * arrayMaximumN(field("scores"), 3); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - The number of elements to return. + * @returns A new {Expression} representing the largest `n` elements. + */ +export function arrayMaximumN( + arrayExpression: Expression, + n: number, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the largest `n` elements of an array. + * + * @example + * ```typescript + * // Get the top n elements from an array expression + * arrayMaximumN(field("scores"), field("count")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {Expression} representing the largest `n` elements. + */ +export function arrayMaximumN( + arrayExpression: Expression, + n: Expression, +): FunctionExpression; +export function arrayMaximumN( + array: Expression | string, + n: Expression | number, +): FunctionExpression { + return fieldOrExpression(array).arrayMaximumN(valueToDefaultExpr(n)); +} + +/** + * @beta + * + * Creates an expression that returns the minimum value in an array. + * + * @example + * ```typescript + * // Get the minimum value from the 'scores' array field + * arrayMinimum("scores"); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @returns A new {Expression} representing the minimum value. + */ +export function arrayMinimum(fieldName: string): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the minimum value in an array. + * + * @example + * ```typescript + * // Get the minimum value from the 'scores' array field + * arrayMinimum(field("scores")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @returns A new {Expression} representing the minimum value. + */ +export function arrayMinimum(arrayExpression: Expression): FunctionExpression; +export function arrayMinimum(array: Expression | string): FunctionExpression { + return fieldOrExpression(array).arrayMinimum(); +} + +/** + * @beta + * + * Creates an expression that returns the smallest `n` elements of an array. + * + * @example + * ```typescript + * // Get the bottom 3 scores from the 'scores' array field + * arrayMinimumN("scores", 3); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - The number of elements to return. + * @returns A new {Expression} representing the smallest `n` elements. + */ +export function arrayMinimumN(fieldName: string, n: number): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the smallest `n` elements of an array. + * + * @example + * ```typescript + * // Get the bottom n scores from the 'scores' array field + * arrayMinimumN(field("scores"), field("count")); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {Expression} representing the smallest `n` elements. + */ +export function arrayMinimumN( + fieldName: string, + n: Expression, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the smallest `n` elements of an array. + * + * @example + * ```typescript + * // Get the bottom 3 scores from the 'scores' array field + * arrayMinimumN(field("scores"), 3); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - The number of elements to return. + * @returns A new {Expression} representing the smallest `n` elements. + */ +export function arrayMinimumN( + arrayExpression: Expression, + n: number, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the smallest `n` elements of an array. + * + * @example + * ```typescript + * // Get the bottom n scores from the 'scores' array field + * arrayMinimumN(field("scores"), field("count")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {Expression} representing the smallest `n` elements. + */ +export function arrayMinimumN( + arrayExpression: Expression, + n: Expression, +): FunctionExpression; +export function arrayMinimumN( + array: Expression | string, + n: Expression | number, +): FunctionExpression { + return fieldOrExpression(array).arrayMinimumN(valueToDefaultExpr(n)); +} + +/** + * @beta + * + * Creates an expression that returns a slice of an array. + * + * @example + * ```typescript + * // Get the first 3 elements of the 'tags' array field + * arraySlice("tags", 0, 3); + * ``` + * + * @param fieldName - The name of the field containing the array to slice. + * @param start - The index to start the slice. + * @param end - The index to end the slice (inclusive). + * @returns A new {Expression} representing the slice. + */ +export function arraySlice( + fieldName: string, + start: number | Expression, + end?: number | Expression, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns a slice of an array. + * + * @example + * ```typescript + * // Get the first 3 elements of the 'tags' array field + * arraySlice(field("tags"), 0, 3); + * ``` + * + * @param arrayExpression - The expression representing the array to slice. + * @param start - The index to start the slice. + * @param end - The index to end the slice (inclusive). + * @returns A new {Expression} representing the slice. + */ +export function arraySlice( + arrayExpression: Expression, + start: number | Expression, + end?: number | Expression, +): FunctionExpression; +export function arraySlice( + array: Expression | string, + start: number | Expression, + end?: number | Expression, +): FunctionExpression { + return fieldOrExpression(array).arraySlice( + valueToDefaultExpr(start), + end === undefined ? undefined : valueToDefaultExpr(end), + ); +} + +/** + * @beta + * + * Creates an expression that returns the first index of the search value in an array. + * Returns -1 if the value is not found. + * + * @example + * ```typescript + * // Get the index of "politics" in the 'tags' array field + * arrayIndexOf("tags", "politics"); + * ``` + * + * @param fieldName - The name of the field containing the array to search. + * @param search - The value to search for. + * @returns A new {Expression} representing the index. + */ +export function arrayIndexOf( + fieldName: string, + search: unknown | Expression, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the first index of the search value in an array. + * Returns -1 if the value is not found. + * + * @example + * ```typescript + * // Get the index of "politics" in the 'tags' array field + * arrayIndexOf(field("tags"), "politics"); + * ``` + * + * @param arrayExpression - The expression representing the array to search. + * @param search - The value to search for. + * @returns A new {Expression} representing the index. + */ +export function arrayIndexOf( + arrayExpression: Expression, + search: unknown | Expression, +): FunctionExpression; +export function arrayIndexOf( + array: Expression | string, + search: unknown | Expression, +): FunctionExpression { + return fieldOrExpression(array).arrayIndexOf(valueToDefaultExpr(search)); +} + +/** + * @beta + * + * Creates an expression that returns the last index of the search value in an array. + * Returns -1 if the value is not found. + * + * @example + * ```typescript + * // Get the last index of "politics" in the 'tags' array field + * arrayLastIndexOf("tags", "politics"); + * ``` + * + * @param fieldName - The name of the field containing the array to search. + * @param search - The value to search for. + * @returns A new {Expression} representing the index. + */ +export function arrayLastIndexOf( + fieldName: string, + search: unknown | Expression, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns the last index of the search value in an array. + * Returns -1 if the value is not found. + * + * @example + * ```typescript + * // Get the last index of "politics" in the 'tags' array field + * arrayLastIndexOf(field("tags"), "politics"); + * ``` + * + * @param arrayExpression - The expression representing the array to search. + * @param search - The value to search for. + * @returns A new {Expression} representing the index. + */ +export function arrayLastIndexOf( + arrayExpression: Expression, + search: unknown | Expression, +): FunctionExpression; +export function arrayLastIndexOf( + array: Expression | string, + search: unknown | Expression, +): FunctionExpression { + return fieldOrExpression(array).arrayLastIndexOf(valueToDefaultExpr(search)); +} + +/** + * @beta + * + * Creates an expression that returns all indices of the search value in an array. + * + * @example + * ```typescript + * // Get all indices of 5 in the 'scores' array field + * arrayIndexOfAll("scores", 5); + * ``` + * + * @param fieldName - The name of the field containing the array to search. + * @param search - The value to search for. + * @returns A new {Expression} representing the indices. + */ +export function arrayIndexOfAll( + fieldName: string, + search: unknown | Expression, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that returns all indices of the search value in an array. + * + * @example + * ```typescript + * // Get all indices of 5 in the 'scores' array field + * arrayIndexOfAll(field("scores"), 5); + * ``` + * + * @param arrayExpression - The expression representing the array to search. + * @param search - The value to search for. + * @returns A new {Expression} representing the indices. + */ +export function arrayIndexOfAll( + arrayExpression: Expression, + search: unknown | Expression, +): FunctionExpression; +export function arrayIndexOfAll( + array: Expression | string, + search: unknown | Expression, +): FunctionExpression { + return fieldOrExpression(array).arrayIndexOfAll(valueToDefaultExpr(search)); +} + +/** + * @beta + * + * Creates an expression that filters an array based on a predicate. + * + * @example + * ```typescript + * // Filter "scores" to include only values greater than 50 + * arrayFilter("scores", "score", field("score").greaterThan(50)); + * ``` + * + * @param fieldName - The name of the field containing the array to filter. + * @param variable - The variable name to bind to each element in the array. This variable name + * can be used in the `predicate` expression to refer to the current element. + * @param predicate - The predicate boolean expression to filter by. + * @returns A new {Expression} representing the filtered array. + */ +export function arrayFilter( + fieldName: string, + variable: string, + predicate: BooleanExpression, +): FunctionExpression; + +/** + * @beta + * + * Creates an expression that filters an array based on a predicate. + * + * @example + * ```typescript + * // Filter "scores" to include only values greater than 50 + * arrayFilter(field("scores"), "score", field("score").greaterThan(50)); + * ``` + * + * @param arrayExpression - The expression representing the array to filter. + * @param variable - The variable name to bind to each element in the array. This variable name + * can be used in the `predicate` expression to refer to the current element. + * @param predicate - The predicate boolean expression to filter by. + * @returns A new {Expression} representing the filtered array. + */ +export function arrayFilter( + arrayExpression: Expression, + variable: string, + predicate: BooleanExpression, +): FunctionExpression; +export function arrayFilter( + array: Expression | string, + variable: string, + predicate: BooleanExpression, +): FunctionExpression { + return fieldOrExpression(array).arrayFilter(variable, predicate); +} // TODO(new-expression): Add new top-level expression function definitions above this line /** diff --git a/dev/src/pipelines/index.ts b/dev/src/pipelines/index.ts index 79cd1a389..e7c52ab40 100644 --- a/dev/src/pipelines/index.ts +++ b/dev/src/pipelines/index.ts @@ -50,6 +50,19 @@ export { equalAny, map, array, + arrayFilter, + arrayFirst, + arrayLast, + arrayFirstN, + arrayLastN, + arrayIndexOf, + arrayIndexOfAll, + arrayLastIndexOf, + arrayMaximum, + arrayMinimum, + arrayMaximumN, + arrayMinimumN, + arraySlice, field, xor, AggregateFunction, diff --git a/dev/system-test/pipeline.ts b/dev/system-test/pipeline.ts index efc5ff470..265c2031a 100644 --- a/dev/system-test/pipeline.ts +++ b/dev/system-test/pipeline.ts @@ -141,7 +141,23 @@ import {getTestDb, getTestRoot} from './firestore'; import {Firestore as InternalFirestore} from '../src'; import {ServiceError} from 'google-gax'; -import {regexFind, regexFindAll} from '../src/pipelines/expression'; +import { + arrayFilter, + arrayFirst, + arrayFirstN, + arrayIndexOf, + arrayIndexOfAll, + arrayLast, + arrayLastIndexOf, + arrayLastN, + arrayMaximum, + arrayMaximumN, + arrayMinimum, + arrayMinimumN, + arraySlice, + regexFind, + regexFindAll, +} from '../src/pipelines/expression'; use(chaiAsPromised); @@ -3101,6 +3117,560 @@ describe.skipClassic('Pipeline class', () => { expectResults(snapshot, ...expectedResults); }); + it('supports arrayFirst', async () => { + let snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(arrayFirst('tags').as('firstTag')) + .execute(); + const expectedResults = [ + { + firstTag: 'adventure', + }, + { + firstTag: 'politics', + }, + { + firstTag: 'classic', + }, + ]; + expectResults(snapshot, ...expectedResults); + + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(field('tags').arrayFirst().as('firstTag')) + .execute(); + expectResults(snapshot, ...expectedResults); + }); + + it('supports arrayFirstN', async () => { + let snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(arrayFirstN('tags', 2).as('firstTwoTags')) + .execute(); + const expectedResults = [ + { + firstTwoTags: ['adventure', 'magic'], + }, + { + firstTwoTags: ['politics', 'desert'], + }, + { + firstTwoTags: ['classic', 'social commentary'], + }, + ]; + expectResults(snapshot, ...expectedResults); + + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(field('tags').arrayFirstN(2).as('firstTwoTags')) + .execute(); + expectResults(snapshot, ...expectedResults); + }); + + it('supports arrayLast', async () => { + let snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(arrayLast('tags').as('lastTag')) + .execute(); + const expectedResults = [ + { + lastTag: 'epic', + }, + { + lastTag: 'ecology', + }, + { + lastTag: 'love', + }, + ]; + expectResults(snapshot, ...expectedResults); + + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(field('tags').arrayLast().as('lastTag')) + .execute(); + expectResults(snapshot, ...expectedResults); + }); + + it('supports arrayLastN', async () => { + let snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(arrayLastN('tags', 2).as('lastTwoTags')) + .execute(); + const expectedResults = [ + { + lastTwoTags: ['magic', 'epic'], + }, + { + lastTwoTags: ['desert', 'ecology'], + }, + { + lastTwoTags: ['social commentary', 'love'], + }, + ]; + expectResults(snapshot, ...expectedResults); + + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(field('tags').arrayLastN(2).as('lastTwoTags')) + .execute(); + expectResults(snapshot, ...expectedResults); + }); + + it('supports arrayMaximum', async () => { + let snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(arrayMaximum('tags').as('maxTag')) + .execute(); + const expectedResults = [ + { + maxTag: 'magic', + }, + ]; + expectResults(snapshot, ...expectedResults); + + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('tags').arrayMaximum().as('maxTag')) + .execute(); + expectResults(snapshot, ...expectedResults); + }); + + it('supports arrayMaximumN', async () => { + let snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(arrayMaximumN('tags', 2).as('maxTwoTags')) + .execute(); + const expectedResults = [ + { + maxTwoTags: ['magic', 'epic'], + }, + ]; + expectResults(snapshot, ...expectedResults); + + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('tags').arrayMaximumN(2).as('maxTwoTags')) + .execute(); + expectResults(snapshot, ...expectedResults); + }); + + it('supports arrayMinimum', async () => { + let snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(arrayMinimum('tags').as('minTag')) + .execute(); + const expectedResults = [ + { + minTag: 'adventure', + }, + ]; + expectResults(snapshot, ...expectedResults); + + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('tags').arrayMinimum().as('minTag')) + .execute(); + expectResults(snapshot, ...expectedResults); + }); + + it('supports arrayMinimumN', async () => { + let snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(arrayMinimumN('tags', 2).as('minTwoTags')) + .execute(); + const expectedResults = [ + { + minTwoTags: ['adventure', 'epic'], + }, + ]; + expectResults(snapshot, ...expectedResults); + + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('tags').arrayMinimumN(2).as('minTwoTags')) + .execute(); + expectResults(snapshot, ...expectedResults); + }); + + it('supports arraySlice', async () => { + let snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + arraySlice('tags', 0, 1).as('slice1'), // inclusive start and end + arraySlice('tags', 1, 100).as('slice2'), // overflow end + arraySlice('tags', 1).as('slice3'), // slice to end + field('tags').arraySlice(1, 2).as('slice4'), // class method + arraySlice('empty', 0, 1).as('sliceEmpty'), // null array + ) + .execute(); + const expectedResults = [ + { + slice1: ['adventure', 'magic'], + slice2: ['magic', 'epic'], + slice3: ['magic', 'epic'], + slice4: ['magic', 'epic'], + sliceEmpty: null, + }, + ]; + expectResults(snapshot, ...expectedResults); + + // Test with expressions + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + arraySlice('tags', field('tags').arrayLength().subtract(2)).as( + 'slice', + ), + ) + .execute(); + // length of tags is 3. slice(1) -> ['magic', 'epic'] + expectResults(snapshot, { + slice: ['magic', 'epic'], + }); + }); + + it('supports arrayIndexOf', async () => { + const snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + arrayIndexOf('tags', 'adventure').as('indexFirst'), + arrayIndexOf(field('tags'), 'magic').as('indexSecond'), + field('tags').arrayIndexOf('adventure').as('indexFirst2'), + arrayIndexOf('tags', 'nonexistent').as('indexNone'), + arrayIndexOf('empty', 'anything').as('indexEmpty'), + ) + .execute(); + const expectedResults = [ + { + indexFirst: 0, + indexSecond: 1, + indexFirst2: 0, + indexNone: -1, + indexEmpty: null, + }, + ]; + expectResults(snapshot, ...expectedResults); + + // Test with duplicate values + const snapshotDuplicates = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + arr: [1, 2, 3, 2, 1], + }), + ) + .select( + arrayIndexOf('arr', 2).as('firstIndex'), + arrayLastIndexOf('arr', 2).as('lastIndex'), + ) + .execute(); + expectResults(snapshotDuplicates, { + firstIndex: 1, + lastIndex: 3, + }); + }); + + it('supports arrayLastIndexOf', async () => { + const snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + arrayLastIndexOf('tags', 'adventure').as('lastIndexFirst'), + arrayLastIndexOf(field('tags'), 'epic').as('lastIndexLast'), + field('tags').arrayLastIndexOf('adventure').as('lastIndexFirst2'), + arrayLastIndexOf('tags', 'nonexistent').as('lastIndexNone'), + arrayLastIndexOf('empty', 'anything').as('lastIndexEmpty'), + ) + .execute(); + const expectedResults = [ + { + lastIndexFirst: 0, + lastIndexLast: 2, + lastIndexFirst2: 0, + lastIndexNone: -1, + lastIndexEmpty: null, + }, + ]; + expectResults(snapshot, ...expectedResults); + + // Test with duplicate values + const snapshotDuplicates = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + arr: [1, 2, 3, 2, 1], + }), + ) + .select( + arrayIndexOf('arr', 2).as('firstIndex'), + arrayLastIndexOf('arr', 2).as('lastIndex'), + ) + .execute(); + expectResults(snapshotDuplicates, { + firstIndex: 1, + lastIndex: 3, + }); + }); + + it('supports arrayIndexOfAll', async () => { + const snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + arrayIndexOfAll('tags', 'adventure').as('indicesFirst'), // [0] + arrayIndexOfAll(field('tags'), 'epic').as('indicesLast'), // [2] + field('tags').arrayIndexOfAll('nonexistent').as('indicesNone'), // [] + arrayIndexOfAll('empty', 'anything').as('indicesEmpty'), // [] + ) + .execute(); + const expectedResults = [ + { + indicesFirst: [0], + indicesLast: [2], + indicesNone: [], + indicesEmpty: null, + }, + ]; + expectResults(snapshot, ...expectedResults); + + // Test with duplicate values + const snapshotDuplicates = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + arr: [1, 2, 3, 2, 1], + }), + ) + .select( + arrayIndexOfAll('arr', 1).as('indices1'), + arrayIndexOfAll('arr', 2).as('indices2'), + ) + .execute(); + expectResults(snapshotDuplicates, { + indices1: [0, 4], + indices2: [1, 3], + }); + }); + + describe('arrayFilter', () => { + it('supports arrayFilter simple', async () => { + const snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + arr: [1, 2, 3, 4, 5], + arr2: [10, 20], + empty: [], + nullArr: null, + notArr: [1, 2, 3, 4, 5], + }), + ) + .select( + field('arr') + .arrayFilter('element', field('element').greaterThan(3)) + .as('result1'), + arrayFilter('arr2', 'element', field('element').greaterThan(3)).as( + 'result2', + ), + arrayFilter('empty', 'element', field('element').greaterThan(3)).as( + 'result3', + ), + arrayFilter( + 'nullArr', + 'element', + field('element').greaterThan(3), + ).as('result4'), + ) + .execute(); + expectResults(snapshot, { + result1: [4, 5], + result2: [10, 20], + result3: [], + result4: null, + }); + }); + + it('supports arrayFilter on map property', async () => { + const snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + arr: [{a: {b: 1}}, {a: {b: 2}}, {a: {b: 3}}], + }), + ) + .select( + arrayFilter('arr', 'element', field('element.a.b').equal(2)).as( + 'result', + ), + ) + .execute(); + expectResults(snapshot, { + result: [{a: {b: 2}}], + }); + }); + + it('supports arrayFilter nested child references parent', async () => { + const snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + arr: [ + {outerVal: 2, innerArr: [1, 2, 3]}, + {outerVal: 5, innerArr: [4, 5, 6]}, + {outerVal: 9, innerArr: [7, 8]}, + ], + }), + ) + .select( + arrayFilter( + field('arr'), + 'parent', + field('parent.innerArr') + .arrayFilter( + 'child', + field('child').equal(field('parent.outerVal')), + ) + .length() + .greaterThan(0), + ).as('result'), + ) + .execute(); + expectResults(snapshot, { + result: [ + {outerVal: 2, innerArr: [1, 2, 3]}, + {outerVal: 5, innerArr: [4, 5, 6]}, + ], + }); + }); + + it('supports arrayFilter nested child references other fields', async () => { + const snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + otherField: 2, + arr: [{nested: [1, 2, 3]}, {nested: [4, 5, 6]}], + }), + ) + .select( + field('__name__'), + arrayFilter( + field('arr'), + 'outer', + arrayContains( + arrayFilter( + field('outer.nested'), + 'inner', + field('otherField').equal(constant(2)), + ), + constant(1), + ), + ).as('result'), + ) + .execute(); + expectResults(snapshot, { + result: [{nested: [1, 2, 3]}], + }); + }); + + it('supports arrayFilter edge case missing property in map', async () => { + const snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + arr: [{a: 1}, {b: 2}, {a: 3}], + }), + ) + .select( + arrayFilter('arr', 'element', field('element.a').greaterThan(1)).as( + 'result', + ), + ) + .execute(); + expectResults(snapshot, { + result: [{a: 3}], + }); + }); + }); + it('supports map', async () => { const snapshot = await firestore .pipeline() From d41676400324de510793775975b91d4133c68bab Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:01:45 -0500 Subject: [PATCH 02/12] Update firestore.d.ts --- types/firestore.d.ts | 994 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 994 insertions(+) diff --git a/types/firestore.d.ts b/types/firestore.d.ts index e53d75f7c..803414ee4 100644 --- a/types/firestore.d.ts +++ b/types/firestore.d.ts @@ -3631,6 +3631,325 @@ declare namespace FirebaseFirestore { */ arrayLength(): FunctionExpression; + /** + * @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(): FunctionExpression; + + /** + * @beta + * Returns the first `n` elements of the array. + * + * @example + * ```typescript + * // Get the first 3 elements of the 'myArray' field. + * field("myArray").arrayFirstN(3); + * ``` + * + * @param n The number of elements to return. + * @returns A new `Expression` representing the first `n` elements. + */ + arrayFirstN(n: number): FunctionExpression; + + /** + * @beta + * Returns the first `n` elements of the array. + * + * @example + * ```typescript + * // Get the first n elements of the 'myArray' field. + * field("myArray").arrayFirstN(field("count")); + * ``` + * + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the first `n` elements. + */ + arrayFirstN(n: Expression): FunctionExpression; + + /** + * @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(): FunctionExpression; + + /** + * @beta + * Returns the last `n` elements of the array. + * + * @example + * ```typescript + * // Get the last 3 elements of the 'myArray' field. + * field("myArray").arrayLastN(3); + * ``` + * + * @param n The number of elements to return. + * @returns A new `Expression` representing the last `n` elements. + */ + arrayLastN(n: number): FunctionExpression; + + /** + * @beta + * Returns the last `n` elements of the array. + * + * @example + * ```typescript + * // Get the last n elements of the 'myArray' field. + * field("myArray").arrayLastN(field("count")); + * ``` + * + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the last `n` elements. + */ + arrayLastN(n: Expression): FunctionExpression; + + /** + * @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(): FunctionExpression; + + /** + * @beta + * Returns the largest `n` elements of the array. + * + * @example + * ```typescript + * // Get the largest 3 elements of the 'myArray' field. + * field("myArray").arrayMaximumN(3); + * ``` + * + * @param n The number of elements to return. + * @returns A new `Expression` representing the largest `n` elements. + */ + arrayMaximumN(n: number): FunctionExpression; + + /** + * @beta + * Returns the largest `n` elements of the array. + * + * @example + * ```typescript + * // Get the largest n elements of the 'myArray' field. + * field("myArray").arrayMaximumN(field("count")); + * ``` + * + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the largest `n` elements. + */ + arrayMaximumN(n: Expression): FunctionExpression; + + /** + * @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(): FunctionExpression; + + /** + * @beta + * Returns the smallest `n` elements of the array. + * + * @example + * ```typescript + * // Get the smallest 3 elements of the 'myArray' field. + * field("myArray").arrayMinimumN(3); + * ``` + * + * @param n The number of elements to return. + * @returns A new `Expression` representing the smallest `n` elements. + */ + arrayMinimumN(n: number): FunctionExpression; + + /** + * @beta + * Returns the smallest `n` elements of the array. + * + * @example + * ```typescript + * // Get the smallest n elements of the 'myArray' field. + * field("myArray").arrayMinimumN(field("count")); + * ``` + * + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the smallest `n` elements. + */ + arrayMinimumN(n: Expression): FunctionExpression; + + /** + * @beta + * Returns a slice of the array. + * + * @example + * ```typescript + * // Get a slice of the 'myArray' field from index 1 to 3 (inclusive). + * field("myArray").arraySlice(1, 3); + * ``` + * + * @param start The index to start the slice. + * @param end The index to end the slice (inclusive). + * @returns A new `Expression` representing the slice. + */ + arraySlice(start: number, end?: number): FunctionExpression; + + /** + * @beta + * Returns a slice of the array. + * + * @example + * ```typescript + * // Get a slice of the 'myArray' field from index value in 'start' field to + * // index value in 'end' field (inclusive). + * field("myArray").arraySlice(field("start"), field("end")); + * ``` + * + * @param start An expression evaluating to the index to start the slice. + * @param end An expression evaluating to the index to end the slice (inclusive). + * @returns A new `Expression` representing the slice. + */ + arraySlice(start: Expression, end?: Expression): FunctionExpression; + + /** + * @beta + * Returns the first index of the search value in the array, or -1 if not found. + * + * @example + * ```typescript + * // Get the first index of the value 3 in the 'myArray' field. + * field("myArray").arrayIndexOf(3); + * ``` + * + * @param search The value to search for. + * @returns A new `Expression` representing the index. + */ + arrayIndexOf(search: unknown): FunctionExpression; + + /** + * @beta + * Returns the first index of the search value in the array, or -1 if not found. + * + * @example + * ```typescript + * // Get the first index of the value in 'searchVal' field in the 'myArray' field. + * field("myArray").arrayIndexOf(field("searchVal")); + * ``` + * + * @param search An expression evaluating to the value to search for. + * @returns A new `Expression` representing the index. + */ + arrayIndexOf(search: Expression): FunctionExpression; + + /** + * @beta + * Returns the last index of the search value in the array, or -1 if not found. + * + * @example + * ```typescript + * // Get the last index of the value 3 in the 'myArray' field. + * field("myArray").arrayLastIndexOf(3); + * ``` + * + * @param search The value to search for. + * @returns A new `Expression` representing the index. + */ + arrayLastIndexOf(search: unknown): FunctionExpression; + + /** + * @beta + * Returns the last index of the search value in the array, or -1 if not found. + * + * @example + * ```typescript + * // Get the last index of the value in 'searchVal' field in the 'myArray' field. + * field("myArray").arrayLastIndexOf(field("searchVal")); + * ``` + * + * @param search An expression evaluating to the value to search for. + * @returns A new `Expression` representing the index. + */ + arrayLastIndexOf(search: Expression): FunctionExpression; + + /** + * @beta + * Returns all indices of the search value in the array. + * + * @example + * ```typescript + * // Get all indices of the value 3 in the 'myArray' field. + * field("myArray").arrayIndexOfAll(3); + * ``` + * + * @param search The value to search for. + * @returns A new `Expression` representing the indices. + */ + arrayIndexOfAll(search: unknown): FunctionExpression; + + /** + * @beta + * Returns all indices of the search value in the array. + * + * @example + * ```typescript + * // Get all indices of the value in 'searchVal' field in the 'myArray' field. + * field("myArray").arrayIndexOfAll(field("searchVal")); + * ``` + * + * @param search An expression evaluating to the value to search for. + * @returns A new `Expression` representing the indices. + */ + arrayIndexOfAll(search: Expression): FunctionExpression; + + /** + * @beta + * Returns a filtered array containing only elements that match the predicate. + * + * @example + * ```typescript + * // Get a filtered array of the 'scores' field containing only elements greater than 50. + * field("scores").arrayFilter("score", field("score").greaterThan(50)); + * ``` + * + * @param variable The variable name to bind to each element in the array. This variable name + * can be used in the `predicate` expression to refer to the current element. + * @param predicate The predicate boolean expression to filter by. + * @returns A new `Expression` representing the filtered array. + */ + arrayFilter( + variable: string, + predicate: BooleanExpression, + ): FunctionExpression; + /** * @beta * Creates an expression that checks if this expression is equal to any of the provided values or @@ -7098,6 +7417,681 @@ declare namespace FirebaseFirestore { * @returns A new {@code Expression} representing the length of the array. */ export function arrayLength(array: Expression): FunctionExpression; + + /** + * @beta + * + * Creates an expression that filters an array based on a predicate. + * + * @example + * ```typescript + * // Filter "scores" to include only values greater than 50 + * arrayFilter("scores", "score", field("score").greaterThan(50)); + * ``` + * + * @param fieldName - The name of the field containing the array to filter. + * @param variable - The variable name to bind to each element in the array. This variable name + * can be used in the `predicate` expression to refer to the current element. + * @param predicate - The predicate boolean expression to filter by. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the filtered array. + */ + export function arrayFilter( + fieldName: string, + variable: string, + predicate: BooleanExpression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that filters an array based on a predicate. + * + * @example + * ```typescript + * // Filter "scores" to include only values greater than 50 + * arrayFilter(field("scores"), "score", field("score").greaterThan(50)); + * ``` + * + * @param arrayExpression - The expression representing the array to filter. + * @param variable - The variable name to bind to each element in the array. This variable name + * can be used in the `predicate` expression to refer to the current element. + * @param predicate - The predicate boolean expression to filter by. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the filtered array. + */ + export function arrayFilter( + arrayExpression: Expression, + variable: string, + predicate: BooleanExpression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the first element of an array. + * + * @example + * ```typescript + * // Get the first tag from the 'tags' array field + * arrayFirst("tags"); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the first element. + */ + export function arrayFirst(fieldName: string): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the first element of an array. + * + * @example + * ```typescript + * // Get the first tag from the 'tags' array field + * arrayFirst(field("tags")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the first element. + */ + export function arrayFirst(arrayExpression: Expression): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the first `n` elements of an array. + * + * @example + * ```typescript + * // Get the first 3 tags from the 'tags' array field + * arrayFirstN("tags", 3); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - The number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the first `n` elements. + */ + export function arrayFirstN( + fieldName: string, + n: number, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the first `n` elements of an array. + * + * @example + * ```typescript + * // Get the first n tags from the 'tags' array field + * arrayFirstN("tags", field("count")); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the first `n` elements. + */ + export function arrayFirstN( + fieldName: string, + n: Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the first `n` elements of an array. + * + * @example + * ```typescript + * // Get the first 3 elements from an array expression + * arrayFirstN(field("tags"), 3); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - The number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the first `n` elements. + */ + export function arrayFirstN( + arrayExpression: Expression, + n: number, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the first `n` elements of an array. + * + * @example + * ```typescript + * // Get the first n elements from an array expression + * arrayFirstN(field("tags"), field("count")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the first `n` elements. + */ + export function arrayFirstN( + arrayExpression: Expression, + n: Expression, + ): FunctionExpression; + /** + * @beta + * Creates an expression that indexes into an array from the beginning or end + * and return the element. If the offset exceeds the array length, an error is + * returned. A negative offset, starts from the end. + * + * @example + * ```typescript + * // Return the value in the tags field array at index 1. + * arrayGet(field('tags'), 1); + * ``` + * + * @param arrayExpression - An `Expression` evaluating to an array. + * @param offset - The index of the element to return. + * @returns A new `Expression` representing the 'arrayGet' operation. + */ + export function arrayGet( + arrayExpression: Expression, + offset: number, + ): FunctionExpression; + /** + * @beta + * Creates an expression that indexes into an array from the beginning or end + * and return the element. If the offset exceeds the array length, an error is + * returned. A negative offset, starts from the end. + * + * @example + * ```typescript + * // Return the value in the tags field array at index specified by field + * // 'favoriteTag'. + * arrayGet(field('tags'), field('favoriteTag')); + * ``` + * + * @param arrayExpression - An `Expression` evaluating to an array. + * @param offsetExpr - An `Expression` evaluating to the index of the element to return. + * @returns A new `Expression` representing the 'arrayGet' operation. + */ + export function arrayGet( + arrayExpression: Expression, + offsetExpr: Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the first index of the search value in an array. + * Returns -1 if the value is not found. + * + * @example + * ```typescript + * // Get the index of "politics" in the 'tags' array field + * arrayIndexOf("tags", "politics"); + * ``` + * + * @param fieldName - The name of the field containing the array to search. + * @param search - The value to search for. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the index. + */ + export function arrayIndexOf( + fieldName: string, + search: unknown | Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the first index of the search value in an array. + * Returns -1 if the value is not found. + * + * @example + * ```typescript + * // Get the index of "politics" in the 'tags' array field + * arrayIndexOf(field("tags"), "politics"); + * ``` + * + * @param arrayExpression - The expression representing the array to search. + * @param search - The value to search for. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the index. + */ + export function arrayIndexOf( + arrayExpression: Expression, + search: unknown | Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns all indices of the search value in an array. + * + * @example + * ```typescript + * // Get all indices of 5 in the 'scores' array field + * arrayIndexOfAll("scores", 5); + * ``` + * + * @param fieldName - The name of the field containing the array to search. + * @param search - The value to search for. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the indices. + */ + export function arrayIndexOfAll( + fieldName: string, + search: unknown | Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns all indices of the search value in an array. + * + * @example + * ```typescript + * // Get all indices of 5 in the 'scores' array field + * arrayIndexOfAll(field("scores"), 5); + * ``` + * + * @param arrayExpression - The expression representing the array to search. + * @param search - The value to search for. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the indices. + */ + export function arrayIndexOfAll( + arrayExpression: Expression, + search: unknown | Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the last element of an array. + * + * @example + * ```typescript + * // Get the last tag from the 'tags' array field + * arrayLast("tags"); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the last element. + */ + export function arrayLast(fieldName: string): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the last element of an array. + * + * @example + * ```typescript + * // Get the last tag from the 'tags' array field + * arrayLast(field("tags")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the last element. + */ + export function arrayLast(arrayExpression: Expression): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the last index of the search value in an array. + * Returns -1 if the value is not found. + * + * @example + * ```typescript + * // Get the last index of "politics" in the 'tags' array field + * arrayLastIndexOf("tags", "politics"); + * ``` + * + * @param fieldName - The name of the field containing the array to search. + * @param search - The value to search for. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the index. + */ + export function arrayLastIndexOf( + fieldName: string, + search: unknown | Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the last index of the search value in an array. + * Returns -1 if the value is not found. + * + * @example + * ```typescript + * // Get the last index of "politics" in the 'tags' array field + * arrayLastIndexOf(field("tags"), "politics"); + * ``` + * + * @param arrayExpression - The expression representing the array to search. + * @param search - The value to search for. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the index. + */ + export function arrayLastIndexOf( + arrayExpression: Expression, + search: unknown | Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the last `n` elements of an array. + * + * @example + * ```typescript + * // Get the last 3 tags from the 'tags' array field + * arrayLastN("tags", 3); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - The number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the last `n` elements. + */ + export function arrayLastN( + fieldName: string, + n: number, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the last `n` elements of an array. + * + * @example + * ```typescript + * // Get the last n tags from the 'tags' array field + * arrayLastN("tags", field("count")); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the last `n` elements. + */ + export function arrayLastN( + fieldName: string, + n: Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the last `n` elements of an array. + * + * @example + * ```typescript + * // Get the last 3 elements from an array expression + * arrayLastN(field("tags"), 3); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - The number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the last `n` elements. + */ + export function arrayLastN( + arrayExpression: Expression, + n: number, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the last `n` elements of an array. + * + * @example + * ```typescript + * // Get the last n elements from an array expression + * arrayLastN(field("tags"), field("count")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the last `n` elements. + */ + export function arrayLastN( + arrayExpression: Expression, + n: Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the maximum value in an array. + * + * @example + * ```typescript + * // Get the maximum value from the 'scores' array field + * arrayMaximum("scores"); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the maximum value. + */ + export function arrayMaximum(fieldName: string): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the maximum value in an array. + * + * @example + * ```typescript + * // Get the maximum value from the 'scores' array field + * arrayMaximum(field("scores")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the maximum value. + */ + export function arrayMaximum( + arrayExpression: Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the largest `n` elements of an array. + * + * @example + * ```typescript + * // Get the top 3 scores from the 'scores' array field + * arrayMaximumN("scores", 3); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - The number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the largest `n` elements. + */ + export function arrayMaximumN( + fieldName: string, + n: number, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the largest `n` elements of an array. + * + * @example + * ```typescript + * // Get the top n scores from the 'scores' array field + * arrayMaximumN("scores", field("count")); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the largest `n` elements. + */ + export function arrayMaximumN( + fieldName: string, + n: Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the largest `n` elements of an array. + * + * @example + * ```typescript + * // Get the top 3 elements from an array expression + * arrayMaximumN(field("scores"), 3); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - The number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the largest `n` elements. + */ + export function arrayMaximumN( + arrayExpression: Expression, + n: number, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the largest `n` elements of an array. + * + * @example + * ```typescript + * // Get the top n elements from an array expression + * arrayMaximumN(field("scores"), field("count")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the largest `n` elements. + */ + export function arrayMaximumN( + arrayExpression: Expression, + n: Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the minimum value in an array. + * + * @example + * ```typescript + * // Get the minimum value from the 'scores' array field + * arrayMinimum("scores"); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the minimum value. + */ + export function arrayMinimum(fieldName: string): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the minimum value in an array. + * + * @example + * ```typescript + * // Get the minimum value from the 'scores' array field + * arrayMinimum(field("scores")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the minimum value. + */ + export function arrayMinimum( + arrayExpression: Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the smallest `n` elements of an array. + * + * @example + * ```typescript + * // Get the bottom 3 scores from the 'scores' array field + * arrayMinimumN("scores", 3); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - The number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the smallest `n` elements. + */ + export function arrayMinimumN( + fieldName: string, + n: number, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the smallest `n` elements of an array. + * + * @example + * ```typescript + * // Get the bottom n scores from the 'scores' array field + * arrayMinimumN(field("scores"), field("count")); + * ``` + * + * @param fieldName - The name of the field containing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the smallest `n` elements. + */ + export function arrayMinimumN( + fieldName: string, + n: Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the smallest `n` elements of an array. + * + * @example + * ```typescript + * // Get the bottom 3 scores from the 'scores' array field + * arrayMinimumN(field("scores"), 3); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - The number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the smallest `n` elements. + */ + export function arrayMinimumN( + arrayExpression: Expression, + n: number, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns the smallest `n` elements of an array. + * + * @example + * ```typescript + * // Get the bottom n scores from the 'scores' array field + * arrayMinimumN(field("scores"), field("count")); + * ``` + * + * @param arrayExpression - The expression representing the array. + * @param n - An expression evaluating to the number of elements to return. + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the smallest `n` elements. + */ + export function arrayMinimumN( + arrayExpression: Expression, + n: Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns a slice of an array. + * + * @example + * ```typescript + * // Get the first 3 elements of the 'tags' array field + * arraySlice("tags", 0, 3); + * ``` + * + * @param fieldName - The name of the field containing the array to slice. + * @param start - The index to start the slice. + * @param end - The index to end the slice (inclusive). + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the slice. + */ + export function arraySlice( + fieldName: string, + start: number | Expression, + end?: number | Expression, + ): FunctionExpression; + /** + * @beta + * + * Creates an expression that returns a slice of an array. + * + * @example + * ```typescript + * // Get the first 3 elements of the 'tags' array field + * arraySlice(field("tags"), 0, 3); + * ``` + * + * @param arrayExpression - The expression representing the array to slice. + * @param start - The index to start the slice. + * @param end - The index to end the slice (inclusive). + * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the slice. + */ + export function arraySlice( + arrayExpression: Expression, + start: number | Expression, + end?: number | Expression, + ): FunctionExpression; + /** * @beta * Creates an expression that checks if an expression, when evaluated, is equal to any of the provided values or From ef886f6345184cd2be02f1acd9059ac331648e82 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Thu, 19 Feb 2026 10:11:54 -0500 Subject: [PATCH 03/12] Update firestore.d.ts --- types/firestore.d.ts | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/types/firestore.d.ts b/types/firestore.d.ts index 803414ee4..d19f2d3bc 100644 --- a/types/firestore.d.ts +++ b/types/firestore.d.ts @@ -7584,47 +7584,6 @@ declare namespace FirebaseFirestore { * @param offset - The index of the element to return. * @returns A new `Expression` representing the 'arrayGet' operation. */ - export function arrayGet( - arrayExpression: Expression, - offset: number, - ): FunctionExpression; - /** - * @beta - * Creates an expression that indexes into an array from the beginning or end - * and return the element. If the offset exceeds the array length, an error is - * returned. A negative offset, starts from the end. - * - * @example - * ```typescript - * // Return the value in the tags field array at index specified by field - * // 'favoriteTag'. - * arrayGet(field('tags'), field('favoriteTag')); - * ``` - * - * @param arrayExpression - An `Expression` evaluating to an array. - * @param offsetExpr - An `Expression` evaluating to the index of the element to return. - * @returns A new `Expression` representing the 'arrayGet' operation. - */ - export function arrayGet( - arrayExpression: Expression, - offsetExpr: Expression, - ): FunctionExpression; - /** - * @beta - * - * Creates an expression that returns the first index of the search value in an array. - * Returns -1 if the value is not found. - * - * @example - * ```typescript - * // Get the index of "politics" in the 'tags' array field - * arrayIndexOf("tags", "politics"); - * ``` - * - * @param fieldName - The name of the field containing the array to search. - * @param search - The value to search for. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the index. - */ export function arrayIndexOf( fieldName: string, search: unknown | Expression, From 1f633a2c16a6f56dcda4ad259d2d1891f80b0ef0 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Thu, 19 Feb 2026 12:17:25 -0500 Subject: [PATCH 04/12] fix format --- api-report/firestore.api.md | 102 ---------------- dev/src/pipelines/expression.ts | 202 ++++++++++++++++---------------- dev/system-test/pipeline.ts | 102 ++++++++++++++++ types/firestore.d.ts | 194 +++++++++++++++--------------- 4 files changed, 300 insertions(+), 300 deletions(-) diff --git a/api-report/firestore.api.md b/api-report/firestore.api.md index 980148e44..96a85997c 100644 --- a/api-report/firestore.api.md +++ b/api-report/firestore.api.md @@ -211,51 +211,27 @@ function arrayContainsAny(array: Expression, values: Expression): BooleanExpress // @beta function arrayContainsAny(fieldName: string, values: Expression): BooleanExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayFilter(fieldName: string, variable: string, predicate: BooleanExpression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayFilter(arrayExpression: Expression, variable: string, predicate: BooleanExpression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayFirst(fieldName: string): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayFirst(arrayExpression: Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayFirstN(fieldName: string, n: number): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayFirstN(fieldName: string, n: Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayFirstN(arrayExpression: Expression, n: number): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayFirstN(arrayExpression: Expression, n: Expression): FunctionExpression; @@ -271,75 +247,39 @@ function arrayGet(arrayExpression: Expression, index: number): FunctionExpressio // @beta function arrayGet(arrayExpression: Expression, indexExpr: Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayIndexOf(fieldName: string, search: unknown | Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayIndexOf(arrayExpression: Expression, search: unknown | Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayIndexOfAll(fieldName: string, search: unknown | Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayIndexOfAll(arrayExpression: Expression, search: unknown | Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayLast(fieldName: string): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayLast(arrayExpression: Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayLastIndexOf(fieldName: string, search: unknown | Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayLastIndexOf(arrayExpression: Expression, search: unknown | Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayLastN(fieldName: string, n: number): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayLastN(fieldName: string, n: Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayLastN(arrayExpression: Expression, n: number): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayLastN(arrayExpression: Expression, n: Expression): FunctionExpression; @@ -349,75 +289,39 @@ function arrayLength(fieldName: string): FunctionExpression; // @beta function arrayLength(array: Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayMaximum(fieldName: string): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayMaximum(arrayExpression: Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayMaximumN(fieldName: string, n: number): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayMaximumN(fieldName: string, n: Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayMaximumN(arrayExpression: Expression, n: number): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayMaximumN(arrayExpression: Expression, n: Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayMinimum(fieldName: string): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayMinimum(arrayExpression: Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayMinimumN(fieldName: string, n: number): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayMinimumN(fieldName: string, n: Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayMinimumN(arrayExpression: Expression, n: number): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arrayMinimumN(arrayExpression: Expression, n: Expression): FunctionExpression; @@ -427,15 +331,9 @@ function arrayReverse(fieldName: string): FunctionExpression; // @beta function arrayReverse(arrayExpression: Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arraySlice(fieldName: string, start: number | Expression, end?: number | Expression): FunctionExpression; -// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag -// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" -// // @beta function arraySlice(arrayExpression: Expression, start: number | Expression, end?: number | Expression): FunctionExpression; diff --git a/dev/src/pipelines/expression.ts b/dev/src/pipelines/expression.ts index 5a0cc7191..abd01e0f3 100644 --- a/dev/src/pipelines/expression.ts +++ b/dev/src/pipelines/expression.ts @@ -1006,8 +1006,8 @@ export abstract class Expression * field("scores").arrayFilter("score", field("score").greaterThan(50)); * ``` * - * @param variable The variable name to bind to each element in the array. This variable name - * can be used in the `predicate` expression to refer to the current element. + * @param variable The variable name to bind to each element in the array. This variable + * name can be used in the `predicate` expression to refer to the current element. * @param predicate The predicate boolean expression to filter by. * @returns A new `Expression` representing the filtered array. */ @@ -8413,8 +8413,8 @@ export function type( * arrayFirst("tags"); * ``` * - * @param fieldName - The name of the field containing the array. - * @returns A new {Expression} representing the first element. + * @param fieldName The name of the field containing the array. + * @returns A new `Expression` representing the first element. */ export function arrayFirst(fieldName: string): FunctionExpression; @@ -8429,8 +8429,8 @@ export function arrayFirst(fieldName: string): FunctionExpression; * arrayFirst(field("tags")); * ``` * - * @param arrayExpression - The expression representing the array. - * @returns A new {Expression} representing the first element. + * @param arrayExpression The expression representing the array. + * @returns A new `Expression` representing the first element. */ export function arrayFirst(arrayExpression: Expression): FunctionExpression; export function arrayFirst(array: Expression | string): FunctionExpression { @@ -8448,9 +8448,9 @@ export function arrayFirst(array: Expression | string): FunctionExpression { * arrayFirstN("tags", 3); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - The number of elements to return. - * @returns A new {Expression} representing the first `n` elements. + * @param fieldName The name of the field containing the array. + * @param n The number of elements to return. + * @returns A new `Expression` representing the first `n` elements. */ export function arrayFirstN(fieldName: string, n: number): FunctionExpression; @@ -8465,9 +8465,9 @@ export function arrayFirstN(fieldName: string, n: number): FunctionExpression; * arrayFirstN("tags", field("count")); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {Expression} representing the first `n` elements. + * @param fieldName The name of the field containing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the first `n` elements. */ export function arrayFirstN( fieldName: string, @@ -8485,9 +8485,9 @@ export function arrayFirstN( * arrayFirstN(field("tags"), 3); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - The number of elements to return. - * @returns A new {Expression} representing the first `n` elements. + * @param arrayExpression The expression representing the array. + * @param n The number of elements to return. + * @returns A new `Expression` representing the first `n` elements. */ export function arrayFirstN( arrayExpression: Expression, @@ -8505,9 +8505,9 @@ export function arrayFirstN( * arrayFirstN(field("tags"), field("count")); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {Expression} representing the first `n` elements. + * @param arrayExpression The expression representing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the first `n` elements. */ export function arrayFirstN( arrayExpression: Expression, @@ -8531,8 +8531,8 @@ export function arrayFirstN( * arrayLast("tags"); * ``` * - * @param fieldName - The name of the field containing the array. - * @returns A new {Expression} representing the last element. + * @param fieldName The name of the field containing the array. + * @returns A new `Expression` representing the last element. */ export function arrayLast(fieldName: string): FunctionExpression; @@ -8547,8 +8547,8 @@ export function arrayLast(fieldName: string): FunctionExpression; * arrayLast(field("tags")); * ``` * - * @param arrayExpression - The expression representing the array. - * @returns A new {Expression} representing the last element. + * @param arrayExpression The expression representing the array. + * @returns A new `Expression` representing the last element. */ export function arrayLast(arrayExpression: Expression): FunctionExpression; export function arrayLast(array: Expression | string): FunctionExpression { @@ -8566,9 +8566,9 @@ export function arrayLast(array: Expression | string): FunctionExpression { * arrayLastN("tags", 3); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - The number of elements to return. - * @returns A new {Expression} representing the last `n` elements. + * @param fieldName The name of the field containing the array. + * @param n The number of elements to return. + * @returns A new `Expression` representing the last `n` elements. */ export function arrayLastN(fieldName: string, n: number): FunctionExpression; @@ -8583,9 +8583,9 @@ export function arrayLastN(fieldName: string, n: number): FunctionExpression; * arrayLastN("tags", field("count")); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {Expression} representing the last `n` elements. + * @param fieldName The name of the field containing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the last `n` elements. */ export function arrayLastN( fieldName: string, @@ -8603,9 +8603,9 @@ export function arrayLastN( * arrayLastN(field("tags"), 3); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - The number of elements to return. - * @returns A new {Expression} representing the last `n` elements. + * @param arrayExpression The expression representing the array. + * @param n The number of elements to return. + * @returns A new `Expression` representing the last `n` elements. */ export function arrayLastN( arrayExpression: Expression, @@ -8623,9 +8623,9 @@ export function arrayLastN( * arrayLastN(field("tags"), field("count")); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {Expression} representing the last `n` elements. + * @param arrayExpression The expression representing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the last `n` elements. */ export function arrayLastN( arrayExpression: Expression, @@ -8649,8 +8649,8 @@ export function arrayLastN( * arrayMaximum("scores"); * ``` * - * @param fieldName - The name of the field containing the array. - * @returns A new {Expression} representing the maximum value. + * @param fieldName The name of the field containing the array. + * @returns A new `Expression` representing the maximum value. */ export function arrayMaximum(fieldName: string): FunctionExpression; @@ -8665,8 +8665,8 @@ export function arrayMaximum(fieldName: string): FunctionExpression; * arrayMaximum(field("scores")); * ``` * - * @param arrayExpression - The expression representing the array. - * @returns A new {Expression} representing the maximum value. + * @param arrayExpression The expression representing the array. + * @returns A new `Expression` representing the maximum value. */ export function arrayMaximum(arrayExpression: Expression): FunctionExpression; export function arrayMaximum(array: Expression | string): FunctionExpression { @@ -8684,9 +8684,9 @@ export function arrayMaximum(array: Expression | string): FunctionExpression { * arrayMaximumN("scores", 3); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - The number of elements to return. - * @returns A new {Expression} representing the largest `n` elements. + * @param fieldName The name of the field containing the array. + * @param n The number of elements to return. + * @returns A new `Expression` representing the largest `n` elements. */ export function arrayMaximumN(fieldName: string, n: number): FunctionExpression; @@ -8701,9 +8701,9 @@ export function arrayMaximumN(fieldName: string, n: number): FunctionExpression; * arrayMaximumN("scores", field("count")); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {Expression} representing the largest `n` elements. + * @param fieldName The name of the field containing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the largest `n` elements. */ export function arrayMaximumN( fieldName: string, @@ -8721,9 +8721,9 @@ export function arrayMaximumN( * arrayMaximumN(field("scores"), 3); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - The number of elements to return. - * @returns A new {Expression} representing the largest `n` elements. + * @param arrayExpression The expression representing the array. + * @param n The number of elements to return. + * @returns A new `Expression` representing the largest `n` elements. */ export function arrayMaximumN( arrayExpression: Expression, @@ -8741,9 +8741,9 @@ export function arrayMaximumN( * arrayMaximumN(field("scores"), field("count")); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {Expression} representing the largest `n` elements. + * @param arrayExpression The expression representing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the largest `n` elements. */ export function arrayMaximumN( arrayExpression: Expression, @@ -8767,8 +8767,8 @@ export function arrayMaximumN( * arrayMinimum("scores"); * ``` * - * @param fieldName - The name of the field containing the array. - * @returns A new {Expression} representing the minimum value. + * @param fieldName The name of the field containing the array. + * @returns A new `Expression` representing the minimum value. */ export function arrayMinimum(fieldName: string): FunctionExpression; @@ -8783,8 +8783,8 @@ export function arrayMinimum(fieldName: string): FunctionExpression; * arrayMinimum(field("scores")); * ``` * - * @param arrayExpression - The expression representing the array. - * @returns A new {Expression} representing the minimum value. + * @param arrayExpression The expression representing the array. + * @returns A new `Expression` representing the minimum value. */ export function arrayMinimum(arrayExpression: Expression): FunctionExpression; export function arrayMinimum(array: Expression | string): FunctionExpression { @@ -8802,9 +8802,9 @@ export function arrayMinimum(array: Expression | string): FunctionExpression { * arrayMinimumN("scores", 3); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - The number of elements to return. - * @returns A new {Expression} representing the smallest `n` elements. + * @param fieldName The name of the field containing the array. + * @param n The number of elements to return. + * @returns A new `Expression` representing the smallest `n` elements. */ export function arrayMinimumN(fieldName: string, n: number): FunctionExpression; @@ -8819,9 +8819,9 @@ export function arrayMinimumN(fieldName: string, n: number): FunctionExpression; * arrayMinimumN(field("scores"), field("count")); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {Expression} representing the smallest `n` elements. + * @param fieldName The name of the field containing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the smallest `n` elements. */ export function arrayMinimumN( fieldName: string, @@ -8839,9 +8839,9 @@ export function arrayMinimumN( * arrayMinimumN(field("scores"), 3); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - The number of elements to return. - * @returns A new {Expression} representing the smallest `n` elements. + * @param arrayExpression The expression representing the array. + * @param n The number of elements to return. + * @returns A new `Expression` representing the smallest `n` elements. */ export function arrayMinimumN( arrayExpression: Expression, @@ -8859,9 +8859,9 @@ export function arrayMinimumN( * arrayMinimumN(field("scores"), field("count")); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {Expression} representing the smallest `n` elements. + * @param arrayExpression The expression representing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new `Expression` representing the smallest `n` elements. */ export function arrayMinimumN( arrayExpression: Expression, @@ -8885,10 +8885,10 @@ export function arrayMinimumN( * arraySlice("tags", 0, 3); * ``` * - * @param fieldName - The name of the field containing the array to slice. - * @param start - The index to start the slice. - * @param end - The index to end the slice (inclusive). - * @returns A new {Expression} representing the slice. + * @param fieldName The name of the field containing the array to slice. + * @param start The index to start the slice. + * @param end The index to end the slice (inclusive). + * @returns A new `Expression` representing the slice. */ export function arraySlice( fieldName: string, @@ -8907,10 +8907,10 @@ export function arraySlice( * arraySlice(field("tags"), 0, 3); * ``` * - * @param arrayExpression - The expression representing the array to slice. - * @param start - The index to start the slice. - * @param end - The index to end the slice (inclusive). - * @returns A new {Expression} representing the slice. + * @param arrayExpression The expression representing the array to slice. + * @param start The index to start the slice. + * @param end The index to end the slice (inclusive). + * @returns A new `Expression` representing the slice. */ export function arraySlice( arrayExpression: Expression, @@ -8940,9 +8940,9 @@ export function arraySlice( * arrayIndexOf("tags", "politics"); * ``` * - * @param fieldName - The name of the field containing the array to search. - * @param search - The value to search for. - * @returns A new {Expression} representing the index. + * @param fieldName The name of the field containing the array to search. + * @param search The value to search for. + * @returns A new `Expression` representing the index. */ export function arrayIndexOf( fieldName: string, @@ -8961,9 +8961,9 @@ export function arrayIndexOf( * arrayIndexOf(field("tags"), "politics"); * ``` * - * @param arrayExpression - The expression representing the array to search. - * @param search - The value to search for. - * @returns A new {Expression} representing the index. + * @param arrayExpression The expression representing the array to search. + * @param search The value to search for. + * @returns A new `Expression` representing the index. */ export function arrayIndexOf( arrayExpression: Expression, @@ -8988,9 +8988,9 @@ export function arrayIndexOf( * arrayLastIndexOf("tags", "politics"); * ``` * - * @param fieldName - The name of the field containing the array to search. - * @param search - The value to search for. - * @returns A new {Expression} representing the index. + * @param fieldName The name of the field containing the array to search. + * @param search The value to search for. + * @returns A new `Expression` representing the index. */ export function arrayLastIndexOf( fieldName: string, @@ -9009,9 +9009,9 @@ export function arrayLastIndexOf( * arrayLastIndexOf(field("tags"), "politics"); * ``` * - * @param arrayExpression - The expression representing the array to search. - * @param search - The value to search for. - * @returns A new {Expression} representing the index. + * @param arrayExpression The expression representing the array to search. + * @param search The value to search for. + * @returns A new `Expression` representing the index. */ export function arrayLastIndexOf( arrayExpression: Expression, @@ -9035,9 +9035,9 @@ export function arrayLastIndexOf( * arrayIndexOfAll("scores", 5); * ``` * - * @param fieldName - The name of the field containing the array to search. - * @param search - The value to search for. - * @returns A new {Expression} representing the indices. + * @param fieldName The name of the field containing the array to search. + * @param search The value to search for. + * @returns A new `Expression` representing the indices. */ export function arrayIndexOfAll( fieldName: string, @@ -9055,9 +9055,9 @@ export function arrayIndexOfAll( * arrayIndexOfAll(field("scores"), 5); * ``` * - * @param arrayExpression - The expression representing the array to search. - * @param search - The value to search for. - * @returns A new {Expression} representing the indices. + * @param arrayExpression The expression representing the array to search. + * @param search The value to search for. + * @returns A new `Expression` representing the indices. */ export function arrayIndexOfAll( arrayExpression: Expression, @@ -9081,11 +9081,11 @@ export function arrayIndexOfAll( * arrayFilter("scores", "score", field("score").greaterThan(50)); * ``` * - * @param fieldName - The name of the field containing the array to filter. - * @param variable - The variable name to bind to each element in the array. This variable name + * @param fieldName The name of the field containing the array to filter. + * @param variable The variable name to bind to each element in the array. This variable name * can be used in the `predicate` expression to refer to the current element. - * @param predicate - The predicate boolean expression to filter by. - * @returns A new {Expression} representing the filtered array. + * @param predicate The predicate boolean expression to filter by. + * @returns A new `Expression` representing the filtered array. */ export function arrayFilter( fieldName: string, @@ -9104,11 +9104,11 @@ export function arrayFilter( * arrayFilter(field("scores"), "score", field("score").greaterThan(50)); * ``` * - * @param arrayExpression - The expression representing the array to filter. - * @param variable - The variable name to bind to each element in the array. This variable name - * can be used in the `predicate` expression to refer to the current element. - * @param predicate - The predicate boolean expression to filter by. - * @returns A new {Expression} representing the filtered array. + * @param arrayExpression The expression representing the array to filter. + * @param variable The variable name to bind to each element in the array. This variable + * name can be used in the `predicate` expression to refer to the current element. + * @param predicate The predicate boolean expression to filter by. + * @returns A new `Expression` representing the filtered array. */ export function arrayFilter( arrayExpression: Expression, diff --git a/dev/system-test/pipeline.ts b/dev/system-test/pipeline.ts index 265c2031a..9f398e8f4 100644 --- a/dev/system-test/pipeline.ts +++ b/dev/system-test/pipeline.ts @@ -3177,6 +3177,30 @@ describe.skipClassic('Pipeline class', () => { .select(field('tags').arrayFirstN(2).as('firstTwoTags')) .execute(); expectResults(snapshot, ...expectedResults); + + // Test with empty/null/non-existent + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + empty: [], + nullVal: null, + }), + ) + .select( + arrayFirstN('empty', 1).as('emptyResult'), + arrayFirstN('nullVal', 1).as('nullResult'), + arrayFirstN('nonExistent', 1).as('absentResult'), + ) + .execute(); + + expectResults(snapshot, { + emptyResult: [], + nullResult: null, + absentResult: null, + }); }); it('supports arrayLast', async () => { @@ -3239,6 +3263,30 @@ describe.skipClassic('Pipeline class', () => { .select(field('tags').arrayLastN(2).as('lastTwoTags')) .execute(); expectResults(snapshot, ...expectedResults); + + // Test with empty/null/non-existent + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + empty: [], + nullVal: null, + }), + ) + .select( + arrayLastN('empty', 1).as('emptyResult'), + arrayLastN('nullVal', 1).as('nullResult'), + arrayLastN('nonExistent', 1).as('absentResult'), + ) + .execute(); + + expectResults(snapshot, { + emptyResult: [], + nullResult: null, + absentResult: null, + }); }); it('supports arrayMaximum', async () => { @@ -3264,6 +3312,33 @@ describe.skipClassic('Pipeline class', () => { .select(field('tags').arrayMaximum().as('maxTag')) .execute(); expectResults(snapshot, ...expectedResults); + + // Test with empty/null/non-existent and mixed types + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + empty: [], + nullVal: null, + mixed: [1, '2', 3, '10'], // string > number in Firestore + }), + ) + .select( + arrayMaximum('empty').as('emptyResult'), + arrayMaximum('nullVal').as('nullResult'), + arrayMaximum('nonExistent').as('absentResult'), + arrayMaximum('mixed').as('mixedResult'), + ) + .execute(); + + expectResults(snapshot, { + emptyResult: null, + nullResult: null, + absentResult: null, + mixedResult: '2', // "2" > "10" > 3 > 1 + }); }); it('supports arrayMaximumN', async () => { @@ -3314,6 +3389,33 @@ describe.skipClassic('Pipeline class', () => { .select(field('tags').arrayMinimum().as('minTag')) .execute(); expectResults(snapshot, ...expectedResults); + + // Test with empty/null/non-existent and mixed types + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + empty: [], + nullVal: null, + mixed: [1, '2', 3, '10'], // Strings > Numbers in Firestore + }), + ) + .select( + arrayMinimum('empty').as('emptyResult'), + arrayMinimum('nullVal').as('nullResult'), + arrayMinimum('nonExistent').as('absentResult'), + arrayMinimum('mixed').as('mixedResult'), + ) + .execute(); + + expectResults(snapshot, { + emptyResult: null, + nullResult: null, + absentResult: null, + mixedResult: 1, // 1 < 2 < 3 < "10" + }); }); it('supports arrayMinimumN', async () => { diff --git a/types/firestore.d.ts b/types/firestore.d.ts index d19f2d3bc..c909a455b 100644 --- a/types/firestore.d.ts +++ b/types/firestore.d.ts @@ -7429,11 +7429,11 @@ declare namespace FirebaseFirestore { * arrayFilter("scores", "score", field("score").greaterThan(50)); * ``` * - * @param fieldName - The name of the field containing the array to filter. - * @param variable - The variable name to bind to each element in the array. This variable name + * @param fieldName The name of the field containing the array to filter. + * @param variable The variable name to bind to each element in the array. This variable name * can be used in the `predicate` expression to refer to the current element. - * @param predicate - The predicate boolean expression to filter by. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the filtered array. + * @param predicate The predicate boolean expression to filter by. + * @returns A new {@code Expression} representing the filtered array. */ export function arrayFilter( fieldName: string, @@ -7451,11 +7451,11 @@ declare namespace FirebaseFirestore { * arrayFilter(field("scores"), "score", field("score").greaterThan(50)); * ``` * - * @param arrayExpression - The expression representing the array to filter. - * @param variable - The variable name to bind to each element in the array. This variable name + * @param arrayExpression The expression representing the array to filter. + * @param variable The variable name to bind to each element in the array. This variable name * can be used in the `predicate` expression to refer to the current element. - * @param predicate - The predicate boolean expression to filter by. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the filtered array. + * @param predicate The predicate boolean expression to filter by. + * @returns A new {@code Expression} representing the filtered array. */ export function arrayFilter( arrayExpression: Expression, @@ -7473,8 +7473,8 @@ declare namespace FirebaseFirestore { * arrayFirst("tags"); * ``` * - * @param fieldName - The name of the field containing the array. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the first element. + * @param fieldName The name of the field containing the array. + * @returns A new {@code Expression} representing the first element. */ export function arrayFirst(fieldName: string): FunctionExpression; /** @@ -7488,8 +7488,8 @@ declare namespace FirebaseFirestore { * arrayFirst(field("tags")); * ``` * - * @param arrayExpression - The expression representing the array. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the first element. + * @param arrayExpression The expression representing the array. + * @returns A new {@code Expression} representing the first element. */ export function arrayFirst(arrayExpression: Expression): FunctionExpression; /** @@ -7503,9 +7503,9 @@ declare namespace FirebaseFirestore { * arrayFirstN("tags", 3); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - The number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the first `n` elements. + * @param fieldName The name of the field containing the array. + * @param n The number of elements to return. + * @returns A new {@code Expression} representing the first `n` elements. */ export function arrayFirstN( fieldName: string, @@ -7522,9 +7522,9 @@ declare namespace FirebaseFirestore { * arrayFirstN("tags", field("count")); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the first `n` elements. + * @param fieldName The name of the field containing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new {@code Expression} representing the first `n` elements. */ export function arrayFirstN( fieldName: string, @@ -7541,9 +7541,9 @@ declare namespace FirebaseFirestore { * arrayFirstN(field("tags"), 3); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - The number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the first `n` elements. + * @param arrayExpression The expression representing the array. + * @param n The number of elements to return. + * @returns A new {@code Expression} representing the first `n` elements. */ export function arrayFirstN( arrayExpression: Expression, @@ -7560,9 +7560,9 @@ declare namespace FirebaseFirestore { * arrayFirstN(field("tags"), field("count")); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the first `n` elements. + * @param arrayExpression The expression representing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new {@code Expression} representing the first `n` elements. */ export function arrayFirstN( arrayExpression: Expression, @@ -7580,8 +7580,8 @@ declare namespace FirebaseFirestore { * arrayGet(field('tags'), 1); * ``` * - * @param arrayExpression - An `Expression` evaluating to an array. - * @param offset - The index of the element to return. + * @param arrayExpression An `Expression` evaluating to an array. + * @param offset The index of the element to return. * @returns A new `Expression` representing the 'arrayGet' operation. */ export function arrayIndexOf( @@ -7600,9 +7600,9 @@ declare namespace FirebaseFirestore { * arrayIndexOf(field("tags"), "politics"); * ``` * - * @param arrayExpression - The expression representing the array to search. - * @param search - The value to search for. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the index. + * @param arrayExpression The expression representing the array to search. + * @param search The value to search for. + * @returns A new {@code Expression} representing the index. */ export function arrayIndexOf( arrayExpression: Expression, @@ -7619,9 +7619,9 @@ declare namespace FirebaseFirestore { * arrayIndexOfAll("scores", 5); * ``` * - * @param fieldName - The name of the field containing the array to search. - * @param search - The value to search for. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the indices. + * @param fieldName The name of the field containing the array to search. + * @param search The value to search for. + * @returns A new {@code Expression} representing the indices. */ export function arrayIndexOfAll( fieldName: string, @@ -7638,9 +7638,9 @@ declare namespace FirebaseFirestore { * arrayIndexOfAll(field("scores"), 5); * ``` * - * @param arrayExpression - The expression representing the array to search. - * @param search - The value to search for. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the indices. + * @param arrayExpression The expression representing the array to search. + * @param search The value to search for. + * @returns A new {@code Expression} representing the indices. */ export function arrayIndexOfAll( arrayExpression: Expression, @@ -7657,8 +7657,8 @@ declare namespace FirebaseFirestore { * arrayLast("tags"); * ``` * - * @param fieldName - The name of the field containing the array. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the last element. + * @param fieldName The name of the field containing the array. + * @returns A new {@code Expression} representing the last element. */ export function arrayLast(fieldName: string): FunctionExpression; /** @@ -7672,8 +7672,8 @@ declare namespace FirebaseFirestore { * arrayLast(field("tags")); * ``` * - * @param arrayExpression - The expression representing the array. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the last element. + * @param arrayExpression The expression representing the array. + * @returns A new {@code Expression} representing the last element. */ export function arrayLast(arrayExpression: Expression): FunctionExpression; /** @@ -7688,9 +7688,9 @@ declare namespace FirebaseFirestore { * arrayLastIndexOf("tags", "politics"); * ``` * - * @param fieldName - The name of the field containing the array to search. - * @param search - The value to search for. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the index. + * @param fieldName The name of the field containing the array to search. + * @param search The value to search for. + * @returns A new {@code Expression} representing the index. */ export function arrayLastIndexOf( fieldName: string, @@ -7708,9 +7708,9 @@ declare namespace FirebaseFirestore { * arrayLastIndexOf(field("tags"), "politics"); * ``` * - * @param arrayExpression - The expression representing the array to search. - * @param search - The value to search for. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the index. + * @param arrayExpression The expression representing the array to search. + * @param search The value to search for. + * @returns A new {@code Expression} representing the index. */ export function arrayLastIndexOf( arrayExpression: Expression, @@ -7727,9 +7727,9 @@ declare namespace FirebaseFirestore { * arrayLastN("tags", 3); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - The number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the last `n` elements. + * @param fieldName The name of the field containing the array. + * @param n The number of elements to return. + * @returns A new {@code Expression} representing the last `n` elements. */ export function arrayLastN( fieldName: string, @@ -7746,9 +7746,9 @@ declare namespace FirebaseFirestore { * arrayLastN("tags", field("count")); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the last `n` elements. + * @param fieldName The name of the field containing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new {@code Expression} representing the last `n` elements. */ export function arrayLastN( fieldName: string, @@ -7765,9 +7765,9 @@ declare namespace FirebaseFirestore { * arrayLastN(field("tags"), 3); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - The number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the last `n` elements. + * @param arrayExpression The expression representing the array. + * @param n The number of elements to return. + * @returns A new {@code Expression} representing the last `n` elements. */ export function arrayLastN( arrayExpression: Expression, @@ -7784,9 +7784,9 @@ declare namespace FirebaseFirestore { * arrayLastN(field("tags"), field("count")); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the last `n` elements. + * @param arrayExpression The expression representing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new {@code Expression} representing the last `n` elements. */ export function arrayLastN( arrayExpression: Expression, @@ -7803,8 +7803,8 @@ declare namespace FirebaseFirestore { * arrayMaximum("scores"); * ``` * - * @param fieldName - The name of the field containing the array. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the maximum value. + * @param fieldName The name of the field containing the array. + * @returns A new {@code Expression} representing the maximum value. */ export function arrayMaximum(fieldName: string): FunctionExpression; /** @@ -7818,8 +7818,8 @@ declare namespace FirebaseFirestore { * arrayMaximum(field("scores")); * ``` * - * @param arrayExpression - The expression representing the array. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the maximum value. + * @param arrayExpression The expression representing the array. + * @returns A new {@code Expression} representing the maximum value. */ export function arrayMaximum( arrayExpression: Expression, @@ -7835,9 +7835,9 @@ declare namespace FirebaseFirestore { * arrayMaximumN("scores", 3); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - The number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the largest `n` elements. + * @param fieldName The name of the field containing the array. + * @param n The number of elements to return. + * @returns A new {@code Expression} representing the largest `n` elements. */ export function arrayMaximumN( fieldName: string, @@ -7854,9 +7854,9 @@ declare namespace FirebaseFirestore { * arrayMaximumN("scores", field("count")); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the largest `n` elements. + * @param fieldName The name of the field containing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new {@code Expression} representing the largest `n` elements. */ export function arrayMaximumN( fieldName: string, @@ -7873,9 +7873,9 @@ declare namespace FirebaseFirestore { * arrayMaximumN(field("scores"), 3); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - The number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the largest `n` elements. + * @param arrayExpression The expression representing the array. + * @param n The number of elements to return. + * @returns A new {@code Expression} representing the largest `n` elements. */ export function arrayMaximumN( arrayExpression: Expression, @@ -7892,9 +7892,9 @@ declare namespace FirebaseFirestore { * arrayMaximumN(field("scores"), field("count")); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the largest `n` elements. + * @param arrayExpression The expression representing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new {@code Expression} representing the largest `n` elements. */ export function arrayMaximumN( arrayExpression: Expression, @@ -7911,8 +7911,8 @@ declare namespace FirebaseFirestore { * arrayMinimum("scores"); * ``` * - * @param fieldName - The name of the field containing the array. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the minimum value. + * @param fieldName The name of the field containing the array. + * @returns A new {@code Expression} representing the minimum value. */ export function arrayMinimum(fieldName: string): FunctionExpression; /** @@ -7926,8 +7926,8 @@ declare namespace FirebaseFirestore { * arrayMinimum(field("scores")); * ``` * - * @param arrayExpression - The expression representing the array. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the minimum value. + * @param arrayExpression The expression representing the array. + * @returns A new {@code Expression} representing the minimum value. */ export function arrayMinimum( arrayExpression: Expression, @@ -7943,9 +7943,9 @@ declare namespace FirebaseFirestore { * arrayMinimumN("scores", 3); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - The number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the smallest `n` elements. + * @param fieldName The name of the field containing the array. + * @param n The number of elements to return. + * @returns A new {@code Expression} representing the smallest `n` elements. */ export function arrayMinimumN( fieldName: string, @@ -7962,9 +7962,9 @@ declare namespace FirebaseFirestore { * arrayMinimumN(field("scores"), field("count")); * ``` * - * @param fieldName - The name of the field containing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the smallest `n` elements. + * @param fieldName The name of the field containing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new {@code Expression} representing the smallest `n` elements. */ export function arrayMinimumN( fieldName: string, @@ -7981,9 +7981,9 @@ declare namespace FirebaseFirestore { * arrayMinimumN(field("scores"), 3); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - The number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the smallest `n` elements. + * @param arrayExpression The expression representing the array. + * @param n The number of elements to return. + * @returns A new {@code Expression} representing the smallest `n` elements. */ export function arrayMinimumN( arrayExpression: Expression, @@ -8000,9 +8000,9 @@ declare namespace FirebaseFirestore { * arrayMinimumN(field("scores"), field("count")); * ``` * - * @param arrayExpression - The expression representing the array. - * @param n - An expression evaluating to the number of elements to return. - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the smallest `n` elements. + * @param arrayExpression The expression representing the array. + * @param n An expression evaluating to the number of elements to return. + * @returns A new {@code Expression} representing the smallest `n` elements. */ export function arrayMinimumN( arrayExpression: Expression, @@ -8019,10 +8019,10 @@ declare namespace FirebaseFirestore { * arraySlice("tags", 0, 3); * ``` * - * @param fieldName - The name of the field containing the array to slice. - * @param start - The index to start the slice. - * @param end - The index to end the slice (inclusive). - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the slice. + * @param fieldName The name of the field containing the array to slice. + * @param start The index to start the slice. + * @param end The index to end the slice (inclusive). + * @returns A new {@code Expression} representing the slice. */ export function arraySlice( fieldName: string, @@ -8040,10 +8040,10 @@ declare namespace FirebaseFirestore { * arraySlice(field("tags"), 0, 3); * ``` * - * @param arrayExpression - The expression representing the array to slice. - * @param start - The index to start the slice. - * @param end - The index to end the slice (inclusive). - * @returns A new {@link @firebase/firestore/pipelines#Expression} representing the slice. + * @param arrayExpression The expression representing the array to slice. + * @param start The index to start the slice. + * @param end The index to end the slice (inclusive). + * @returns A new {@code Expression} representing the slice. */ export function arraySlice( arrayExpression: Expression, From 4390881c7b3c19fac0018e4b0ddc847604384e42 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Tue, 24 Feb 2026 15:02:20 -0500 Subject: [PATCH 05/12] remove arraySlice and arrayFilter for now --- api-report/firestore.api.md | 17 --- dev/src/pipelines/expression.ts | 175 ---------------------------- dev/src/pipelines/index.ts | 2 - dev/system-test/pipeline.ts | 196 -------------------------------- types/firestore.d.ts | 53 --------- 5 files changed, 443 deletions(-) diff --git a/api-report/firestore.api.md b/api-report/firestore.api.md index 3747f3a34..3b0dc7277 100644 --- a/api-report/firestore.api.md +++ b/api-report/firestore.api.md @@ -211,12 +211,6 @@ function arrayContainsAny(array: Expression, values: Expression): BooleanExpress // @beta function arrayContainsAny(fieldName: string, values: Expression): BooleanExpression; -// @beta -function arrayFilter(fieldName: string, variable: string, predicate: BooleanExpression): FunctionExpression; - -// @beta -function arrayFilter(arrayExpression: Expression, variable: string, predicate: BooleanExpression): FunctionExpression; - // @beta function arrayFirst(fieldName: string): FunctionExpression; @@ -331,12 +325,6 @@ function arrayReverse(fieldName: string): FunctionExpression; // @beta function arrayReverse(arrayExpression: Expression): FunctionExpression; -// @beta -function arraySlice(fieldName: string, start: number | Expression, end?: number | Expression): FunctionExpression; - -// @beta -function arraySlice(arrayExpression: Expression, start: number | Expression, end?: number | Expression): FunctionExpression; - // @beta function arraySum(fieldName: string): FunctionExpression; @@ -1067,7 +1055,6 @@ abstract class Expression implements firestore.Pipelines.Expression, HasUserData arrayContainsAll(arrayExpression: Expression): BooleanExpression; arrayContainsAny(values: Array): BooleanExpression; arrayContainsAny(arrayExpression: Expression): BooleanExpression; - arrayFilter(variable: string, predicate: BooleanExpression): FunctionExpression; arrayFirst(): FunctionExpression; arrayFirstN(n: number): FunctionExpression; arrayFirstN(n: Expression): FunctionExpression; @@ -1090,8 +1077,6 @@ abstract class Expression implements firestore.Pipelines.Expression, HasUserData arrayMinimumN(n: number): FunctionExpression; arrayMinimumN(n: Expression): FunctionExpression; arrayReverse(): FunctionExpression; - arraySlice(start: number, end?: number): FunctionExpression; - arraySlice(start: Expression, end?: Expression): FunctionExpression; arraySum(): FunctionExpression; as(name: string): AliasedExpression; asBoolean(): BooleanExpression; @@ -1984,7 +1969,6 @@ declare namespace Pipelines { equalAny, map, array, - arrayFilter, arrayFirst, arrayLast, arrayFirstN, @@ -1996,7 +1980,6 @@ declare namespace Pipelines { arrayMinimum, arrayMaximumN, arrayMinimumN, - arraySlice, field, xor, AggregateFunction, diff --git a/dev/src/pipelines/expression.ts b/dev/src/pipelines/expression.ts index 60fba4c14..6f6574a94 100644 --- a/dev/src/pipelines/expression.ts +++ b/dev/src/pipelines/expression.ts @@ -843,49 +843,6 @@ export abstract class Expression return new FunctionExpression('minimum_n', [this, valueToDefaultExpr(n)]); } - /** - * @beta - * Returns a slice of the array. - * - * @example - * ```typescript - * // Get a slice of the 'myArray' field from index 1 to 3 (inclusive). - * field("myArray").arraySlice(1, 3); - * ``` - * - * @param start The index to start the slice. - * @param end The index to end the slice (inclusive). - * @returns A new `Expression` representing the slice. - */ - arraySlice(start: number, end?: number): FunctionExpression; - - /** - * @beta - * Returns a slice of the array. - * - * @example - * ```typescript - * // Get a slice of the 'myArray' field from index value in 'start' field to - * // index value in 'end' field (inclusive). - * field("myArray").arraySlice(field("start"), field("end")); - * ``` - * - * @param start An expression evaluating to the index to start the slice. - * @param end An expression evaluating to the index to end the slice (inclusive). - * @returns A new `Expression` representing the slice. - */ - arraySlice(start: Expression, end?: Expression): FunctionExpression; - arraySlice( - start: number | Expression, - end?: number | Expression, - ): FunctionExpression { - const args = [this, valueToDefaultExpr(start)]; - if (end !== undefined) { - args.push(valueToDefaultExpr(end)); - } - return new FunctionExpression('array_slice', args); - } - /** * @beta * Returns the first index of the search value in the array, or -1 if not found. @@ -996,32 +953,6 @@ export abstract class Expression ]); } - /** - * @beta - * Returns a filtered array containing only elements that match the predicate. - * - * @example - * ```typescript - * // Get a filtered array of the 'scores' field containing only elements greater than 50. - * field("scores").arrayFilter("score", field("score").greaterThan(50)); - * ``` - * - * @param variable The variable name to bind to each element in the array. This variable - * name can be used in the `predicate` expression to refer to the current element. - * @param predicate The predicate boolean expression to filter by. - * @returns A new `Expression` representing the filtered array. - */ - arrayFilter( - variable: string, - predicate: BooleanExpression, - ): FunctionExpression { - return new FunctionExpression('array_filter', [ - this, - valueToDefaultExpr(variable), - predicate, - ]); - } - /** * @beta * Creates an expression that checks if this expression is equal to any of the provided values or @@ -9162,60 +9093,6 @@ export function arrayMinimumN( return fieldOrExpression(array).arrayMinimumN(valueToDefaultExpr(n)); } -/** - * @beta - * - * Creates an expression that returns a slice of an array. - * - * @example - * ```typescript - * // Get the first 3 elements of the 'tags' array field - * arraySlice("tags", 0, 3); - * ``` - * - * @param fieldName The name of the field containing the array to slice. - * @param start The index to start the slice. - * @param end The index to end the slice (inclusive). - * @returns A new `Expression` representing the slice. - */ -export function arraySlice( - fieldName: string, - start: number | Expression, - end?: number | Expression, -): FunctionExpression; - -/** - * @beta - * - * Creates an expression that returns a slice of an array. - * - * @example - * ```typescript - * // Get the first 3 elements of the 'tags' array field - * arraySlice(field("tags"), 0, 3); - * ``` - * - * @param arrayExpression The expression representing the array to slice. - * @param start The index to start the slice. - * @param end The index to end the slice (inclusive). - * @returns A new `Expression` representing the slice. - */ -export function arraySlice( - arrayExpression: Expression, - start: number | Expression, - end?: number | Expression, -): FunctionExpression; -export function arraySlice( - array: Expression | string, - start: number | Expression, - end?: number | Expression, -): FunctionExpression { - return fieldOrExpression(array).arraySlice( - valueToDefaultExpr(start), - end === undefined ? undefined : valueToDefaultExpr(end), - ); -} - /** * @beta * @@ -9358,58 +9235,6 @@ export function arrayIndexOfAll( return fieldOrExpression(array).arrayIndexOfAll(valueToDefaultExpr(search)); } -/** - * @beta - * - * Creates an expression that filters an array based on a predicate. - * - * @example - * ```typescript - * // Filter "scores" to include only values greater than 50 - * arrayFilter("scores", "score", field("score").greaterThan(50)); - * ``` - * - * @param fieldName The name of the field containing the array to filter. - * @param variable The variable name to bind to each element in the array. This variable name - * can be used in the `predicate` expression to refer to the current element. - * @param predicate The predicate boolean expression to filter by. - * @returns A new `Expression` representing the filtered array. - */ -export function arrayFilter( - fieldName: string, - variable: string, - predicate: BooleanExpression, -): FunctionExpression; - -/** - * @beta - * - * Creates an expression that filters an array based on a predicate. - * - * @example - * ```typescript - * // Filter "scores" to include only values greater than 50 - * arrayFilter(field("scores"), "score", field("score").greaterThan(50)); - * ``` - * - * @param arrayExpression The expression representing the array to filter. - * @param variable The variable name to bind to each element in the array. This variable - * name can be used in the `predicate` expression to refer to the current element. - * @param predicate The predicate boolean expression to filter by. - * @returns A new `Expression` representing the filtered array. - */ -export function arrayFilter( - arrayExpression: Expression, - variable: string, - predicate: BooleanExpression, -): FunctionExpression; -export function arrayFilter( - array: Expression | string, - variable: string, - predicate: BooleanExpression, -): FunctionExpression { - return fieldOrExpression(array).arrayFilter(variable, predicate); -} // TODO(new-expression): Add new top-level expression function definitions above this line /** diff --git a/dev/src/pipelines/index.ts b/dev/src/pipelines/index.ts index b54984d40..686848ef4 100644 --- a/dev/src/pipelines/index.ts +++ b/dev/src/pipelines/index.ts @@ -54,7 +54,6 @@ export { equalAny, map, array, - arrayFilter, arrayFirst, arrayLast, arrayFirstN, @@ -66,7 +65,6 @@ export { arrayMinimum, arrayMaximumN, arrayMinimumN, - arraySlice, field, xor, AggregateFunction, diff --git a/dev/system-test/pipeline.ts b/dev/system-test/pipeline.ts index f73a33232..71f90dfc2 100644 --- a/dev/system-test/pipeline.ts +++ b/dev/system-test/pipeline.ts @@ -146,7 +146,6 @@ import {getTestDb, getTestRoot} from './firestore'; import {Firestore as InternalFirestore} from '../src'; import {ServiceError} from 'google-gax'; import { - arrayFilter, arrayFirst, arrayFirstN, arrayIndexOf, @@ -158,7 +157,6 @@ import { arrayMaximumN, arrayMinimum, arrayMinimumN, - arraySlice, regexFind, regexFindAll, } from '../src/pipelines/expression'; @@ -3553,49 +3551,6 @@ describe.skipClassic('Pipeline class', () => { expectResults(snapshot, ...expectedResults); }); - it('supports arraySlice', async () => { - let snapshot = await firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select( - arraySlice('tags', 0, 1).as('slice1'), // inclusive start and end - arraySlice('tags', 1, 100).as('slice2'), // overflow end - arraySlice('tags', 1).as('slice3'), // slice to end - field('tags').arraySlice(1, 2).as('slice4'), // class method - arraySlice('empty', 0, 1).as('sliceEmpty'), // null array - ) - .execute(); - const expectedResults = [ - { - slice1: ['adventure', 'magic'], - slice2: ['magic', 'epic'], - slice3: ['magic', 'epic'], - slice4: ['magic', 'epic'], - sliceEmpty: null, - }, - ]; - expectResults(snapshot, ...expectedResults); - - // Test with expressions - snapshot = await firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select( - arraySlice('tags', field('tags').arrayLength().subtract(2)).as( - 'slice', - ), - ) - .execute(); - // length of tags is 3. slice(1) -> ['magic', 'epic'] - expectResults(snapshot, { - slice: ['magic', 'epic'], - }); - }); - it('supports arrayIndexOf', async () => { const snapshot = await firestore .pipeline() @@ -3732,157 +3687,6 @@ describe.skipClassic('Pipeline class', () => { }); }); - describe('arrayFilter', () => { - it('supports arrayFilter simple', async () => { - const snapshot = await firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .replaceWith( - map({ - arr: [1, 2, 3, 4, 5], - arr2: [10, 20], - empty: [], - nullArr: null, - notArr: [1, 2, 3, 4, 5], - }), - ) - .select( - field('arr') - .arrayFilter('element', field('element').greaterThan(3)) - .as('result1'), - arrayFilter('arr2', 'element', field('element').greaterThan(3)).as( - 'result2', - ), - arrayFilter('empty', 'element', field('element').greaterThan(3)).as( - 'result3', - ), - arrayFilter( - 'nullArr', - 'element', - field('element').greaterThan(3), - ).as('result4'), - ) - .execute(); - expectResults(snapshot, { - result1: [4, 5], - result2: [10, 20], - result3: [], - result4: null, - }); - }); - - it('supports arrayFilter on map property', async () => { - const snapshot = await firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .replaceWith( - map({ - arr: [{a: {b: 1}}, {a: {b: 2}}, {a: {b: 3}}], - }), - ) - .select( - arrayFilter('arr', 'element', field('element.a.b').equal(2)).as( - 'result', - ), - ) - .execute(); - expectResults(snapshot, { - result: [{a: {b: 2}}], - }); - }); - - it('supports arrayFilter nested child references parent', async () => { - const snapshot = await firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .replaceWith( - map({ - arr: [ - {outerVal: 2, innerArr: [1, 2, 3]}, - {outerVal: 5, innerArr: [4, 5, 6]}, - {outerVal: 9, innerArr: [7, 8]}, - ], - }), - ) - .select( - arrayFilter( - field('arr'), - 'parent', - field('parent.innerArr') - .arrayFilter( - 'child', - field('child').equal(field('parent.outerVal')), - ) - .length() - .greaterThan(0), - ).as('result'), - ) - .execute(); - expectResults(snapshot, { - result: [ - {outerVal: 2, innerArr: [1, 2, 3]}, - {outerVal: 5, innerArr: [4, 5, 6]}, - ], - }); - }); - - it('supports arrayFilter nested child references other fields', async () => { - const snapshot = await firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .replaceWith( - map({ - otherField: 2, - arr: [{nested: [1, 2, 3]}, {nested: [4, 5, 6]}], - }), - ) - .select( - field('__name__'), - arrayFilter( - field('arr'), - 'outer', - arrayContains( - arrayFilter( - field('outer.nested'), - 'inner', - field('otherField').equal(constant(2)), - ), - constant(1), - ), - ).as('result'), - ) - .execute(); - expectResults(snapshot, { - result: [{nested: [1, 2, 3]}], - }); - }); - - it('supports arrayFilter edge case missing property in map', async () => { - const snapshot = await firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .replaceWith( - map({ - arr: [{a: 1}, {b: 2}, {a: 3}], - }), - ) - .select( - arrayFilter('arr', 'element', field('element.a').greaterThan(1)).as( - 'result', - ), - ) - .execute(); - expectResults(snapshot, { - result: [{a: 3}], - }); - }); - }); - it('supports map', async () => { const snapshot = await firestore .pipeline() diff --git a/types/firestore.d.ts b/types/firestore.d.ts index b74c466fe..34d54edd7 100644 --- a/types/firestore.d.ts +++ b/types/firestore.d.ts @@ -3807,39 +3807,6 @@ declare namespace FirebaseFirestore { */ arrayMinimumN(n: Expression): FunctionExpression; - /** - * @beta - * Returns a slice of the array. - * - * @example - * ```typescript - * // Get a slice of the 'myArray' field from index 1 to 3 (inclusive). - * field("myArray").arraySlice(1, 3); - * ``` - * - * @param start The index to start the slice. - * @param end The index to end the slice (inclusive). - * @returns A new `Expression` representing the slice. - */ - arraySlice(start: number, end?: number): FunctionExpression; - - /** - * @beta - * Returns a slice of the array. - * - * @example - * ```typescript - * // Get a slice of the 'myArray' field from index value in 'start' field to - * // index value in 'end' field (inclusive). - * field("myArray").arraySlice(field("start"), field("end")); - * ``` - * - * @param start An expression evaluating to the index to start the slice. - * @param end An expression evaluating to the index to end the slice (inclusive). - * @returns A new `Expression` representing the slice. - */ - arraySlice(start: Expression, end?: Expression): FunctionExpression; - /** * @beta * Returns the first index of the search value in the array, or -1 if not found. @@ -3930,26 +3897,6 @@ declare namespace FirebaseFirestore { */ arrayIndexOfAll(search: Expression): FunctionExpression; - /** - * @beta - * Returns a filtered array containing only elements that match the predicate. - * - * @example - * ```typescript - * // Get a filtered array of the 'scores' field containing only elements greater than 50. - * field("scores").arrayFilter("score", field("score").greaterThan(50)); - * ``` - * - * @param variable The variable name to bind to each element in the array. This variable name - * can be used in the `predicate` expression to refer to the current element. - * @param predicate The predicate boolean expression to filter by. - * @returns A new `Expression` representing the filtered array. - */ - arrayFilter( - variable: string, - predicate: BooleanExpression, - ): FunctionExpression; - /** * @beta * Creates an expression that checks if this expression is equal to any of the provided values or From 746281285c958d90972c87aa13f50181000666a5 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Tue, 24 Feb 2026 15:14:57 -0500 Subject: [PATCH 06/12] Update pipeline.ts --- dev/system-test/pipeline.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/dev/system-test/pipeline.ts b/dev/system-test/pipeline.ts index 2c1eba064..0ec5bc3e9 100644 --- a/dev/system-test/pipeline.ts +++ b/dev/system-test/pipeline.ts @@ -80,8 +80,6 @@ import { arrayMaximumN, arrayMinimum, arrayMinimumN, - regexFind, - regexFindAll, average, countAll, endsWith, From 0bb00da6126d06d725274e7e0852cef46b853068 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Wed, 25 Feb 2026 12:13:01 -0500 Subject: [PATCH 07/12] update arrayFirst, arrayLast tests --- dev/system-test/pipeline.ts | 48 +++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/dev/system-test/pipeline.ts b/dev/system-test/pipeline.ts index 0ec5bc3e9..bef2d6286 100644 --- a/dev/system-test/pipeline.ts +++ b/dev/system-test/pipeline.ts @@ -3252,6 +3252,30 @@ describe.skipClassic('Pipeline class', () => { .select(field('tags').arrayFirst().as('firstTag')) .execute(); expectResults(snapshot, ...expectedResults); + + // Test with empty/null/non-existent + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + empty: [], + nullVal: null, + }), + ) + .select( + arrayFirst('empty').as('emptyResult'), + arrayFirst('nullVal').as('nullResult'), + arrayFirst('nonExistent').as('absentResult'), + ) + .execute(); + + expectResults(snapshot, { + // no emptyResult because arrayFirst returns UNSET for empty arrays + nullResult: null, + absentResult: null, + }); }); it('supports arrayFirstN', async () => { @@ -3338,6 +3362,30 @@ describe.skipClassic('Pipeline class', () => { .select(field('tags').arrayLast().as('lastTag')) .execute(); expectResults(snapshot, ...expectedResults); + + // Test with empty/null/non-existent + snapshot = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + empty: [], + nullVal: null, + }), + ) + .select( + arrayLast('empty').as('emptyResult'), + arrayLast('nullVal').as('nullResult'), + arrayLast('nonExistent').as('absentResult'), + ) + .execute(); + + expectResults(snapshot, { + // no emptyResult because arrayLast returns UNSET for empty arrays + nullResult: null, + absentResult: null, + }); }); it('supports arrayLastN', async () => { From d836142f61cb5d32c44559229a873485a14e24b7 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Wed, 25 Feb 2026 15:52:47 -0500 Subject: [PATCH 08/12] update jsdoc --- dev/src/pipelines/expression.ts | 48 ++++++++++ types/firestore.d.ts | 163 ++++++++++---------------------- 2 files changed, 96 insertions(+), 115 deletions(-) diff --git a/dev/src/pipelines/expression.ts b/dev/src/pipelines/expression.ts index 6f6574a94..45c5925c0 100644 --- a/dev/src/pipelines/expression.ts +++ b/dev/src/pipelines/expression.ts @@ -765,6 +765,10 @@ export abstract class Expression * @beta * Returns the largest `n` elements of the array. * + * Returns the n largest non-null elements in the array, in descending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the largest 3 elements of the 'myArray' field. @@ -780,6 +784,10 @@ export abstract class Expression * @beta * Returns the largest `n` elements of the array. * + * Returns the n largest non-null elements in the array, in descending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the largest n elements of the 'myArray' field. @@ -814,6 +822,10 @@ export abstract class Expression * @beta * Returns the smallest `n` elements of the array. * + * Note: Returns the n smallest non-null elements in the array, in ascending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. + * * @example * ```typescript * // Get the smallest 3 elements of the 'myArray' field. @@ -829,6 +841,10 @@ export abstract class Expression * @beta * Returns the smallest `n` elements of the array. * + * Note: Returns the n smallest non-null elements in the array, in ascending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. + * * @example * ```typescript * // Get the smallest n elements of the 'myArray' field. @@ -8897,6 +8913,10 @@ export function arrayMaximum(array: Expression | string): FunctionExpression { * * Creates an expression that returns the largest `n` elements of an array. * + * Returns the n largest non-null elements in the array, in descending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the top 3 scores from the 'scores' array field @@ -8914,6 +8934,10 @@ export function arrayMaximumN(fieldName: string, n: number): FunctionExpression; * * Creates an expression that returns the largest `n` elements of an array. * + * Returns the n largest non-null elements in the array, in descending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the top n scores from the 'scores' array field @@ -8934,6 +8958,10 @@ export function arrayMaximumN( * * Creates an expression that returns the largest `n` elements of an array. * + * Returns the n largest non-null elements in the array, in descending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the top 3 elements from an array expression @@ -8954,6 +8982,10 @@ export function arrayMaximumN( * * Creates an expression that returns the largest `n` elements of an array. * + * Returns the n largest non-null elements in the array, in descending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the top n elements from an array expression @@ -9015,6 +9047,10 @@ export function arrayMinimum(array: Expression | string): FunctionExpression { * * Creates an expression that returns the smallest `n` elements of an array. * + * Note: Returns the n smallest non-null elements in the array, in ascending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. + * * @example * ```typescript * // Get the bottom 3 scores from the 'scores' array field @@ -9032,6 +9068,10 @@ export function arrayMinimumN(fieldName: string, n: number): FunctionExpression; * * Creates an expression that returns the smallest `n` elements of an array. * + * Note: Returns the n smallest non-null elements in the array, in ascending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. + * * @example * ```typescript * // Get the bottom n scores from the 'scores' array field @@ -9052,6 +9092,10 @@ export function arrayMinimumN( * * Creates an expression that returns the smallest `n` elements of an array. * + * Note: Returns the n smallest non-null elements in the array, in ascending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. + * * @example * ```typescript * // Get the bottom 3 scores from the 'scores' array field @@ -9072,6 +9116,10 @@ export function arrayMinimumN( * * Creates an expression that returns the smallest `n` elements of an array. * + * Note: Returns the n smallest non-null elements in the array, in ascending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. + * * @example * ```typescript * // Get the bottom n scores from the 'scores' array field diff --git a/types/firestore.d.ts b/types/firestore.d.ts index 34d54edd7..74142a363 100644 --- a/types/firestore.d.ts +++ b/types/firestore.d.ts @@ -3737,6 +3737,10 @@ declare namespace FirebaseFirestore { * @beta * Returns the largest `n` elements of the array. * + * Returns the n largest non-null elements in the array, in descending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the largest 3 elements of the 'myArray' field. @@ -3752,6 +3756,10 @@ declare namespace FirebaseFirestore { * @beta * Returns the largest `n` elements of the array. * + * Returns the n largest non-null elements in the array, in descending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the largest n elements of the 'myArray' field. @@ -3781,6 +3789,10 @@ declare namespace FirebaseFirestore { * @beta * Returns the smallest `n` elements of the array. * + * Returns the n smallest non-null elements in the array, in ascending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the smallest 3 elements of the 'myArray' field. @@ -3796,6 +3808,10 @@ declare namespace FirebaseFirestore { * @beta * Returns the smallest `n` elements of the array. * + * Returns the n smallest non-null elements in the array, in ascending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the smallest n elements of the 'myArray' field. @@ -7444,51 +7460,6 @@ declare namespace FirebaseFirestore { /** * @beta - * - * Creates an expression that filters an array based on a predicate. - * - * @example - * ```typescript - * // Filter "scores" to include only values greater than 50 - * arrayFilter("scores", "score", field("score").greaterThan(50)); - * ``` - * - * @param fieldName The name of the field containing the array to filter. - * @param variable The variable name to bind to each element in the array. This variable name - * can be used in the `predicate` expression to refer to the current element. - * @param predicate The predicate boolean expression to filter by. - * @returns A new {@code Expression} representing the filtered array. - */ - export function arrayFilter( - fieldName: string, - variable: string, - predicate: BooleanExpression, - ): FunctionExpression; - /** - * @beta - * - * Creates an expression that filters an array based on a predicate. - * - * @example - * ```typescript - * // Filter "scores" to include only values greater than 50 - * arrayFilter(field("scores"), "score", field("score").greaterThan(50)); - * ``` - * - * @param arrayExpression The expression representing the array to filter. - * @param variable The variable name to bind to each element in the array. This variable name - * can be used in the `predicate` expression to refer to the current element. - * @param predicate The predicate boolean expression to filter by. - * @returns A new {@code Expression} representing the filtered array. - */ - export function arrayFilter( - arrayExpression: Expression, - variable: string, - predicate: BooleanExpression, - ): FunctionExpression; - /** - * @beta - * * Creates an expression that returns the first element of an array. * * @example @@ -7503,7 +7474,6 @@ declare namespace FirebaseFirestore { export function arrayFirst(fieldName: string): FunctionExpression; /** * @beta - * * Creates an expression that returns the first element of an array. * * @example @@ -7518,7 +7488,6 @@ declare namespace FirebaseFirestore { export function arrayFirst(arrayExpression: Expression): FunctionExpression; /** * @beta - * * Creates an expression that returns the first `n` elements of an array. * * @example @@ -7537,7 +7506,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the first `n` elements of an array. * * @example @@ -7556,7 +7524,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the first `n` elements of an array. * * @example @@ -7575,7 +7542,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the first `n` elements of an array. * * @example @@ -7614,7 +7580,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the first index of the search value in an array. * Returns -1 if the value is not found. * @@ -7634,7 +7599,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns all indices of the search value in an array. * * @example @@ -7653,7 +7617,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns all indices of the search value in an array. * * @example @@ -7672,7 +7635,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the last element of an array. * * @example @@ -7687,7 +7649,6 @@ declare namespace FirebaseFirestore { export function arrayLast(fieldName: string): FunctionExpression; /** * @beta - * * Creates an expression that returns the last element of an array. * * @example @@ -7702,7 +7663,6 @@ declare namespace FirebaseFirestore { export function arrayLast(arrayExpression: Expression): FunctionExpression; /** * @beta - * * Creates an expression that returns the last index of the search value in an array. * Returns -1 if the value is not found. * @@ -7722,7 +7682,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the last index of the search value in an array. * Returns -1 if the value is not found. * @@ -7742,7 +7701,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the last `n` elements of an array. * * @example @@ -7761,7 +7719,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the last `n` elements of an array. * * @example @@ -7780,7 +7737,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the last `n` elements of an array. * * @example @@ -7799,7 +7755,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the last `n` elements of an array. * * @example @@ -7818,7 +7773,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the maximum value in an array. * * @example @@ -7833,7 +7787,6 @@ declare namespace FirebaseFirestore { export function arrayMaximum(fieldName: string): FunctionExpression; /** * @beta - * * Creates an expression that returns the maximum value in an array. * * @example @@ -7850,9 +7803,12 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the largest `n` elements of an array. * + * Returns the n largest non-null elements in the array, in descending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the top 3 scores from the 'scores' array field @@ -7869,9 +7825,12 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the largest `n` elements of an array. * + * Returns the n largest non-null elements in the array, in descending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the top n scores from the 'scores' array field @@ -7888,9 +7847,12 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the largest `n` elements of an array. * + * Returns the n largest non-null elements in the array, in descending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the top 3 elements from an array expression @@ -7907,9 +7869,12 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the largest `n` elements of an array. * + * Returns the n largest non-null elements in the array, in descending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the top n elements from an array expression @@ -7926,7 +7891,6 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the minimum value in an array. * * @example @@ -7941,7 +7905,6 @@ declare namespace FirebaseFirestore { export function arrayMinimum(fieldName: string): FunctionExpression; /** * @beta - * * Creates an expression that returns the minimum value in an array. * * @example @@ -7958,9 +7921,12 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the smallest `n` elements of an array. * + * Returns the n smallest non-null elements in the array, in ascending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the bottom 3 scores from the 'scores' array field @@ -7977,9 +7943,12 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the smallest `n` elements of an array. * + * Returns the n smallest non-null elements in the array, in ascending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the bottom n scores from the 'scores' array field @@ -7996,9 +7965,12 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the smallest `n` elements of an array. * + * Returns the n smallest non-null elements in the array, in ascending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the bottom 3 scores from the 'scores' array field @@ -8015,9 +7987,12 @@ declare namespace FirebaseFirestore { ): FunctionExpression; /** * @beta - * * Creates an expression that returns the smallest `n` elements of an array. * + * Returns the n smallest non-null elements in the array, in ascending order. + * This does not use a stable sort, meaning the order of equivalent elements + * is undefined. + * * @example * ```typescript * // Get the bottom n scores from the 'scores' array field @@ -8032,48 +8007,6 @@ declare namespace FirebaseFirestore { arrayExpression: Expression, n: Expression, ): FunctionExpression; - /** - * @beta - * - * Creates an expression that returns a slice of an array. - * - * @example - * ```typescript - * // Get the first 3 elements of the 'tags' array field - * arraySlice("tags", 0, 3); - * ``` - * - * @param fieldName The name of the field containing the array to slice. - * @param start The index to start the slice. - * @param end The index to end the slice (inclusive). - * @returns A new {@code Expression} representing the slice. - */ - export function arraySlice( - fieldName: string, - start: number | Expression, - end?: number | Expression, - ): FunctionExpression; - /** - * @beta - * - * Creates an expression that returns a slice of an array. - * - * @example - * ```typescript - * // Get the first 3 elements of the 'tags' array field - * arraySlice(field("tags"), 0, 3); - * ``` - * - * @param arrayExpression The expression representing the array to slice. - * @param start The index to start the slice. - * @param end The index to end the slice (inclusive). - * @returns A new {@code Expression} representing the slice. - */ - export function arraySlice( - arrayExpression: Expression, - start: number | Expression, - end?: number | Expression, - ): FunctionExpression; /** * @beta From 79d653fb52139ccec9f39ee500e9aa7cdcf970a5 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Thu, 26 Feb 2026 13:30:41 -0500 Subject: [PATCH 09/12] update jsdocs --- dev/src/pipelines/expression.ts | 36 ++++++++--------- dev/system-test/pipeline.ts | 62 +++++++++++++++++++++------- types/firestore.d.ts | 72 ++++++++++++++++----------------- 3 files changed, 102 insertions(+), 68 deletions(-) diff --git a/dev/src/pipelines/expression.ts b/dev/src/pipelines/expression.ts index 22346285c..49fd71a83 100644 --- a/dev/src/pipelines/expression.ts +++ b/dev/src/pipelines/expression.ts @@ -765,9 +765,9 @@ export abstract class Expression * @beta * Returns the largest `n` elements of the array. * - * Returns the n largest non-null elements in the array, in descending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n largest non-null elements in the array, in descending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -784,9 +784,9 @@ export abstract class Expression * @beta * Returns the largest `n` elements of the array. * - * Returns the n largest non-null elements in the array, in descending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n largest non-null elements in the array, in descending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -9060,9 +9060,9 @@ export function arrayMaximum(array: Expression | string): FunctionExpression { * * Creates an expression that returns the largest `n` elements of an array. * - * Returns the n largest non-null elements in the array, in descending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n largest non-null elements in the array, in descending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -9081,9 +9081,9 @@ export function arrayMaximumN(fieldName: string, n: number): FunctionExpression; * * Creates an expression that returns the largest `n` elements of an array. * - * Returns the n largest non-null elements in the array, in descending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n largest non-null elements in the array, in descending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -9105,9 +9105,9 @@ export function arrayMaximumN( * * Creates an expression that returns the largest `n` elements of an array. * - * Returns the n largest non-null elements in the array, in descending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n largest non-null elements in the array, in descending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -9129,9 +9129,9 @@ export function arrayMaximumN( * * Creates an expression that returns the largest `n` elements of an array. * - * Returns the n largest non-null elements in the array, in descending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n largest non-null elements in the array, in descending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript diff --git a/dev/system-test/pipeline.ts b/dev/system-test/pipeline.ts index a830b4584..c06b679be 100644 --- a/dev/system-test/pipeline.ts +++ b/dev/system-test/pipeline.ts @@ -3634,14 +3634,31 @@ describe.skipClassic('Pipeline class', () => { arr: [1, 2, 3, 2, 1], }), ) - .select( - arrayIndexOf('arr', 2).as('firstIndex'), - arrayLastIndexOf('arr', 2).as('lastIndex'), - ) + .select(arrayIndexOf('arr', 2).as('firstIndex')) .execute(); expectResults(snapshotDuplicates, { firstIndex: 1, - lastIndex: 3, + }); + + // Test with null values + const snapshotNull = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + arr: [1, null, 3, null, 1], + nullArr: null, + }), + ) + .select( + arrayIndexOf('arr', null).as('firstNullIndex'), + arrayIndexOf('nullArr', 1).as('nullArrIndex'), + ) + .execute(); + expectResults(snapshotNull, { + firstNullIndex: 1, + nullArrIndex: null, }); }); @@ -3680,13 +3697,9 @@ describe.skipClassic('Pipeline class', () => { arr: [1, 2, 3, 2, 1], }), ) - .select( - arrayIndexOf('arr', 2).as('firstIndex'), - arrayLastIndexOf('arr', 2).as('lastIndex'), - ) + .select(arrayLastIndexOf('arr', 2).as('lastIndex')) .execute(); expectResults(snapshotDuplicates, { - firstIndex: 1, lastIndex: 3, }); }); @@ -3698,10 +3711,10 @@ describe.skipClassic('Pipeline class', () => { .sort(field('rating').descending()) .limit(1) .select( - arrayIndexOfAll('tags', 'adventure').as('indicesFirst'), // [0] - arrayIndexOfAll(field('tags'), 'epic').as('indicesLast'), // [2] - field('tags').arrayIndexOfAll('nonexistent').as('indicesNone'), // [] - arrayIndexOfAll('empty', 'anything').as('indicesEmpty'), // [] + arrayIndexOfAll('tags', 'adventure').as('indicesFirst'), + arrayIndexOfAll(field('tags'), 'epic').as('indicesLast'), + field('tags').arrayIndexOfAll('nonexistent').as('indicesNone'), + arrayIndexOfAll('empty', 'anything').as('indicesEmpty'), ) .execute(); const expectedResults = [ @@ -3733,6 +3746,27 @@ describe.skipClassic('Pipeline class', () => { indices1: [0, 4], indices2: [1, 3], }); + + // Test with null values + const snapshotNull = await firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .replaceWith( + map({ + arr: [1, null, 3, null, 1], + nullArr: null, + }), + ) + .select( + arrayIndexOfAll('arr', null).as('nullIndices'), + arrayIndexOfAll('nullArr', null).as('nullArrIndices'), + ) + .execute(); + expectResults(snapshotNull, { + nullIndices: [1, 3], + nullArrIndices: null, + }); }); it('supports map', async () => { diff --git a/types/firestore.d.ts b/types/firestore.d.ts index bcf106a7d..7155d8dd6 100644 --- a/types/firestore.d.ts +++ b/types/firestore.d.ts @@ -3737,9 +3737,9 @@ declare namespace FirebaseFirestore { * @beta * Returns the largest `n` elements of the array. * - * Returns the n largest non-null elements in the array, in descending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n largest non-null elements in the array, in descending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -3756,9 +3756,9 @@ declare namespace FirebaseFirestore { * @beta * Returns the largest `n` elements of the array. * - * Returns the n largest non-null elements in the array, in descending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n largest non-null elements in the array, in descending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -3789,9 +3789,9 @@ declare namespace FirebaseFirestore { * @beta * Returns the smallest `n` elements of the array. * - * Returns the n smallest non-null elements in the array, in ascending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n smallest non-null elements in the array, in ascending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -3808,9 +3808,9 @@ declare namespace FirebaseFirestore { * @beta * Returns the smallest `n` elements of the array. * - * Returns the n smallest non-null elements in the array, in ascending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n smallest non-null elements in the array, in ascending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -7846,9 +7846,9 @@ declare namespace FirebaseFirestore { * @beta * Creates an expression that returns the largest `n` elements of an array. * - * Returns the n largest non-null elements in the array, in descending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n largest non-null elements in the array, in descending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -7868,9 +7868,9 @@ declare namespace FirebaseFirestore { * @beta * Creates an expression that returns the largest `n` elements of an array. * - * Returns the n largest non-null elements in the array, in descending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n largest non-null elements in the array, in descending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -7890,9 +7890,9 @@ declare namespace FirebaseFirestore { * @beta * Creates an expression that returns the largest `n` elements of an array. * - * Returns the n largest non-null elements in the array, in descending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n largest non-null elements in the array, in descending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -7912,9 +7912,9 @@ declare namespace FirebaseFirestore { * @beta * Creates an expression that returns the largest `n` elements of an array. * - * Returns the n largest non-null elements in the array, in descending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n largest non-null elements in the array, in descending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -7964,9 +7964,9 @@ declare namespace FirebaseFirestore { * @beta * Creates an expression that returns the smallest `n` elements of an array. * - * Returns the n smallest non-null elements in the array, in ascending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n smallest non-null elements in the array, in ascending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -7986,9 +7986,9 @@ declare namespace FirebaseFirestore { * @beta * Creates an expression that returns the smallest `n` elements of an array. * - * Returns the n smallest non-null elements in the array, in ascending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n smallest non-null elements in the array, in ascending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -8008,9 +8008,9 @@ declare namespace FirebaseFirestore { * @beta * Creates an expression that returns the smallest `n` elements of an array. * - * Returns the n smallest non-null elements in the array, in ascending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n smallest non-null elements in the array, in ascending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript @@ -8030,9 +8030,9 @@ declare namespace FirebaseFirestore { * @beta * Creates an expression that returns the smallest `n` elements of an array. * - * Returns the n smallest non-null elements in the array, in ascending order. - * This does not use a stable sort, meaning the order of equivalent elements - * is undefined. + * Note: Returns the n smallest non-null elements in the array, in ascending + * order. This does not use a stable sort, meaning the order of equivalent + * elements is undefined. * * @example * ```typescript From 5dd8d90823ebfe0d80ac9c83e891b75c5a1d3d98 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Thu, 26 Feb 2026 13:33:59 -0500 Subject: [PATCH 10/12] use enum for magic strings --- dev/src/pipelines/expression.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/dev/src/pipelines/expression.ts b/dev/src/pipelines/expression.ts index 49fd71a83..be9bdc3c2 100644 --- a/dev/src/pipelines/expression.ts +++ b/dev/src/pipelines/expression.ts @@ -29,6 +29,17 @@ import { import {HasUserData, Serializer, validateUserInput} from '../serializer'; import {cast} from '../util'; +/** + * Direction of array index. + * + * @private + * @internal + */ +enum ArrayIndexDirection { + FIRST = 'first', + LAST = 'last', +} + /** * @beta * Represents an expression that can be evaluated to a value within the execution of a `Pipeline`. @@ -892,7 +903,7 @@ export abstract class Expression return new FunctionExpression('array_index_of', [ this, valueToDefaultExpr(search), - valueToDefaultExpr('first'), + valueToDefaultExpr(ArrayIndexDirection.FIRST), ]); } @@ -929,7 +940,7 @@ export abstract class Expression return new FunctionExpression('array_index_of', [ this, valueToDefaultExpr(search), - valueToDefaultExpr('last'), + valueToDefaultExpr(ArrayIndexDirection.LAST), ]); } From 2405fb535f8832da44e998ec7b4a9b520c2c0bc7 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Thu, 26 Feb 2026 13:55:53 -0500 Subject: [PATCH 11/12] Update expression.ts --- dev/src/pipelines/expression.ts | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/dev/src/pipelines/expression.ts b/dev/src/pipelines/expression.ts index be9bdc3c2..49fd71a83 100644 --- a/dev/src/pipelines/expression.ts +++ b/dev/src/pipelines/expression.ts @@ -29,17 +29,6 @@ import { import {HasUserData, Serializer, validateUserInput} from '../serializer'; import {cast} from '../util'; -/** - * Direction of array index. - * - * @private - * @internal - */ -enum ArrayIndexDirection { - FIRST = 'first', - LAST = 'last', -} - /** * @beta * Represents an expression that can be evaluated to a value within the execution of a `Pipeline`. @@ -903,7 +892,7 @@ export abstract class Expression return new FunctionExpression('array_index_of', [ this, valueToDefaultExpr(search), - valueToDefaultExpr(ArrayIndexDirection.FIRST), + valueToDefaultExpr('first'), ]); } @@ -940,7 +929,7 @@ export abstract class Expression return new FunctionExpression('array_index_of', [ this, valueToDefaultExpr(search), - valueToDefaultExpr(ArrayIndexDirection.LAST), + valueToDefaultExpr('last'), ]); } From 1bb8f76e933f0d6750cfde07c7b74f1d6f7a257a Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Thu, 26 Feb 2026 14:32:26 -0500 Subject: [PATCH 12/12] fix merge error --- dev/src/pipelines/expression.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dev/src/pipelines/expression.ts b/dev/src/pipelines/expression.ts index ac1461f17..0aa326ef2 100644 --- a/dev/src/pipelines/expression.ts +++ b/dev/src/pipelines/expression.ts @@ -9483,10 +9483,11 @@ export function arrayIndexOfAll( search: unknown | Expression, ): FunctionExpression { return fieldOrExpression(array).arrayIndexOfAll(valueToDefaultExpr(search)); - - /** +} + +/** * @beta - * + * * Creates an expression that checks if the value in the specified field is of the given type. * * @remarks Null or undefined fields evaluate to skip/error. Use `ifAbsent()` / `isAbsent()` to evaluate missing data.