From e23ecfb87de5c956572e18a7319637d6bc40fa86 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:05:29 -0700 Subject: [PATCH 01/75] Multiple entry points for main package. --- common/api-review/firestore-pipelines.api.md | 1751 +++++++++++++++++ common/api-review/firestore.api.md | 1742 +--------------- .../firebase/firestore/pipelines/index.ts | 18 + .../firebase/firestore/pipelines/package.json | 7 + packages/firebase/package.json | 12 + packages/firestore/package.json | 40 +- packages/firestore/pipelines/package.json | 14 + packages/firestore/rollup.config.js | 48 +- packages/firestore/rollup.shared.js | 4 + packages/firestore/src/all_packages.ts | 25 + packages/firestore/src/api.ts | 169 -- packages/firestore/src/api_pipelines.ts | 8 +- packages/firestore/src/pipelines.node.ts | 18 + packages/firestore/src/pipelines.rn.ts | 18 + packages/firestore/src/pipelines.ts | 50 + .../test/integration/util/firebase_export.ts | 1 + repo-scripts/prune-dts/extract-public-api.ts | 15 +- repo-scripts/prune-dts/prune-dts.ts | 93 +- 18 files changed, 2096 insertions(+), 1937 deletions(-) create mode 100644 common/api-review/firestore-pipelines.api.md create mode 100644 packages/firebase/firestore/pipelines/index.ts create mode 100644 packages/firebase/firestore/pipelines/package.json create mode 100644 packages/firestore/pipelines/package.json create mode 100644 packages/firestore/src/all_packages.ts create mode 100644 packages/firestore/src/pipelines.node.ts create mode 100644 packages/firestore/src/pipelines.rn.ts create mode 100644 packages/firestore/src/pipelines.ts diff --git a/common/api-review/firestore-pipelines.api.md b/common/api-review/firestore-pipelines.api.md new file mode 100644 index 00000000000..b9023a41300 --- /dev/null +++ b/common/api-review/firestore-pipelines.api.md @@ -0,0 +1,1751 @@ +## API Report File for "@firebase/firestore-pipelines" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { FirebaseApp } from '@firebase/app'; + +// @beta +export interface Accumulator { + // (undocumented) + accumulator: true; +} + +// @beta +export type AccumulatorTarget = ExprWithAlias; + +// @beta (undocumented) +export class Add extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function add(left: Constant, right: Constant): Add; + +// @beta +export function add(left: Constant, right: any): Add; + +// @beta +export function add(left: string, right: Constant): Add; + +// @beta +export function add(left: string, right: any): Add; + +// @beta (undocumented) +export class AddFields implements Stage { + constructor(fields: Map); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class Aggregate implements Stage { + constructor(accumulators: Map, groups: Map); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class And extends FirestoreFunction implements FilterCondition { + constructor(conditions: FilterExpr[]); + // (undocumented) + filterable: true; +} + +// @beta +export function andFunction(left: FilterExpr, ...right: FilterExpr[]): And; + +// @beta (undocumented) +export class ArrayConcat extends FirestoreFunction { + constructor(array: Constant, elements: Constant[]); + } + +// @beta +export function arrayConcat(array: Constant, elements: Constant[]): ArrayConcat; + +// @beta +export function arrayConcat(array: Constant, elements: any[]): ArrayConcat; + +// @beta +export function arrayConcat(array: string, elements: Constant[]): ArrayConcat; + +// @beta +export function arrayConcat(array: string, elements: any[]): ArrayConcat; + +// @beta (undocumented) +export class ArrayContains extends FirestoreFunction implements FilterCondition { + constructor(array: Constant, element: Constant); + // (undocumented) + filterable: true; +} + +// @beta +export function arrayContains(array: Constant, element: Constant): ArrayContains; + +// @beta +export function arrayContains(array: Constant, element: any): ArrayContains; + +// @beta +export function arrayContains(array: string, element: Constant): ArrayContains; + +// @beta +export function arrayContains(array: string, element: any): ArrayContains; + +// @beta (undocumented) +export class ArrayContainsAll extends FirestoreFunction implements FilterCondition { + constructor(array: Constant, values: Constant[]); + // (undocumented) + filterable: true; + } + +// @beta +export function arrayContainsAll(array: Constant, values: Constant[]): ArrayContainsAll; + +// @beta +export function arrayContainsAll(array: Constant, values: any[]): ArrayContainsAll; + +// @beta +export function arrayContainsAll(array: string, values: Constant[]): ArrayContainsAll; + +// @beta +export function arrayContainsAll(array: string, values: any[]): ArrayContainsAll; + +// @beta (undocumented) +export class ArrayContainsAny extends FirestoreFunction implements FilterCondition { + constructor(array: Constant, values: Constant[]); + // (undocumented) + filterable: true; + } + +// @beta +export function arrayContainsAny(array: Constant, values: Constant[]): ArrayContainsAny; + +// @beta +export function arrayContainsAny(array: Constant, values: any[]): ArrayContainsAny; + +// @beta +export function arrayContainsAny(array: string, values: Constant[]): ArrayContainsAny; + +// @beta +export function arrayContainsAny(array: string, values: any[]): ArrayContainsAny; + +// @beta (undocumented) +export class ArrayElement extends FirestoreFunction { + constructor(); +} + +// @beta (undocumented) +export class ArrayLength extends FirestoreFunction { + constructor(array: Constant); + } + +// @beta +export function arrayLength(array: Constant): ArrayLength; + +// @beta (undocumented) +export class ArrayReverse extends FirestoreFunction { + constructor(array: Constant); + } + +// @beta +export function ascending(expr: Constant): Ordering; + +// @beta (undocumented) +export class Avg extends FirestoreFunction implements Accumulator { + constructor(value: Constant, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function avgFunction(value: Constant): Avg; + +// @beta +export function avgFunction(value: string): Avg; + +// @beta (undocumented) +export class ByteLength extends FirestoreFunction { + constructor(value: Constant); + } + +// @beta +export function byteLength(expr: Constant): ByteLength; + +// @beta +export function byteLength(field: string): ByteLength; + +// @beta (undocumented) +export class CharLength extends FirestoreFunction { + constructor(value: Constant); + } + +// @beta +export function charLength(field: string): CharLength; + +// @beta +export function charLength(expr: Constant): CharLength; + +// @beta (undocumented) +export class CollectionGroupSource implements Stage { + constructor(collectionId: string); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class CollectionSource implements Stage { + constructor(collectionPath: string); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class Cond extends FirestoreFunction implements FilterCondition { + constructor(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function cond(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant): Cond; + +// @beta +export class Constant { + add(other: Constant): Add; + add(other: any): Add; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): NotEqAny; + // (undocumented) + notEqAny(...others: any[]): NotEqAny; + static of(value: number): Constant; + static of(value: string): Constant; + static of(value: boolean): Constant; + static of(value: null): Constant; + static of(value: undefined): Constant; + // Warning: (ae-forgotten-export) The symbol "GeoPoint" needs to be exported by the entry point pipelines.d.ts + static of(value: GeoPoint): Constant; + // Warning: (ae-forgotten-export) The symbol "Timestamp" needs to be exported by the entry point pipelines.d.ts + static of(value: Timestamp): Constant; + static of(value: Date): Constant; + static of(value: Uint8Array): Constant; + // Warning: (ae-forgotten-export) The symbol "DocumentReference" needs to be exported by the entry point pipelines.d.ts + static of(value: DocumentReference): Constant; + static of(value: any[]): Constant; + static of(value: Map): Constant; + // Warning: (ae-forgotten-export) The symbol "VectorValue" needs to be exported by the entry point pipelines.d.ts + static of(value: VectorValue): Constant; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + static vector(value: number[] | VectorValue): Constant; + vectorLength(): VectorLength; +} + +// @beta (undocumented) +export class CosineDistance extends FirestoreFunction { + constructor(vector1: Constant, vector2: Constant); + } + +// @beta +export function cosineDistance(expr: string, other: number[]): CosineDistance; + +// @beta +export function cosineDistance(expr: string, other: VectorValue): CosineDistance; + +// @beta +export function cosineDistance(expr: string, other: Constant): CosineDistance; + +// @beta +export function cosineDistance(expr: Constant, other: number[]): CosineDistance; + +// @beta +export function cosineDistance(expr: Constant, other: VectorValue): CosineDistance; + +// @beta +export function cosineDistance(expr: Constant, other: Constant): CosineDistance; + +// @beta (undocumented) +export class Count extends FirestoreFunction implements Accumulator { + constructor(value: Constant | undefined, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function countAll(): Count; + +// @beta +export function countFunction(value: Constant): Count; + +// Warning: (ae-incompatible-release-tags) The symbol "countFunction" is marked as @public, but its signature references "Count" which is marked as @beta +// +// @public +export function countFunction(value: string): Count; + +// @beta (undocumented) +export class DatabaseSource implements Stage { + // (undocumented) + name: string; +} + +// @beta +export function descending(expr: Constant): Ordering; + +// @beta (undocumented) +export class Distinct implements Stage { + constructor(groups: Map); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class Divide extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function divide(left: Constant, right: Constant): Divide; + +// @beta +export function divide(left: Constant, right: any): Divide; + +// @beta +export function divide(left: string, right: Constant): Divide; + +// @beta +export function divide(left: string, right: any): Divide; + +// @beta (undocumented) +export class DocumentsSource implements Stage { + constructor(docPaths: string[]); + // (undocumented) + name: string; + // (undocumented) + static of(refs: DocumentReference[]): DocumentsSource; +} + +// @beta (undocumented) +export class DotProduct extends FirestoreFunction { + constructor(vector1: Constant, vector2: Constant); + } + +// @beta +export function dotProduct(expr: string, other: number[]): DotProduct; + +// @beta +export function dotProduct(expr: string, other: VectorValue): DotProduct; + +// @beta +export function dotProduct(expr: string, other: Constant): DotProduct; + +// @beta +export function dotProduct(expr: Constant, other: number[]): DotProduct; + +// @beta +export function dotProduct(expr: Constant, other: VectorValue): DotProduct; + +// @beta +export function dotProduct(expr: Constant, other: Constant): DotProduct; + +// @beta (undocumented) +export class EndsWith extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, suffix: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function endsWith(expr: string, suffix: string): EndsWith; + +// @beta +export function endsWith(expr: string, suffix: Constant): EndsWith; + +// @beta +export function endsWith(expr: Constant, suffix: string): EndsWith; + +// @beta +export function endsWith(expr: Constant, suffix: Constant): EndsWith; + +// @beta (undocumented) +export class Eq extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function eq(left: Constant, right: Constant): Eq; + +// @beta +export function eq(left: Constant, right: any): Eq; + +// @beta +export function eq(left: string, right: Constant): Eq; + +// @beta +export function eq(left: string, right: any): Eq; + +// @beta (undocumented) +export class EqAny extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, others: Constant[]); + // (undocumented) + filterable: true; + } + +// @beta +export function eqAny(element: Constant, others: Constant[]): EqAny; + +// @beta +export function eqAny(element: Constant, others: any[]): EqAny; + +// @beta +export function eqAny(element: string, others: Constant[]): EqAny; + +// @beta +export function eqAny(element: string, others: any[]): EqAny; + +// @beta (undocumented) +export class EuclideanDistance extends FirestoreFunction { + constructor(vector1: Constant, vector2: Constant); + } + +// @beta +export function euclideanDistance(expr: string, other: number[]): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: string, other: VectorValue): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: string, other: Constant): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: Constant, other: number[]): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: Constant, other: VectorValue): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: Constant, other: Constant): EuclideanDistance; + +// Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta +// +// @public (undocumented) +export function execute(pipeline: Pipeline): Promise>>; + +// @beta (undocumented) +export class Exists extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant); + // (undocumented) + filterable: true; +} + +// @beta +export function exists(value: Constant): Exists; + +// @beta +export function exists(field: string): Exists; + +// @beta +export type ExprType = 'Field' | 'Constant' | 'Function' | 'ListOfExprs' | 'ExprWithAlias'; + +// @beta (undocumented) +export class ExprWithAlias implements Selectable { + constructor(expr: T, alias: string); + add(other: Constant): Add; + add(other: any): Add; + // (undocumented) + alias: string; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + expr: T; + // (undocumented) + exprType: ExprType; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): NotEqAny; + // (undocumented) + notEqAny(...others: any[]): NotEqAny; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + // (undocumented) + selectable: true; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + +// @beta +export class Field implements Selectable { + add(other: Constant): Add; + add(other: any): Add; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + // (undocumented) + fieldName(): string; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): NotEqAny; + // (undocumented) + notEqAny(...others: any[]): NotEqAny; + static of(name: string): Field; + // Warning: (ae-forgotten-export) The symbol "FieldPath" needs to be exported by the entry point pipelines.d.ts + // + // (undocumented) + static of(path: FieldPath): Field; + // (undocumented) + static of(pipeline: Pipeline, name: string): Field; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + // (undocumented) + selectable: true; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + +// @beta (undocumented) +export class Fields implements Selectable { + add(other: Constant): Add; + add(other: any): Add; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + // (undocumented) + fieldList(): Field[]; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): NotEqAny; + // (undocumented) + notEqAny(...others: any[]): NotEqAny; + // (undocumented) + static of(name: string, ...others: string[]): Fields; + // (undocumented) + static ofAll(): Fields; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + // (undocumented) + selectable: true; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + +// @beta +export interface FilterCondition { + // (undocumented) + filterable: true; +} + +// @beta +export type FilterExpr = Constant & FilterCondition; + +// @beta (undocumented) +export class FindNearest implements Stage { + // (undocumented) + name: string; +} + +// @beta (undocumented) +export interface FindNearestOptions { + // (undocumented) + distanceField?: string; + // (undocumented) + distanceMeasure: 'euclidean' | 'cosine' | 'dot_product'; + // (undocumented) + field: Field; + // (undocumented) + limit?: number; + // (undocumented) + vectorValue: VectorValue | number[]; +} + +// @beta +export class FirestoreFunction { + constructor(name: string, params: Constant[]); + add(other: Constant): Add; + add(other: any): Add; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): NotEqAny; + // (undocumented) + notEqAny(...others: any[]): NotEqAny; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + +// @beta +export function genericFunction(name: string, params: Constant[]): FirestoreFunction; + +// @beta (undocumented) +export class GenericStage implements Stage { + constructor(name: string, params: unknown[]); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class Gt extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function gt(left: Constant, right: Constant): Gt; + +// @beta +export function gt(left: Constant, right: any): Gt; + +// @beta +export function gt(left: string, right: Constant): Gt; + +// @beta +export function gt(left: string, right: any): Gt; + +// @beta (undocumented) +export class Gte extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function gte(left: Constant, right: Constant): Gte; + +// @beta +export function gte(left: Constant, right: any): Gte; + +// @beta +export function gte(left: string, right: Constant): Gte; + +// @beta +export function gte(left: string, right: any): Gte; + +// @beta (undocumented) +export class IsNan extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant); + // (undocumented) + filterable: true; +} + +// @beta +export function isNan(value: Constant): IsNan; + +// @beta +export function isNan(value: string): IsNan; + +// @beta (undocumented) +export class Like extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, pattern: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function like(left: string, pattern: string): Like; + +// @beta +export function like(left: string, pattern: Constant): Like; + +// @beta +export function like(left: Constant, pattern: string): Like; + +// @beta +export function like(left: Constant, pattern: Constant): Like; + +// @beta (undocumented) +export class Limit implements Stage { + constructor(limit: number); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class LogicalMaximum extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function logicalMaximum(left: Constant, right: Constant): LogicalMaximum; + +// @beta +export function logicalMaximum(left: Constant, right: any): LogicalMaximum; + +// @beta +export function logicalMaximum(left: string, right: Constant): LogicalMaximum; + +// @beta +export function logicalMaximum(left: string, right: any): LogicalMaximum; + +// @beta (undocumented) +export class LogicalMinimum extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function logicalMinimum(left: Constant, right: Constant): LogicalMinimum; + +// @beta +export function logicalMinimum(left: Constant, right: any): LogicalMinimum; + +// @beta +export function logicalMinimum(left: string, right: Constant): LogicalMinimum; + +// @beta +export function logicalMinimum(left: string, right: any): LogicalMinimum; + +// @beta (undocumented) +export class Lt extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function lt(left: Constant, right: Constant): Lt; + +// @beta +export function lt(left: Constant, right: any): Lt; + +// @beta +export function lt(left: string, right: Constant): Lt; + +// @beta +export function lt(left: string, right: any): Lt; + +// @beta (undocumented) +export class Lte extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function lte(left: Constant, right: Constant): Lte; + +// @beta +export function lte(left: Constant, right: any): Lte; + +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Constant" which is marked as @beta +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Lte" which is marked as @beta +// +// @public +export function lte(left: string, right: Constant): Lte; + +// @beta +export function lte(left: string, right: any): Lte; + +// @beta (undocumented) +export class MapGet extends FirestoreFunction { + constructor(map: Constant, name: string); +} + +// @beta +export function mapGet(mapField: string, subField: string): MapGet; + +// @beta +export function mapGet(mapExpr: Constant, subField: string): MapGet; + +// @beta (undocumented) +export class Maximum extends FirestoreFunction implements Accumulator { + constructor(value: Constant, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function maximum(value: Constant): Maximum; + +// @beta +export function maximum(value: string): Maximum; + +// @beta (undocumented) +export class Minimum extends FirestoreFunction implements Accumulator { + constructor(value: Constant, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function minimum(value: Constant): Minimum; + +// @beta +export function minimum(value: string): Minimum; + +// @beta (undocumented) +export class Mod extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function mod(left: Constant, right: Constant): Mod; + +// @beta +export function mod(left: Constant, right: any): Mod; + +// @beta +export function mod(left: string, right: Constant): Mod; + +// @beta +export function mod(left: string, right: any): Mod; + +// @beta (undocumented) +export class Multiply extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function multiply(left: Constant, right: Constant): Multiply; + +// @beta +export function multiply(left: Constant, right: any): Multiply; + +// @beta +export function multiply(left: string, right: Constant): Multiply; + +// @beta +export function multiply(left: string, right: any): Multiply; + +// @beta (undocumented) +export class Neq extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function neq(left: Constant, right: Constant): Neq; + +// @beta +export function neq(left: Constant, right: any): Neq; + +// @beta +export function neq(left: string, right: Constant): Neq; + +// @beta +export function neq(left: string, right: any): Neq; + +// @beta (undocumented) +export class Not extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant); + // (undocumented) + filterable: true; +} + +// @beta +export function not(filter: FilterExpr): Not; + +// @beta (undocumented) +export class NotEqAny extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, others: Constant[]); + // (undocumented) + filterable: true; + } + +// @beta +export function notEqAny(element: Constant, others: Constant[]): NotEqAny; + +// @beta +export function notEqAny(element: Constant, others: any[]): NotEqAny; + +// @beta +export function notEqAny(element: string, others: Constant[]): NotEqAny; + +// @beta +export function notEqAny(element: string, others: any[]): NotEqAny; + +// @beta (undocumented) +export class Offset implements Stage { + constructor(offset: number); + // (undocumented) + name: string; + } + +// @beta (undocumented) +export class Or extends FirestoreFunction implements FilterCondition { + constructor(conditions: FilterExpr[]); + // (undocumented) + filterable: true; +} + +// @beta +export class Ordering { + constructor(expr: Constant, direction: 'ascending' | 'descending'); + } + +// @beta +export function orFunction(left: FilterExpr, ...right: FilterExpr[]): Or; + +// Warning: (ae-forgotten-export) The symbol "DocumentData" needs to be exported by the entry point pipelines.d.ts +// +// @public (undocumented) +export class Pipeline { + /* Excluded from this release type: __constructor */ + /* Excluded from this release type: newPipeline */ + // Warning: (ae-incompatible-release-tags) The symbol "addFields" is marked as @public, but its signature references "Selectable" which is marked as @beta + addFields(...fields: Selectable[]): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta + aggregate(...accumulators: AccumulatorTarget[]): Pipeline; + aggregate(options: { accumulators: AccumulatorTarget[]; groups?: Array; }): Pipeline; + // (undocumented) + converter: any; + // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta + distinct(...groups: Array): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta + execute(): Promise>>; + // Warning: (ae-incompatible-release-tags) The symbol "findNearest" is marked as @public, but its signature references "FindNearestOptions" which is marked as @beta + // + // (undocumented) + findNearest(options: FindNearestOptions): Pipeline; + genericStage(name: string, params: any[]): Pipeline; + limit(limit: number): Pipeline; + offset(offset: number): Pipeline; + readUserData: any; + // Warning: (ae-incompatible-release-tags) The symbol "select" is marked as @public, but its signature references "Selectable" which is marked as @beta + select(...selections: Array): Pipeline; + // (undocumented) + selectablesToMap: any; + // Warning: (ae-incompatible-release-tags) The symbol "sort" is marked as @public, but its signature references "Ordering" which is marked as @beta + sort(...orderings: Ordering[]): Pipeline; + // (undocumented) + sort(options: { orderings: Ordering[]; }): Pipeline; + // (undocumented) + stages: any; + // (undocumented) + userDataReader: any; + // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "FilterCondition" which is marked as @beta + // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "Constant" which is marked as @beta + where(condition: FilterCondition & Constant): Pipeline; +} + +// Warning: (ae-forgotten-export) The symbol "Firestore" needs to be exported by the entry point pipelines.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "pipeline" is marked as @public, but its signature references "PipelineSource" which is marked as @beta +// +// @public +export function pipeline(firestore: Firestore): PipelineSource; + +// Warning: (ae-forgotten-export) The symbol "Query" needs to be exported by the entry point pipelines.d.ts +// +// @public +export function pipeline(query: Query): Pipeline; + +// @beta +export class PipelineResult { + /* Excluded from this release type: _ref */ + /* Excluded from this release type: _fields */ + /* Excluded from this release type: __constructor */ + get createTime(): Timestamp | undefined; + data(): AppModelType | undefined; + get executionTime(): Timestamp; + get(fieldPath: string | FieldPath): any; + get id(): string | undefined; + get ref(): DocumentReference | undefined; + get updateTime(): Timestamp | undefined; +} + +// @beta +export class PipelineSource { + /* Excluded from this release type: _db */ + /* Excluded from this release type: _userDataReader */ + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + /* Excluded from this release type: __constructor */ + // (undocumented) + collection(collectionPath: string): Pipeline; + // (undocumented) + collectionGroup(collectionId: string): Pipeline; + // (undocumented) + database(): Pipeline; + // (undocumented) + documents(docs: DocumentReference[]): Pipeline; +} + +// @beta (undocumented) +export class RegexContains extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, pattern: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function regexContains(left: string, pattern: string): RegexContains; + +// @beta +export function regexContains(left: string, pattern: Constant): RegexContains; + +// @beta +export function regexContains(left: Constant, pattern: string): RegexContains; + +// @beta +export function regexContains(left: Constant, pattern: Constant): RegexContains; + +// @beta (undocumented) +export class RegexMatch extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, pattern: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function regexMatch(left: string, pattern: string): RegexMatch; + +// @beta +export function regexMatch(left: string, pattern: Constant): RegexMatch; + +// @beta +export function regexMatch(left: Constant, pattern: string): RegexMatch; + +// @beta +export function regexMatch(left: Constant, pattern: Constant): RegexMatch; + +// @beta (undocumented) +export class ReplaceAll extends FirestoreFunction { + constructor(value: Constant, find: Constant, replace: Constant); + } + +// @beta +export function replaceAll(value: Constant, find: string, replace: string): ReplaceAll; + +// @beta +export function replaceAll(value: Constant, find: Constant, replace: Constant): ReplaceAll; + +// @beta +export function replaceAll(field: string, find: string, replace: string): ReplaceAll; + +// @beta (undocumented) +export class ReplaceFirst extends FirestoreFunction { + constructor(value: Constant, find: Constant, replace: Constant); + } + +// @beta +export function replaceFirst(value: Constant, find: string, replace: string): ReplaceFirst; + +// @beta +export function replaceFirst(value: Constant, find: Constant, replace: Constant): ReplaceFirst; + +// @beta +export function replaceFirst(field: string, find: string, replace: string): ReplaceFirst; + +// @beta (undocumented) +export class Reverse extends FirestoreFunction { + constructor(value: Constant); + } + +// @beta +export function reverse(expr: Constant): Reverse; + +// @beta +export function reverse(field: string): Reverse; + +// @beta (undocumented) +export class Select implements Stage { + constructor(projections: Map); + // (undocumented) + name: string; + } + +// @beta +export interface Selectable { + // (undocumented) + selectable: true; +} + +// @beta +export type SelectableExpr = Constant & Selectable; + +// @beta (undocumented) +export class Sort implements Stage { + constructor(orders: Ordering[]); + // (undocumented) + name: string; + } + +// @beta (undocumented) +export interface Stage { + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class StartsWith extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, prefix: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function startsWith(expr: string, prefix: string): StartsWith; + +// @beta +export function startsWith(expr: string, prefix: Constant): StartsWith; + +// @beta +export function startsWith(expr: Constant, prefix: string): StartsWith; + +// @beta +export function startsWith(expr: Constant, prefix: Constant): StartsWith; + +// @beta (undocumented) +export class StrConcat extends FirestoreFunction { + constructor(first: Constant, rest: Constant[]); + } + +// @beta +export function strConcat(first: string, ...elements: Array): StrConcat; + +// @beta +export function strConcat(first: Constant, ...elements: Array): StrConcat; + +// @beta (undocumented) +export class StrContains extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, substring: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function strContains(left: string, substring: string): StrContains; + +// @beta +export function strContains(left: string, substring: Constant): StrContains; + +// @beta +export function strContains(left: Constant, substring: string): StrContains; + +// @beta +export function strContains(left: Constant, substring: Constant): StrContains; + +// @beta (undocumented) +export class Subtract extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function subtract(left: Constant, right: Constant): Subtract; + +// @beta +export function subtract(left: Constant, right: any): Subtract; + +// @beta +export function subtract(left: string, right: Constant): Subtract; + +// @beta +export function subtract(left: string, right: any): Subtract; + +// @beta (undocumented) +export class Sum extends FirestoreFunction implements Accumulator { + constructor(value: Constant, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function sumFunction(value: Constant): Sum; + +// @beta +export function sumFunction(value: string): Sum; + +// @beta (undocumented) +export class TimestampAdd extends FirestoreFunction { + constructor(timestamp: Constant, unit: Constant, amount: Constant); + } + +// @beta +export function timestampAdd(timestamp: Constant, unit: Constant, amount: Constant): TimestampAdd; + +// @beta +export function timestampAdd(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + +// @beta +export function timestampAdd(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + +// @beta (undocumented) +export class TimestampSub extends FirestoreFunction { + constructor(timestamp: Constant, unit: Constant, amount: Constant); + } + +// @beta +export function timestampSub(timestamp: Constant, unit: Constant, amount: Constant): TimestampSub; + +// @beta +export function timestampSub(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + +// @beta +export function timestampSub(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + +// @beta (undocumented) +export class TimestampToUnixMicros extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function timestampToUnixMicros(expr: Constant): TimestampToUnixMicros; + +// @beta +export function timestampToUnixMicros(field: string): TimestampToUnixMicros; + +// @beta (undocumented) +export class TimestampToUnixMillis extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function timestampToUnixMillis(expr: Constant): TimestampToUnixMillis; + +// @beta +export function timestampToUnixMillis(field: string): TimestampToUnixMillis; + +// @beta (undocumented) +export class TimestampToUnixSeconds extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function timestampToUnixSeconds(expr: Constant): TimestampToUnixSeconds; + +// @beta +export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; + +// @beta (undocumented) +export class ToLower extends FirestoreFunction { + constructor(expr: Constant); + } + +// @beta +export function toLower(expr: string): ToLower; + +// @beta +export function toLower(expr: Constant): ToLower; + +// @beta (undocumented) +export class ToUpper extends FirestoreFunction { + constructor(expr: Constant); + } + +// @beta +export function toUpper(expr: string): ToUpper; + +// @beta +export function toUpper(expr: Constant): ToUpper; + +// @beta (undocumented) +export class Trim extends FirestoreFunction { + constructor(expr: Constant); + } + +// @beta +export function trim(expr: string): Trim; + +// @beta +export function trim(expr: Constant): Trim; + +// @beta (undocumented) +export class UnixMicrosToTimestamp extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function unixMicrosToTimestamp(expr: Constant): UnixMicrosToTimestamp; + +// @beta +export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; + +// @beta (undocumented) +export class UnixMillisToTimestamp extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function unixMillisToTimestamp(expr: Constant): UnixMillisToTimestamp; + +// @beta +export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; + +// @beta (undocumented) +export class UnixSecondsToTimestamp extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function unixSecondsToTimestamp(expr: Constant): UnixSecondsToTimestamp; + +// @beta +export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; + +// @public (undocumented) +export function useFluentPipelines(): void; + +// @beta (undocumented) +export class VectorLength extends FirestoreFunction { + constructor(value: Constant); + } + +// @beta +export function vectorLength(expr: Constant): VectorLength; + +// @beta +export function vectorLength(field: string): VectorLength; + +// @beta (undocumented) +export class Where implements Stage { + constructor(condition: FilterCondition & Constant); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class Xor extends FirestoreFunction implements FilterCondition { + constructor(conditions: FilterExpr[]); + // (undocumented) + filterable: true; +} + +// @beta +export function xor(left: FilterExpr, ...right: FilterExpr[]): Xor; + + +// Warnings were encountered during analysis: +// +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:8193:26 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:8193:61 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:8220:21 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta + +``` diff --git a/common/api-review/firestore.api.md b/common/api-review/firestore.api.md index 270c71fe955..34b56b97f21 100644 --- a/common/api-review/firestore.api.md +++ b/common/api-review/firestore.api.md @@ -9,54 +9,14 @@ import { FirebaseApp } from '@firebase/app'; import { FirebaseError } from '@firebase/util'; import { LogLevelString as LogLevel } from '@firebase/logger'; -// @beta -export interface Accumulator { - // (undocumented) - accumulator: true; -} - -// @beta -export type AccumulatorTarget = ExprWithAlias; - -// @beta (undocumented) -export class Add extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } - -// @beta -export function add(left: Constant, right: Constant): Add; - -// @beta -export function add(left: Constant, right: any): Add; - -// @beta -export function add(left: string, right: Constant): Add; - -// @beta -export function add(left: string, right: any): Add; - // @public export function addDoc(reference: CollectionReference, data: WithFieldValue): Promise>; -// @beta (undocumented) -export class AddFields implements Stage { - constructor(fields: Map); - // (undocumented) - name: string; -} - // @public export type AddPrefixToKeys> = { [K in keyof T & string as `${Prefix}.${K}`]+?: string extends K ? any : T[K]; }; -// @beta (undocumented) -export class Aggregate implements Stage { - constructor(accumulators: Map, groups: Map); - // (undocumented) - name: string; -} - // @public export class AggregateField { readonly aggregateType: AggregateType; @@ -93,147 +53,18 @@ export type AggregateSpecData = { // @public export type AggregateType = 'count' | 'avg' | 'sum'; -// @beta (undocumented) -export class And extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterExpr[]); - // (undocumented) - filterable: true; -} - // @public export function and(...queryConstraints: QueryFilterConstraint[]): QueryCompositeFilterConstraint; -// @beta -export function andFunction(left: FilterExpr, ...right: FilterExpr[]): And; - -// @beta (undocumented) -export class ArrayConcat extends FirestoreFunction { - constructor(array: Constant, elements: Constant[]); - } - -// @beta -export function arrayConcat(array: Constant, elements: Constant[]): ArrayConcat; - -// @beta -export function arrayConcat(array: Constant, elements: any[]): ArrayConcat; - -// @beta -export function arrayConcat(array: string, elements: Constant[]): ArrayConcat; - -// @beta -export function arrayConcat(array: string, elements: any[]): ArrayConcat; - -// @beta (undocumented) -export class ArrayContains extends FirestoreFunction implements FilterCondition { - constructor(array: Constant, element: Constant); - // (undocumented) - filterable: true; -} - -// @beta -export function arrayContains(array: Constant, element: Constant): ArrayContains; - -// @beta -export function arrayContains(array: Constant, element: any): ArrayContains; - -// @beta -export function arrayContains(array: string, element: Constant): ArrayContains; - -// @beta -export function arrayContains(array: string, element: any): ArrayContains; - -// @beta (undocumented) -export class ArrayContainsAll extends FirestoreFunction implements FilterCondition { - constructor(array: Constant, values: Constant[]); - // (undocumented) - filterable: true; - } - -// @beta -export function arrayContainsAll(array: Constant, values: Constant[]): ArrayContainsAll; - -// @beta -export function arrayContainsAll(array: Constant, values: any[]): ArrayContainsAll; - -// @beta -export function arrayContainsAll(array: string, values: Constant[]): ArrayContainsAll; - -// @beta -export function arrayContainsAll(array: string, values: any[]): ArrayContainsAll; - -// @beta (undocumented) -export class ArrayContainsAny extends FirestoreFunction implements FilterCondition { - constructor(array: Constant, values: Constant[]); - // (undocumented) - filterable: true; - } - -// @beta -export function arrayContainsAny(array: Constant, values: Constant[]): ArrayContainsAny; - -// @beta -export function arrayContainsAny(array: Constant, values: any[]): ArrayContainsAny; - -// @beta -export function arrayContainsAny(array: string, values: Constant[]): ArrayContainsAny; - -// @beta -export function arrayContainsAny(array: string, values: any[]): ArrayContainsAny; - -// @beta (undocumented) -export class ArrayElement extends FirestoreFunction { - constructor(); -} - -// @beta (undocumented) -export class ArrayLength extends FirestoreFunction { - constructor(array: Constant); - } - -// @beta -export function arrayLength(array: Constant): ArrayLength; - // @public export function arrayRemove(...elements: unknown[]): FieldValue; -// @beta (undocumented) -export class ArrayReverse extends FirestoreFunction { - constructor(array: Constant); - } - // @public export function arrayUnion(...elements: unknown[]): FieldValue; -// @beta -export function ascending(expr: Constant): Ordering; - // @public export function average(field: string | FieldPath): AggregateField; -// @beta (undocumented) -export class Avg extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); - // (undocumented) - accumulator: true; - } - -// @beta -export function avgFunction(value: Constant): Avg; - -// @beta -export function avgFunction(value: string): Avg; - -// @beta (undocumented) -export class ByteLength extends FirestoreFunction { - constructor(value: Constant); - } - -// @beta -export function byteLength(expr: Constant): ByteLength; - -// @beta -export function byteLength(field: string): ByteLength; - // @public export class Bytes { static fromBase64String(base64: string): Bytes; @@ -247,17 +78,6 @@ export class Bytes { // @public export const CACHE_SIZE_UNLIMITED = -1; -// @beta (undocumented) -export class CharLength extends FirestoreFunction { - constructor(value: Constant); - } - -// @beta -export function charLength(field: string): CharLength; - -// @beta -export function charLength(expr: Constant): CharLength; - // @public export type ChildUpdateFields = V extends Record ? AddPrefixToKeys> : never; @@ -276,13 +96,6 @@ export function collection(refer // @public export function collectionGroup(firestore: Firestore, collectionId: string): Query; -// @beta (undocumented) -export class CollectionGroupSource implements Stage { - constructor(collectionId: string); - // (undocumented) - name: string; -} - // @public export class CollectionReference extends Query { get id(): string; @@ -293,196 +106,14 @@ export class CollectionReference; } -// @beta (undocumented) -export class CollectionSource implements Stage { - constructor(collectionPath: string); - // (undocumented) - name: string; -} - -// @beta (undocumented) -export class Cond extends FirestoreFunction implements FilterCondition { - constructor(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function cond(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant): Cond; - // @public export function connectFirestoreEmulator(firestore: Firestore, host: string, port: number, options?: { mockUserToken?: EmulatorMockTokenOptions | string; }): void; -// @beta -export class Constant { - add(other: Constant): Add; - add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): NotEqAny; - // (undocumented) - notEqAny(...others: any[]): NotEqAny; - static of(value: number): Constant; - static of(value: string): Constant; - static of(value: boolean): Constant; - static of(value: null): Constant; - static of(value: undefined): Constant; - static of(value: GeoPoint): Constant; - static of(value: Timestamp): Constant; - static of(value: Date): Constant; - static of(value: Uint8Array): Constant; - static of(value: DocumentReference): Constant; - static of(value: any[]): Constant; - static of(value: Map): Constant; - static of(value: VectorValue): Constant; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - static vector(value: number[] | VectorValue): Constant; - vectorLength(): VectorLength; -} - -// @beta (undocumented) -export class CosineDistance extends FirestoreFunction { - constructor(vector1: Constant, vector2: Constant); - } - -// @beta -export function cosineDistance(expr: string, other: number[]): CosineDistance; - -// @beta -export function cosineDistance(expr: string, other: VectorValue): CosineDistance; - -// @beta -export function cosineDistance(expr: string, other: Constant): CosineDistance; - -// @beta -export function cosineDistance(expr: Constant, other: number[]): CosineDistance; - -// @beta -export function cosineDistance(expr: Constant, other: VectorValue): CosineDistance; - -// @beta -export function cosineDistance(expr: Constant, other: Constant): CosineDistance; - -// @beta (undocumented) -export class Count extends FirestoreFunction implements Accumulator { - constructor(value: Constant | undefined, distinct: boolean); - // (undocumented) - accumulator: true; - } - // @public export function count(): AggregateField; -// @beta -export function countAll(): Count; - -// @beta -export function countFunction(value: Constant): Count; - -// Warning: (ae-incompatible-release-tags) The symbol "countFunction" is marked as @public, but its signature references "Count" which is marked as @beta -// -// @public -export function countFunction(value: string): Count; - -// @beta (undocumented) -export class DatabaseSource implements Stage { - // (undocumented) - name: string; -} - // @public export function deleteAllPersistentCacheIndexes(indexManager: PersistentCacheIndexManager): void; @@ -492,39 +123,12 @@ export function deleteDoc(refere // @public export function deleteField(): FieldValue; -// @beta -export function descending(expr: Constant): Ordering; - // @public export function disableNetwork(firestore: Firestore): Promise; // @public export function disablePersistentCacheIndexAutoCreation(indexManager: PersistentCacheIndexManager): void; -// @beta (undocumented) -export class Distinct implements Stage { - constructor(groups: Map); - // (undocumented) - name: string; -} - -// @beta (undocumented) -export class Divide extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } - -// @beta -export function divide(left: Constant, right: Constant): Divide; - -// @beta -export function divide(left: Constant, right: any): Divide; - -// @beta -export function divide(left: string, right: Constant): Divide; - -// @beta -export function divide(left: string, right: any): Divide; - // @public export function doc(firestore: Firestore, path: string, ...pathSegments: string[]): DocumentReference; @@ -576,38 +180,6 @@ export class DocumentSnapshot; } -// @beta (undocumented) -export class DocumentsSource implements Stage { - constructor(docPaths: string[]); - // (undocumented) - name: string; - // (undocumented) - static of(refs: DocumentReference[]): DocumentsSource; -} - -// @beta (undocumented) -export class DotProduct extends FirestoreFunction { - constructor(vector1: Constant, vector2: Constant); - } - -// @beta -export function dotProduct(expr: string, other: number[]): DotProduct; - -// @beta -export function dotProduct(expr: string, other: VectorValue): DotProduct; - -// @beta -export function dotProduct(expr: string, other: Constant): DotProduct; - -// @beta -export function dotProduct(expr: Constant, other: number[]): DotProduct; - -// @beta -export function dotProduct(expr: Constant, other: VectorValue): DotProduct; - -// @beta -export function dotProduct(expr: Constant, other: Constant): DotProduct; - export { EmulatorMockTokenOptions } // @public @deprecated @@ -634,488 +206,22 @@ export function endBefore(snapsh // @public export function endBefore(...fieldValues: unknown[]): QueryEndAtConstraint; -// @beta (undocumented) -export class EndsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, suffix: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function endsWith(expr: string, suffix: string): EndsWith; - -// @beta -export function endsWith(expr: string, suffix: Constant): EndsWith; - -// @beta -export function endsWith(expr: Constant, suffix: string): EndsWith; - -// @beta -export function endsWith(expr: Constant, suffix: Constant): EndsWith; - -// @beta (undocumented) -export class Eq extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function eq(left: Constant, right: Constant): Eq; - -// @beta -export function eq(left: Constant, right: any): Eq; - -// @beta -export function eq(left: string, right: Constant): Eq; - -// @beta -export function eq(left: string, right: any): Eq; - -// @beta (undocumented) -export class EqAny extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, others: Constant[]); - // (undocumented) - filterable: true; - } - -// @beta -export function eqAny(element: Constant, others: Constant[]): EqAny; - -// @beta -export function eqAny(element: Constant, others: any[]): EqAny; - -// @beta -export function eqAny(element: string, others: Constant[]): EqAny; - -// @beta -export function eqAny(element: string, others: any[]): EqAny; - -// @beta (undocumented) -export class EuclideanDistance extends FirestoreFunction { - constructor(vector1: Constant, vector2: Constant); - } - -// @beta -export function euclideanDistance(expr: string, other: number[]): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: string, other: VectorValue): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: string, other: Constant): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: Constant, other: number[]): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: Constant, other: VectorValue): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: Constant, other: Constant): EuclideanDistance; - -// Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta -// -// @public (undocumented) -export function execute(pipeline: Pipeline): Promise>>; - -// @beta (undocumented) -export class Exists extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant); - // (undocumented) - filterable: true; -} - -// @beta -export function exists(value: Constant): Exists; - -// @beta -export function exists(field: string): Exists; - // @public export interface ExperimentalLongPollingOptions { timeoutSeconds?: number; } -// @beta -export type ExprType = 'Field' | 'Constant' | 'Function' | 'ListOfExprs' | 'ExprWithAlias'; - -// @beta (undocumented) -export class ExprWithAlias implements Selectable { - constructor(expr: T, alias: string); - add(other: Constant): Add; - add(other: any): Add; - // (undocumented) - alias: string; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - expr: T; - // (undocumented) - exprType: ExprType; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): NotEqAny; - // (undocumented) - notEqAny(...others: any[]): NotEqAny; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; - // (undocumented) - selectable: true; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} - -// @beta -export class Field implements Selectable { - add(other: Constant): Add; - add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; - // (undocumented) - fieldName(): string; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): NotEqAny; - // (undocumented) - notEqAny(...others: any[]): NotEqAny; - static of(name: string): Field; - // (undocumented) - static of(path: FieldPath): Field; - // (undocumented) - static of(pipeline: Pipeline, name: string): Field; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; - // (undocumented) - selectable: true; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} - // @public export class FieldPath { constructor(...fieldNames: string[]); isEqual(other: FieldPath): boolean; } -// @beta (undocumented) -export class Fields implements Selectable { - add(other: Constant): Add; - add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; - // (undocumented) - fieldList(): Field[]; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): NotEqAny; - // (undocumented) - notEqAny(...others: any[]): NotEqAny; - // (undocumented) - static of(name: string, ...others: string[]): Fields; - // (undocumented) - static ofAll(): Fields; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; - // (undocumented) - selectable: true; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} - // @public export abstract class FieldValue { abstract isEqual(other: FieldValue): boolean; } -// @beta -export interface FilterCondition { - // (undocumented) - filterable: true; -} - -// @beta -export type FilterExpr = Constant & FilterCondition; - -// @beta (undocumented) -export class FindNearest implements Stage { - // (undocumented) - name: string; -} - -// @beta (undocumented) -export interface FindNearestOptions { - // (undocumented) - distanceField?: string; - // (undocumented) - distanceMeasure: 'euclidean' | 'cosine' | 'dot_product'; - // (undocumented) - field: Field; - // (undocumented) - limit?: number; - // (undocumented) - vectorValue: VectorValue | number[]; -} - // @public export class Firestore { get app(): FirebaseApp; @@ -1140,111 +246,6 @@ export class FirestoreError extends FirebaseError { // @public export type FirestoreErrorCode = 'cancelled' | 'unknown' | 'invalid-argument' | 'deadline-exceeded' | 'not-found' | 'already-exists' | 'permission-denied' | 'resource-exhausted' | 'failed-precondition' | 'aborted' | 'out-of-range' | 'unimplemented' | 'internal' | 'unavailable' | 'data-loss' | 'unauthenticated'; -// @beta -export class FirestoreFunction { - constructor(name: string, params: Constant[]); - add(other: Constant): Add; - add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): NotEqAny; - // (undocumented) - notEqAny(...others: any[]): NotEqAny; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} - // @public export type FirestoreLocalCache = MemoryLocalCache | PersistentLocalCache; @@ -1260,16 +261,6 @@ export interface FirestoreSettings { ssl?: boolean; } -// @beta -export function genericFunction(name: string, params: Constant[]): FirestoreFunction; - -// @beta (undocumented) -export class GenericStage implements Stage { - constructor(name: string, params: unknown[]); - // (undocumented) - name: string; -} - // @public export class GeoPoint { constructor(latitude: number, longitude: number); @@ -1323,44 +314,6 @@ export function getFirestore(app: FirebaseApp, databaseId: string): Firestore; // @public export function getPersistentCacheIndexManager(firestore: Firestore): PersistentCacheIndexManager | null; -// @beta (undocumented) -export class Gt extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function gt(left: Constant, right: Constant): Gt; - -// @beta -export function gt(left: Constant, right: any): Gt; - -// @beta -export function gt(left: string, right: Constant): Gt; - -// @beta -export function gt(left: string, right: any): Gt; - -// @beta (undocumented) -export class Gte extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function gte(left: Constant, right: Constant): Gte; - -// @beta -export function gte(left: Constant, right: any): Gte; - -// @beta -export function gte(left: string, right: Constant): Gte; - -// @beta -export function gte(left: string, right: any): Gte; - // @public export function increment(n: number): FieldValue; @@ -1391,45 +344,6 @@ export interface IndexField { // @public export function initializeFirestore(app: FirebaseApp, settings: FirestoreSettings, databaseId?: string): Firestore; -// @beta (undocumented) -export class IsNan extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant); - // (undocumented) - filterable: true; -} - -// @beta -export function isNan(value: Constant): IsNan; - -// @beta -export function isNan(value: string): IsNan; - -// @beta (undocumented) -export class Like extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, pattern: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function like(left: string, pattern: string): Like; - -// @beta -export function like(left: string, pattern: Constant): Like; - -// @beta -export function like(left: Constant, pattern: string): Like; - -// @beta -export function like(left: Constant, pattern: Constant): Like; - -// @beta (undocumented) -export class Limit implements Stage { - constructor(limit: number); - // (undocumented) - name: string; -} - // @public export function limit(limit: number): QueryLimitConstraint; @@ -1452,112 +366,13 @@ export class LoadBundleTask implements PromiseLike { // @public export interface LoadBundleTaskProgress { bytesLoaded: number; - documentsLoaded: number; - taskState: TaskState; - totalBytes: number; - totalDocuments: number; -} - -// @beta (undocumented) -export class LogicalMaximum extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } - -// @beta -export function logicalMaximum(left: Constant, right: Constant): LogicalMaximum; - -// @beta -export function logicalMaximum(left: Constant, right: any): LogicalMaximum; - -// @beta -export function logicalMaximum(left: string, right: Constant): LogicalMaximum; - -// @beta -export function logicalMaximum(left: string, right: any): LogicalMaximum; - -// @beta (undocumented) -export class LogicalMinimum extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } - -// @beta -export function logicalMinimum(left: Constant, right: Constant): LogicalMinimum; - -// @beta -export function logicalMinimum(left: Constant, right: any): LogicalMinimum; - -// @beta -export function logicalMinimum(left: string, right: Constant): LogicalMinimum; - -// @beta -export function logicalMinimum(left: string, right: any): LogicalMinimum; - -export { LogLevel } - -// @beta (undocumented) -export class Lt extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function lt(left: Constant, right: Constant): Lt; - -// @beta -export function lt(left: Constant, right: any): Lt; - -// @beta -export function lt(left: string, right: Constant): Lt; - -// @beta -export function lt(left: string, right: any): Lt; - -// @beta (undocumented) -export class Lte extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function lte(left: Constant, right: Constant): Lte; - -// @beta -export function lte(left: Constant, right: any): Lte; - -// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Constant" which is marked as @beta -// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Lte" which is marked as @beta -// -// @public -export function lte(left: string, right: Constant): Lte; - -// @beta -export function lte(left: string, right: any): Lte; - -// @beta (undocumented) -export class MapGet extends FirestoreFunction { - constructor(map: Constant, name: string); -} - -// @beta -export function mapGet(mapField: string, subField: string): MapGet; - -// @beta -export function mapGet(mapExpr: Constant, subField: string): MapGet; - -// @beta (undocumented) -export class Maximum extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); - // (undocumented) - accumulator: true; - } - -// @beta -export function maximum(value: Constant): Maximum; + documentsLoaded: number; + taskState: TaskState; + totalBytes: number; + totalDocuments: number; +} -// @beta -export function maximum(value: string): Maximum; +export { LogLevel } // @public export interface MemoryCacheSettings { @@ -1596,116 +411,14 @@ export function memoryLruGarbageCollector(settings?: { cacheSizeBytes?: number; }): MemoryLruGarbageCollector; -// @beta (undocumented) -export class Minimum extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); - // (undocumented) - accumulator: true; - } - -// @beta -export function minimum(value: Constant): Minimum; - -// @beta -export function minimum(value: string): Minimum; - -// @beta (undocumented) -export class Mod extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } - -// @beta -export function mod(left: Constant, right: Constant): Mod; - -// @beta -export function mod(left: Constant, right: any): Mod; - -// @beta -export function mod(left: string, right: Constant): Mod; - -// @beta -export function mod(left: string, right: any): Mod; - -// @beta (undocumented) -export class Multiply extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } - -// @beta -export function multiply(left: Constant, right: Constant): Multiply; - -// @beta -export function multiply(left: Constant, right: any): Multiply; - -// @beta -export function multiply(left: string, right: Constant): Multiply; - -// @beta -export function multiply(left: string, right: any): Multiply; - // @public export function namedQuery(firestore: Firestore, name: string): Promise; -// @beta (undocumented) -export class Neq extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function neq(left: Constant, right: Constant): Neq; - -// @beta -export function neq(left: Constant, right: any): Neq; - -// @beta -export function neq(left: string, right: Constant): Neq; - -// @beta -export function neq(left: string, right: any): Neq; - // @public export type NestedUpdateFields> = UnionToIntersection<{ [K in keyof T & string]: ChildUpdateFields; }[keyof T & string]>; -// @beta (undocumented) -export class Not extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant); - // (undocumented) - filterable: true; -} - -// @beta -export function not(filter: FilterExpr): Not; - -// @beta (undocumented) -export class NotEqAny extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, others: Constant[]); - // (undocumented) - filterable: true; - } - -// @beta -export function notEqAny(element: Constant, others: Constant[]): NotEqAny; - -// @beta -export function notEqAny(element: Constant, others: any[]): NotEqAny; - -// @beta -export function notEqAny(element: string, others: Constant[]): NotEqAny; - -// @beta -export function notEqAny(element: string, others: any[]): NotEqAny; - -// @beta (undocumented) -export class Offset implements Stage { - constructor(offset: number); - // (undocumented) - name: string; - } - // @public export function onSnapshot(reference: DocumentReference, observer: { next?: (snapshot: DocumentSnapshot) => void; @@ -1756,13 +469,6 @@ export function onSnapshotsInSync(firestore: Firestore, observer: { // @public export function onSnapshotsInSync(firestore: Firestore, onSync: () => void): Unsubscribe; -// @beta (undocumented) -export class Or extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterExpr[]); - // (undocumented) - filterable: true; -} - // @public export function or(...queryConstraints: QueryFilterConstraint[]): QueryCompositeFilterConstraint; @@ -1772,14 +478,6 @@ export function orderBy(fieldPath: string | FieldPath, directionStr?: OrderByDir // @public export type OrderByDirection = 'desc' | 'asc'; -// @beta -export class Ordering { - constructor(expr: Constant, direction: 'ascending' | 'descending'); - } - -// @beta -export function orFunction(left: FilterExpr, ...right: FilterExpr[]): Or; - // @public export type PartialWithFieldValue = Partial | (T extends Primitive ? T : T extends {} ? { [K in keyof T]?: PartialWithFieldValue | FieldValue; @@ -1836,85 +534,6 @@ export interface PersistentSingleTabManagerSettings { // @public export type PersistentTabManager = PersistentSingleTabManager | PersistentMultipleTabManager; -// @public (undocumented) -export class Pipeline { - /* Excluded from this release type: __constructor */ - /* Excluded from this release type: newPipeline */ - // Warning: (ae-incompatible-release-tags) The symbol "addFields" is marked as @public, but its signature references "Selectable" which is marked as @beta - addFields(...fields: Selectable[]): Pipeline; - // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta - aggregate(...accumulators: AccumulatorTarget[]): Pipeline; - aggregate(options: { accumulators: AccumulatorTarget[]; groups?: Array; }): Pipeline; - // (undocumented) - converter: any; - // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta - distinct(...groups: Array): Pipeline; - // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta - execute(): Promise>>; - // Warning: (ae-incompatible-release-tags) The symbol "findNearest" is marked as @public, but its signature references "FindNearestOptions" which is marked as @beta - // - // (undocumented) - findNearest(options: FindNearestOptions): Pipeline; - genericStage(name: string, params: any[]): Pipeline; - limit(limit: number): Pipeline; - offset(offset: number): Pipeline; - readUserData: any; - // Warning: (ae-incompatible-release-tags) The symbol "select" is marked as @public, but its signature references "Selectable" which is marked as @beta - select(...selections: Array): Pipeline; - // (undocumented) - selectablesToMap: any; - // Warning: (ae-incompatible-release-tags) The symbol "sort" is marked as @public, but its signature references "Ordering" which is marked as @beta - sort(...orderings: Ordering[]): Pipeline; - // (undocumented) - sort(options: { orderings: Ordering[]; }): Pipeline; - // (undocumented) - stages: any; - // (undocumented) - userDataReader: any; - // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "FilterCondition" which is marked as @beta - // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "Constant" which is marked as @beta - where(condition: FilterCondition & Constant): Pipeline; -} - -// Warning: (ae-incompatible-release-tags) The symbol "pipeline" is marked as @public, but its signature references "PipelineSource" which is marked as @beta -// -// @public -export function pipeline(firestore: Firestore): PipelineSource; - -// @public -export function pipeline(query: Query): Pipeline; - -// @beta -export class PipelineResult { - /* Excluded from this release type: _ref */ - /* Excluded from this release type: _fields */ - /* Excluded from this release type: __constructor */ - get createTime(): Timestamp | undefined; - data(): AppModelType | undefined; - get executionTime(): Timestamp; - get(fieldPath: string | FieldPath): any; - get id(): string | undefined; - get ref(): DocumentReference | undefined; - get updateTime(): Timestamp | undefined; -} - -// @beta -export class PipelineSource { - /* Excluded from this release type: _db */ - /* Excluded from this release type: _userDataReader */ - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - /* Excluded from this release type: __constructor */ - // (undocumented) - collection(collectionPath: string): Pipeline; - // (undocumented) - collectionGroup(collectionId: string): Pipeline; - // (undocumented) - database(): Pipeline; - // (undocumented) - documents(docs: DocumentReference[]): Pipeline; -} - // @public export type Primitive = string | number | boolean | undefined | null; @@ -2001,102 +620,9 @@ export class QueryStartAtConstraint extends QueryConstraint { // @public export function refEqual(left: DocumentReference | CollectionReference, right: DocumentReference | CollectionReference): boolean; -// @beta (undocumented) -export class RegexContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, pattern: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function regexContains(left: string, pattern: string): RegexContains; - -// @beta -export function regexContains(left: string, pattern: Constant): RegexContains; - -// @beta -export function regexContains(left: Constant, pattern: string): RegexContains; - -// @beta -export function regexContains(left: Constant, pattern: Constant): RegexContains; - -// @beta (undocumented) -export class RegexMatch extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, pattern: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function regexMatch(left: string, pattern: string): RegexMatch; - -// @beta -export function regexMatch(left: string, pattern: Constant): RegexMatch; - -// @beta -export function regexMatch(left: Constant, pattern: string): RegexMatch; - -// @beta -export function regexMatch(left: Constant, pattern: Constant): RegexMatch; - -// @beta (undocumented) -export class ReplaceAll extends FirestoreFunction { - constructor(value: Constant, find: Constant, replace: Constant); - } - -// @beta -export function replaceAll(value: Constant, find: string, replace: string): ReplaceAll; - -// @beta -export function replaceAll(value: Constant, find: Constant, replace: Constant): ReplaceAll; - -// @beta -export function replaceAll(field: string, find: string, replace: string): ReplaceAll; - -// @beta (undocumented) -export class ReplaceFirst extends FirestoreFunction { - constructor(value: Constant, find: Constant, replace: Constant); - } - -// @beta -export function replaceFirst(value: Constant, find: string, replace: string): ReplaceFirst; - -// @beta -export function replaceFirst(value: Constant, find: Constant, replace: Constant): ReplaceFirst; - -// @beta -export function replaceFirst(field: string, find: string, replace: string): ReplaceFirst; - -// @beta (undocumented) -export class Reverse extends FirestoreFunction { - constructor(value: Constant); - } - -// @beta -export function reverse(expr: Constant): Reverse; - -// @beta -export function reverse(field: string): Reverse; - // @public export function runTransaction(firestore: Firestore, updateFunction: (transaction: Transaction) => Promise, options?: TransactionOptions): Promise; -// @beta (undocumented) -export class Select implements Stage { - constructor(projections: Map); - // (undocumented) - name: string; - } - -// @beta -export interface Selectable { - // (undocumented) - selectable: true; -} - -// @beta -export type SelectableExpr = Constant & Selectable; - // @public export function serverTimestamp(): FieldValue; @@ -2143,19 +669,6 @@ export interface SnapshotOptions { readonly serverTimestamps?: 'estimate' | 'previous' | 'none'; } -// @beta (undocumented) -export class Sort implements Stage { - constructor(orders: Ordering[]); - // (undocumented) - name: string; - } - -// @beta (undocumented) -export interface Stage { - // (undocumented) - name: string; -} - // @public export function startAfter(snapshot: DocumentSnapshot): QueryStartAtConstraint; @@ -2168,88 +681,9 @@ export function startAt(snapshot // @public export function startAt(...fieldValues: unknown[]): QueryStartAtConstraint; -// @beta (undocumented) -export class StartsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, prefix: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function startsWith(expr: string, prefix: string): StartsWith; - -// @beta -export function startsWith(expr: string, prefix: Constant): StartsWith; - -// @beta -export function startsWith(expr: Constant, prefix: string): StartsWith; - -// @beta -export function startsWith(expr: Constant, prefix: Constant): StartsWith; - -// @beta (undocumented) -export class StrConcat extends FirestoreFunction { - constructor(first: Constant, rest: Constant[]); - } - -// @beta -export function strConcat(first: string, ...elements: Array): StrConcat; - -// @beta -export function strConcat(first: Constant, ...elements: Array): StrConcat; - -// @beta (undocumented) -export class StrContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, substring: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function strContains(left: string, substring: string): StrContains; - -// @beta -export function strContains(left: string, substring: Constant): StrContains; - -// @beta -export function strContains(left: Constant, substring: string): StrContains; - -// @beta -export function strContains(left: Constant, substring: Constant): StrContains; - -// @beta (undocumented) -export class Subtract extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } - -// @beta -export function subtract(left: Constant, right: Constant): Subtract; - -// @beta -export function subtract(left: Constant, right: any): Subtract; - -// @beta -export function subtract(left: string, right: Constant): Subtract; - -// @beta -export function subtract(left: string, right: any): Subtract; - -// @beta (undocumented) -export class Sum extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); - // (undocumented) - accumulator: true; - } - // @public export function sum(field: string | FieldPath): AggregateField; -// @beta -export function sumFunction(value: Constant): Sum; - -// @beta -export function sumFunction(value: string): Sum; - // @public export type TaskState = 'Error' | 'Running' | 'Success'; @@ -2277,89 +711,6 @@ export class Timestamp { valueOf(): string; } -// @beta (undocumented) -export class TimestampAdd extends FirestoreFunction { - constructor(timestamp: Constant, unit: Constant, amount: Constant); - } - -// @beta -export function timestampAdd(timestamp: Constant, unit: Constant, amount: Constant): TimestampAdd; - -// @beta -export function timestampAdd(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - -// @beta -export function timestampAdd(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - -// @beta (undocumented) -export class TimestampSub extends FirestoreFunction { - constructor(timestamp: Constant, unit: Constant, amount: Constant); - } - -// @beta -export function timestampSub(timestamp: Constant, unit: Constant, amount: Constant): TimestampSub; - -// @beta -export function timestampSub(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - -// @beta -export function timestampSub(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - -// @beta (undocumented) -export class TimestampToUnixMicros extends FirestoreFunction { - constructor(input: Constant); - } - -// @beta -export function timestampToUnixMicros(expr: Constant): TimestampToUnixMicros; - -// @beta -export function timestampToUnixMicros(field: string): TimestampToUnixMicros; - -// @beta (undocumented) -export class TimestampToUnixMillis extends FirestoreFunction { - constructor(input: Constant); - } - -// @beta -export function timestampToUnixMillis(expr: Constant): TimestampToUnixMillis; - -// @beta -export function timestampToUnixMillis(field: string): TimestampToUnixMillis; - -// @beta (undocumented) -export class TimestampToUnixSeconds extends FirestoreFunction { - constructor(input: Constant); - } - -// @beta -export function timestampToUnixSeconds(expr: Constant): TimestampToUnixSeconds; - -// @beta -export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; - -// @beta (undocumented) -export class ToLower extends FirestoreFunction { - constructor(expr: Constant); - } - -// @beta -export function toLower(expr: string): ToLower; - -// @beta -export function toLower(expr: Constant): ToLower; - -// @beta (undocumented) -export class ToUpper extends FirestoreFunction { - constructor(expr: Constant); - } - -// @beta -export function toUpper(expr: string): ToUpper; - -// @beta -export function toUpper(expr: Constant): ToUpper; - // @public export class Transaction { delete(documentRef: DocumentReference): this; @@ -2375,53 +726,9 @@ export interface TransactionOptions { readonly maxAttempts?: number; } -// @beta (undocumented) -export class Trim extends FirestoreFunction { - constructor(expr: Constant); - } - -// @beta -export function trim(expr: string): Trim; - -// @beta -export function trim(expr: Constant): Trim; - // @public export type UnionToIntersection = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never; -// @beta (undocumented) -export class UnixMicrosToTimestamp extends FirestoreFunction { - constructor(input: Constant); - } - -// @beta -export function unixMicrosToTimestamp(expr: Constant): UnixMicrosToTimestamp; - -// @beta -export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; - -// @beta (undocumented) -export class UnixMillisToTimestamp extends FirestoreFunction { - constructor(input: Constant); - } - -// @beta -export function unixMillisToTimestamp(expr: Constant): UnixMillisToTimestamp; - -// @beta -export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; - -// @beta (undocumented) -export class UnixSecondsToTimestamp extends FirestoreFunction { - constructor(input: Constant); - } - -// @beta -export function unixSecondsToTimestamp(expr: Constant): UnixSecondsToTimestamp; - -// @beta -export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; - // @public export interface Unsubscribe { (): void; @@ -2438,23 +745,9 @@ export function updateDoc(refere // @public export function updateDoc(reference: DocumentReference, field: string | FieldPath, value: unknown, ...moreFieldsAndValues: unknown[]): Promise; -// @public (undocumented) -export function useFluentPipelines(): void; - // @public export function vector(values?: number[]): VectorValue; -// @beta (undocumented) -export class VectorLength extends FirestoreFunction { - constructor(value: Constant); - } - -// @beta -export function vectorLength(expr: Constant): VectorLength; - -// @beta -export function vectorLength(field: string): VectorLength; - // @public export class VectorValue { /* Excluded from this release type: __constructor */ @@ -2465,13 +758,6 @@ export class VectorValue { // @public export function waitForPendingWrites(firestore: Firestore): Promise; -// @beta (undocumented) -export class Where implements Stage { - constructor(condition: FilterCondition & Constant); - // (undocumented) - name: string; -} - // @public export function where(fieldPath: string | FieldPath, opStr: WhereFilterOp, value: unknown): QueryFieldFilterConstraint; @@ -2496,21 +782,5 @@ export class WriteBatch { // @public export function writeBatch(firestore: Firestore): WriteBatch; -// @beta (undocumented) -export class Xor extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterExpr[]); - // (undocumented) - filterable: true; -} - -// @beta -export function xor(left: FilterExpr, ...right: FilterExpr[]): Xor; - - -// Warnings were encountered during analysis: -// -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/index.d.ts:10173:26 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/index.d.ts:10173:61 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/index.d.ts:10200:21 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta ``` diff --git a/packages/firebase/firestore/pipelines/index.ts b/packages/firebase/firestore/pipelines/index.ts new file mode 100644 index 00000000000..be062f16e96 --- /dev/null +++ b/packages/firebase/firestore/pipelines/index.ts @@ -0,0 +1,18 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from '@firebase/firestore/pipelines'; diff --git a/packages/firebase/firestore/pipelines/package.json b/packages/firebase/firestore/pipelines/package.json new file mode 100644 index 00000000000..e63cb928b0f --- /dev/null +++ b/packages/firebase/firestore/pipelines/package.json @@ -0,0 +1,7 @@ +{ + "name": "firebase/firestore/pipelines", + "main": "dist/pipelines.cjs.js", + "browser": "dist/esm/pipelines.esm.js", + "module": "dist/esm/pipelines.esm.js", + "typings": "dist/firestore/lite/pipelines.d.ts" +} diff --git a/packages/firebase/package.json b/packages/firebase/package.json index f716238f483..ee9fe733892 100644 --- a/packages/firebase/package.json +++ b/packages/firebase/package.json @@ -131,6 +131,18 @@ }, "default": "./firestore/dist/esm/index.esm.js" }, + "./firestore/pipelines": { + "types": "./firestore/dist/firestore/pipelines.d.ts", + "node": { + "require": "./firestore/dist/pipelines.cjs.js", + "import": "./firestore/dist/pipelines.mjs" + }, + "browser": { + "require": "./firestore/dist/pipelines.cjs.js", + "import": "./firestore/dist/esm/pipelines.esm.js" + }, + "default": "./firestore/dist/esm/pipelines.esm.js" + }, "./firestore/lite": { "types": "./firestore/lite/dist/firestore/lite/index.d.ts", "node": { diff --git a/packages/firestore/package.json b/packages/firestore/package.json index 896aaa55d6e..4a8d86241ee 100644 --- a/packages/firestore/package.json +++ b/packages/firestore/package.json @@ -47,12 +47,14 @@ "test:travis": "ts-node --compiler-options='{\"module\":\"commonjs\"}' ../../scripts/emulator-testing/firestore-test-runner.ts", "test:minified": "(cd ../../integration/firestore ; yarn test)", "trusted-type-check": "tsec -p tsconfig.json --noEmit", - "api-report:main": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/index.d.ts --rollupDts ./dist/private.d.ts --untrimmedRollupDts ./dist/internal.d.ts --publicDts ./dist/index.d.ts", - "api-report:lite": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite --packageRoot . --typescriptDts ./dist/firestore/lite/index.d.ts --rollupDts ./dist/lite/private.d.ts --untrimmedRollupDts ./dist/lite/internal.d.ts --publicDts ./dist/lite/index.d.ts", + "api-report:main": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/index.d.ts --rollupDts ./dist/private.d.ts --untrimmedRollupDts ./dist/internal.d.ts --publicDts ./dist/index.d.ts", + "api-report:all-packages": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/all_packages.d.ts --rollupDts ./dist/private.all_packages.d.ts --untrimmedRollupDts ./dist/internal.all_packages.d.ts --publicDts ./dist/all_packages.d.ts", + "api-report:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-pipelines --packageRoot . --typescriptDts ./dist/firestore/src/pipelines.d.ts --rollupDts ./dist/private.pipelines.d.ts --untrimmedRollupDts ./dist/internal.pipelines.d.ts --publicDts ./dist/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", + "api-report:lite": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite --packageRoot . --typescriptDts ./dist/firestore/lite/index.d.ts --rollupDts ./dist/lite/private.d.ts --untrimmedRollupDts ./dist/lite/internal.d.ts --publicDts ./dist/lite/index.d.ts", "api-report:api-json": "rm -rf temp && api-extractor run --local --verbose", - "api-report": "run-s --npm-path npm api-report:main api-report:lite && yarn api-report:api-json", + "api-report": "run-s --npm-path npm api-report:main api-report:pipelines api-report:lite && yarn api-report:api-json", "doc": "api-documenter markdown --input temp --output docs", - "typings:public": "node ../../scripts/build/use_typings.js ./dist/index.d.ts" + "typings:public": "node ../../scripts/build/use_typings.js ./dist/all-packages.d.ts" }, "exports": { ".": { @@ -76,11 +78,37 @@ }, "react-native": "./dist/lite/index.rn.esm2017.js", "browser": { - "require": "./dist/lite/index.cjs.js", + "require": "./dist/lite/index.browser.cjs.js", "import": "./dist/lite/index.browser.esm2017.js" }, "default": "./dist/lite/index.browser.esm2017.js" }, + "./lite/pipelines": { + "types": "./dist/lite/pipelines.d.ts", + "node": { + "require": "./dist/lite/pipelines.node.cjs.js", + "import": "./dist/lite/pipelines.node.mjs" + }, + "react-native": "./dist/lite/pipelines.rn.esm2017.js", + "browser": { + "require": "./dist/lite/pipelines.browser.cjs.js", + "import": "./dist/lite/pipelines.browser.esm2017.js" + }, + "default": "./dist/lite/pipelines.browser.esm2017.js" + }, + "./pipelines": { + "types": "./dist/pipelines.d.ts", + "node": { + "require": "./dist/pipelines.node.cjs.js", + "import": "./dist/pipelines.node.mjs" + }, + "react-native": "./dist/index.rn.esm2017.js", + "browser": { + "require": "./dist/pipelines.cjs.js", + "import": "./dist/pipelines.esm2017.js" + }, + "default": "./dist/pipelines.esm2017.js" + }, "./package.json": "./package.json" }, "main": "dist/index.node.cjs.js", @@ -135,7 +163,7 @@ "bugs": { "url": "https://github.com/firebase/firebase-js-sdk/issues" }, - "typings": "dist/firestore/src/index.d.ts", + "types": "dist/all_packages.d.ts", "nyc": { "extension": [ ".ts" diff --git a/packages/firestore/pipelines/package.json b/packages/firestore/pipelines/package.json new file mode 100644 index 00000000000..d0485164ad8 --- /dev/null +++ b/packages/firestore/pipelines/package.json @@ -0,0 +1,14 @@ +{ + "name": "@firebase/firestore/pipelines", + "description": "pipelines", + "main": "../dist/pipelines.node.cjs.js", + "main-esm": "../dist/pipelines.node.mjs", + "module": "../dist/pipelines.browser.esm2017.js", + "browser": "../dist/pipelines.browser.esm2017.js", + "react-native": "../dist/pipelines.rn.esm2017.js", + "typings": "../dist/pipelines.d.ts", + "private": true, + "engines": { + "node": ">=18.0.0" + } +} diff --git a/packages/firestore/rollup.config.js b/packages/firestore/rollup.config.js index c9604fee55d..395c2a88381 100644 --- a/packages/firestore/rollup.config.js +++ b/packages/firestore/rollup.config.js @@ -51,6 +51,7 @@ const browserPlugins = [ cacheDir: tmp.dirSync(), abortOnError: true, transformers: [util.removeAssertAndPrefixInternalTransformer] + //transformers: [util.removeAssertTransformer] }), json({ preferConst: true }), terser(util.manglePrivatePropertiesOptions) @@ -61,9 +62,11 @@ const allBuilds = [ // this is an intermediate build used to generate the actual esm and cjs builds // which add build target reporting { - input: './src/index.node.ts', + input: ['./src/index.node.ts', './src/pipelines.node.ts'], output: { - file: pkg['main-esm'], + dir: 'dist/intermediate', + entryFileNames: '[name].mjs', + chunkFileNames: 'common-[hash].node.mjs', format: 'es', sourcemap: true }, @@ -76,9 +79,11 @@ const allBuilds = [ }, // Node CJS build { - input: pkg['main-esm'], + input: ['dist/intermediate/index.node.mjs', 'dist/intermediate/pipelines.node.mjs'], output: { - file: pkg.main, + dir: 'dist/', + entryFileNames: '[name].cjs.js', + chunkFileNames: 'common-[hash].node.cjs.js', format: 'cjs', sourcemap: true }, @@ -103,9 +108,11 @@ const allBuilds = [ }, // Node ESM build with build target reporting { - input: pkg['main-esm'], + input: ['dist/intermediate/index.node.mjs', 'dist/intermediate/pipelines.node.mjs'], output: { - file: pkg['main-esm'], + dir: 'dist/', + entryFileNames: '[name].mjs', + chunkFileNames: 'common-[hash].node.mjs', format: 'es', sourcemap: true }, @@ -122,13 +129,18 @@ const allBuilds = [ // this is an intermediate build used to generate the actual esm and cjs builds // which add build target reporting { - input: './src/index.ts', + input: ['./src/index.ts', './src/pipelines.ts'], output: { - file: pkg.browser, + dir: 'dist/intermediate', + entryFileNames: '[name].js', + chunkFileNames: 'common-[hash].js', format: 'es', sourcemap: true }, - plugins: [alias(util.generateAliasConfig('browser')), ...browserPlugins], + plugins: [ + alias(util.generateAliasConfig('browser')), + ...browserPlugins + ], external: util.resolveBrowserExterns, treeshake: { moduleSideEffects: false @@ -136,10 +148,12 @@ const allBuilds = [ }, // Convert es2017 build to cjs { - input: pkg['browser'], + input: ['dist/intermediate/index.js', 'dist/intermediate/pipelines.js'], output: [ { - file: './dist/index.cjs.js', + dir: 'dist/', + entryFileNames: '[name].cjs.js', + chunkFileNames: 'common-[hash].cjs.js', format: 'cjs', sourcemap: true } @@ -155,10 +169,12 @@ const allBuilds = [ }, // es2017 build with build target reporting { - input: pkg['browser'], + input: ['dist/intermediate/index.js', 'dist/intermediate/pipelines.js'], output: [ { - file: pkg['browser'], + dir: 'dist/', + entryFileNames: '[name].esm2017.js', + chunkFileNames: 'common-[hash].esm2017.js', format: 'es', sourcemap: true } @@ -174,9 +190,11 @@ const allBuilds = [ }, // RN build { - input: './src/index.rn.ts', + input: ['./src/index.rn.ts', './src/pipelines.rn.ts',], output: { - file: pkg['react-native'], + dir: 'dist/', + entryFileNames: '[name].js', + chunkFileNames: 'common-[hash].rn.js', format: 'es', sourcemap: true }, diff --git a/packages/firestore/rollup.shared.js b/packages/firestore/rollup.shared.js index 1b33ddf0b1b..6443f917a7b 100644 --- a/packages/firestore/rollup.shared.js +++ b/packages/firestore/rollup.shared.js @@ -108,6 +108,10 @@ const publicIdentifiers = extractPublicIdentifiers(externsPaths); // manually add `_delegate` because we don't have typings for the compat package publicIdentifiers.add('_delegate'); + +console.log(`==== publicIdentifiers`) +console.log(JSON.stringify(publicIdentifiers, null, 2)) + /** * Transformers that remove calls to `debugAssert` and messages for 'fail` and * `hardAssert`. diff --git a/packages/firestore/src/all_packages.ts b/packages/firestore/src/all_packages.ts new file mode 100644 index 00000000000..82babeea706 --- /dev/null +++ b/packages/firestore/src/all_packages.ts @@ -0,0 +1,25 @@ +/** + * Cloud Firestore + * + * @packageDocumentation + */ + +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './api'; +export * from './api_pipelines'; diff --git a/packages/firestore/src/api.ts b/packages/firestore/src/api.ts index 7619312d2d5..14390d57b49 100644 --- a/packages/firestore/src/api.ts +++ b/packages/firestore/src/api.ts @@ -15,175 +15,6 @@ * limitations under the License. */ -export { PipelineSource } from './lite-api/pipeline-source'; - -export { PipelineResult } from './lite-api/pipeline-result'; - -export { Pipeline } from './api/pipeline'; - -export { useFluentPipelines, pipeline, execute } from './api/pipeline_impl'; - -export { - Stage, - FindNearestOptions, - AddFields, - Aggregate, - Distinct, - CollectionSource, - CollectionGroupSource, - DatabaseSource, - DocumentsSource, - Where, - FindNearest, - Limit, - Offset, - Select, - Sort, - GenericStage -} from './lite-api/stage'; - -export { - add, - subtract, - multiply, - divide, - mod, - eq, - neq, - lt, - lte, - gt, - gte, - arrayConcat, - arrayContains, - arrayContainsAny, - arrayContainsAll, - arrayLength, - eqAny, - notEqAny, - xor, - cond, - not, - logicalMaximum, - logicalMinimum, - exists, - isNan, - reverse, - replaceFirst, - replaceAll, - byteLength, - charLength, - like, - regexContains, - regexMatch, - strContains, - startsWith, - endsWith, - toLower, - toUpper, - trim, - strConcat, - mapGet, - countAll, - countFunction, - sumFunction, - avgFunction, - andFunction, - orFunction, - minimum, - maximum, - cosineDistance, - dotProduct, - euclideanDistance, - vectorLength, - unixMicrosToTimestamp, - timestampToUnixMicros, - unixMillisToTimestamp, - timestampToUnixMillis, - unixSecondsToTimestamp, - timestampToUnixSeconds, - timestampAdd, - timestampSub, - genericFunction, - ascending, - descending, - ExprWithAlias, - Field, - Fields, - Constant, - FirestoreFunction, - Add, - Subtract, - Multiply, - Divide, - Mod, - Eq, - Neq, - Lt, - Lte, - Gt, - Gte, - ArrayConcat, - ArrayReverse, - ArrayContains, - ArrayContainsAll, - ArrayContainsAny, - ArrayLength, - ArrayElement, - EqAny, - NotEqAny, - IsNan, - Exists, - Not, - And, - Or, - Xor, - Cond, - LogicalMaximum, - LogicalMinimum, - Reverse, - ReplaceFirst, - ReplaceAll, - CharLength, - ByteLength, - Like, - RegexContains, - RegexMatch, - StrContains, - StartsWith, - EndsWith, - ToLower, - ToUpper, - Trim, - StrConcat, - MapGet, - Count, - Sum, - Avg, - Minimum, - Maximum, - CosineDistance, - DotProduct, - EuclideanDistance, - VectorLength, - UnixMicrosToTimestamp, - TimestampToUnixMicros, - UnixMillisToTimestamp, - TimestampToUnixMillis, - UnixSecondsToTimestamp, - TimestampToUnixSeconds, - TimestampAdd, - TimestampSub, - Ordering, - ExprType, - AccumulatorTarget, - FilterExpr, - SelectableExpr, - Selectable, - FilterCondition, - Accumulator -} from './lite-api/expressions'; - export { aggregateFieldEqual, aggregateQuerySnapshotEqual, diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index bcd54dca314..becdab092c1 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -14,13 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + export { PipelineSource } from './lite-api/pipeline-source'; export { PipelineResult } from './lite-api/pipeline-result'; -export { Pipeline } from './lite-api/pipeline'; +export { Pipeline } from './api/pipeline'; -export { useFluentPipelines, execute, pipeline } from './api/pipeline_impl'; +export { useFluentPipelines, pipeline, execute } from './api/pipeline_impl'; export { Stage, @@ -174,6 +175,9 @@ export { TimestampAdd, TimestampSub, Ordering, +} from './lite-api/expressions'; + +export type { ExprType, AccumulatorTarget, FilterExpr, diff --git a/packages/firestore/src/pipelines.node.ts b/packages/firestore/src/pipelines.node.ts new file mode 100644 index 00000000000..411006f56a1 --- /dev/null +++ b/packages/firestore/src/pipelines.node.ts @@ -0,0 +1,18 @@ +/** + * @license + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './api_pipelines'; diff --git a/packages/firestore/src/pipelines.rn.ts b/packages/firestore/src/pipelines.rn.ts new file mode 100644 index 00000000000..f53cc1a0656 --- /dev/null +++ b/packages/firestore/src/pipelines.rn.ts @@ -0,0 +1,18 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './api_pipelines'; diff --git a/packages/firestore/src/pipelines.ts b/packages/firestore/src/pipelines.ts new file mode 100644 index 00000000000..22d29e03748 --- /dev/null +++ b/packages/firestore/src/pipelines.ts @@ -0,0 +1,50 @@ +/** + * Cloud Firestore + * + * @packageDocumentation + */ + +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// External exports: ./api +// These external exports will be stripped from the dist/pipelines.d.ts file +// by the prune-dts script, in order to reduce type duplication. However, these +// types need to be exported here to ensure that api-extractor behaves +// correctly. If a type from api.ts is missing from this export, then +// api-extractor may rename it with a suffix `_#`, e.g. `YourType_2`. +export type { + Timestamp, + DocumentReference, + VectorValue, + GeoPoint, + FieldPath, + DocumentData, + Query, + Firestore, + FirestoreDataConverter, + WithFieldValue, + PartialWithFieldValue, + SetOptions, + QueryDocumentSnapshot, + SnapshotOptions, + Primitive, + FieldValue, + SnapshotMetadata +} from './api'; + +export * from './api_pipelines'; diff --git a/packages/firestore/test/integration/util/firebase_export.ts b/packages/firestore/test/integration/util/firebase_export.ts index f58b3ce045b..d986cf49d74 100644 --- a/packages/firestore/test/integration/util/firebase_export.ts +++ b/packages/firestore/test/integration/util/firebase_export.ts @@ -51,4 +51,5 @@ export function newTestFirestore( } export * from '../../../src'; +export * from '../../../src/pipelines'; export { PrivateSettings }; diff --git a/repo-scripts/prune-dts/extract-public-api.ts b/repo-scripts/prune-dts/extract-public-api.ts index c7517399565..aa25ba3fc57 100644 --- a/repo-scripts/prune-dts/extract-public-api.ts +++ b/repo-scripts/prune-dts/extract-public-api.ts @@ -141,7 +141,8 @@ export async function generateApi( typescriptDtsPath: string, rollupDtsPath: string, untrimmedRollupDtsPath: string, - publicDtsPath: string + publicDtsPath: string, + otherExportDtsPaths: string[] ): Promise { console.log(`Configuring API Extractor for ${packageName}`); writeTypeScriptConfig(packageRoot); @@ -160,7 +161,7 @@ export async function generateApi( }); console.log('Generated rollup DTS'); - pruneDts(rollupDtsPath, publicDtsPath); + pruneDts(rollupDtsPath, publicDtsPath, otherExportDtsPaths); console.log('Pruned DTS file'); await addBlankLines(publicDtsPath); console.log('Added blank lines after imports'); @@ -221,6 +222,13 @@ const argv = yargs 'The output file for the customer-facing .d.ts file that only ' + 'includes the public APIs', require: true + }, + otherExportsPublicDtsFiles: { + type: 'string', + desc: + 'Optional. A comma-separated list of customer-facing of .d.ts' + + 'files for other exports from this package.', + require: false } }) .parseSync(); @@ -231,5 +239,6 @@ void generateApi( path.resolve(argv.typescriptDts), path.resolve(argv.rollupDts), path.resolve(argv.untrimmedRollupDts), - path.resolve(argv.publicDts) + path.resolve(argv.publicDts), + argv.otherExportsPublicDtsFiles ? argv.otherExportsPublicDtsFiles.split(',').map(filePath => path.resolve(filePath)) : [] ); diff --git a/repo-scripts/prune-dts/prune-dts.ts b/repo-scripts/prune-dts/prune-dts.ts index 70cfc2933bb..35a94b3fae1 100644 --- a/repo-scripts/prune-dts/prune-dts.ts +++ b/repo-scripts/prune-dts/prune-dts.ts @@ -18,6 +18,7 @@ import * as yargs from 'yargs'; import * as ts from 'typescript'; import * as fs from 'fs'; +import * as path from 'path'; import { ESLint } from 'eslint'; /** @@ -33,16 +34,17 @@ import { ESLint } from 'eslint'; * @param inputLocation The file path to the .d.ts produced by API explorer. * @param outputLocation The output location for the pruned .d.ts file. */ -export function pruneDts(inputLocation: string, outputLocation: string): void { +export function pruneDts(inputLocation: string, outputLocation: string, otherExportFileLocations: string[] = []): void { const compilerOptions = {}; const host = ts.createCompilerHost(compilerOptions); - const program = ts.createProgram([inputLocation], compilerOptions, host); + const program = ts.createProgram([inputLocation, ...otherExportFileLocations], compilerOptions, host); const printer: ts.Printer = ts.createPrinter(); const sourceFile = program.getSourceFile(inputLocation)!; + const otherExportSourceFiles = otherExportFileLocations.map(otherFileLocation => program.getSourceFile(otherFileLocation)).filter(value => value !== undefined) as ts.SourceFile[]; const result: ts.TransformationResult = ts.transform(sourceFile, [ - dropPrivateApiTransformer.bind(null, program, host) + dropPrivateApiTransformer.bind(null, program, host, otherExportSourceFiles ) ]); const transformedSourceFile: ts.SourceFile = result.transformed[0]; let content = printer.printFile(transformedSourceFile); @@ -422,7 +424,7 @@ function extractJSDocComment( function extractExportedSymbol( typeChecker: ts.TypeChecker, sourceFile: ts.SourceFile, - typeName: ts.Node + typeName: ts.Node, ): ts.Symbol | undefined { if (!ts.isIdentifier(typeName)) { return undefined; @@ -503,14 +505,58 @@ function extractExportedSymbol( return undefined; } +function findExternalExport( + typeChecker: ts.TypeChecker, + sourceFile: ts.SourceFile, + node: ts.InterfaceDeclaration | ts.ClassDeclaration | ts.TypeAliasDeclaration | ts.EnumDeclaration, + otherExportSourceFiles: ts.SourceFile[] +): ts.SourceFile | undefined { + if (!node.name) return undefined; + + const localSymbolName = node.name.text; + + for (const otherExportSourceFile of otherExportSourceFiles) { + + const otherExportedSymbols = typeChecker.getExportsOfModule( + typeChecker.getSymbolAtLocation(otherExportSourceFile)! + ); + + for (const symbol of otherExportedSymbols) { + // TODO: ideally this would compare definitions to handle the case + // of name collisions with different definitions. However, this + // implementation currently does not handle function exports, + // which is the only place we expect name collisions. + if (symbol.name === localSymbolName) { + console.log(`===== removing external export ${symbol.name}`) + return otherExportSourceFile; + } + } + } + + return undefined; +} + function dropPrivateApiTransformer( program: ts.Program, host: ts.CompilerHost, - context: ts.TransformationContext + otherExportSourceFiles: ts.SourceFile[], + context: ts.TransformationContext, + ): ts.Transformer { const typeChecker = program.getTypeChecker(); return (sourceFile: ts.SourceFile) => { + const imports: Record> = {}; + + function ensureImportsForFile(filename: string): Array { + let importsForFile = imports[filename]; + if (!importsForFile) { + importsForFile = []; + imports[filename] = importsForFile; + } + return importsForFile; + } + function visit(node: ts.Node): ts.Node { if ( ts.isInterfaceDeclaration(node) || @@ -531,6 +577,22 @@ function dropPrivateApiTransformer( } } + if ( + ts.isInterfaceDeclaration(node) || + ts.isClassDeclaration(node) || + ts.isTypeAliasDeclaration(node) || + ts.isEnumDeclaration(node) + ) { + // Remove any types that are exported externally + const externalExportFile = findExternalExport(typeChecker, sourceFile, node, otherExportSourceFiles); + if (externalExportFile && node.name) { + console.log(`==== sourceFile.filename ${sourceFile.fileName}`) + console.log(`==== externalExportFile.filename ${externalExportFile.fileName}`) + ensureImportsForFile(path.relative(path.dirname(sourceFile.fileName), externalExportFile.fileName)).push(node.name.text); + return ts.factory.createNotEmittedStatement(node); + } + } + if (ts.isConstructorDeclaration(node)) { // Replace internal constructors with private constructors. return maybeHideConstructor(node); @@ -580,7 +642,26 @@ function dropPrivateApiTransformer( context ) as T; } - return visitNodeAndChildren(sourceFile); + const result = visitNodeAndChildren(sourceFile); + + const moreImports: ts.ImportDeclaration[] = []; + for (let filename in imports) { + const importSpecifiers: ts.ImportSpecifier[] = []; + for (let identifier of imports[filename]) { + importSpecifiers.push(ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier(identifier))); + } + let outFileName = filename.startsWith('.') ? filename : `./${filename}`; + outFileName = outFileName.replace('.d.ts', ''); + const importDeclaration = ts.factory.createImportDeclaration( + [], + ts.factory.createImportClause(true, undefined, ts.factory.createNamedImports(importSpecifiers)), + ts.factory.createStringLiteral(outFileName, true) + ) + + moreImports.push(importDeclaration); + } + + return ts.factory.updateSourceFile(result, [...moreImports, ...result.statements], true); }; } From 8006776a3937a3e14a1389dd65fac7d0000e7be1 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:03:30 -0700 Subject: [PATCH 02/75] MEP for firestore lite building --- .../firestore-lite-pipelines.api.md | 1846 +++++++++++++++++ common/api-review/firestore-lite.api.md | 1794 +--------------- packages/firestore/externs.json | 2 + packages/firestore/lite/index.ts | 167 -- packages/firestore/lite/pipelines.ts | 215 ++ packages/firestore/package.json | 19 +- packages/firestore/rollup.config.js | 17 +- packages/firestore/rollup.config.lite.js | 54 +- packages/firestore/rollup.shared.js | 4 - packages/firestore/src/api_pipelines.ts | 2 +- 10 files changed, 2164 insertions(+), 1956 deletions(-) create mode 100644 common/api-review/firestore-lite-pipelines.api.md create mode 100644 packages/firestore/lite/pipelines.ts diff --git a/common/api-review/firestore-lite-pipelines.api.md b/common/api-review/firestore-lite-pipelines.api.md new file mode 100644 index 00000000000..73432fc2965 --- /dev/null +++ b/common/api-review/firestore-lite-pipelines.api.md @@ -0,0 +1,1846 @@ +## API Report File for "@firebase/firestore-lite-pipelines" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { FirebaseApp } from '@firebase/app'; + +// @beta +export interface Accumulator { + // (undocumented) + accumulator: true; +} + +// @beta +export type AccumulatorTarget = ExprWithAlias; + +// @beta (undocumented) +export class Add extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function add(left: Constant, right: Constant): Add; + +// @beta +export function add(left: Constant, right: any): Add; + +// @beta +export function add(left: string, right: Constant): Add; + +// @beta +export function add(left: string, right: any): Add; + +// @beta (undocumented) +export class AddFields implements Stage { + constructor(fields: Map); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class Aggregate implements Stage { + constructor(accumulators: Map, groups: Map); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class And extends FirestoreFunction implements FilterCondition { + constructor(conditions: FilterExpr[]); + // (undocumented) + filterable: true; +} + +// @beta (undocumented) +export class ArrayConcat extends FirestoreFunction { + constructor(array: Constant, elements: Constant[]); + } + +// @beta +export function arrayConcat(array: Constant, elements: Constant[]): ArrayConcat; + +// @beta +export function arrayConcat(array: Constant, elements: any[]): ArrayConcat; + +// @beta +export function arrayConcat(array: string, elements: Constant[]): ArrayConcat; + +// @beta +export function arrayConcat(array: string, elements: any[]): ArrayConcat; + +// @beta (undocumented) +export class ArrayContains extends FirestoreFunction implements FilterCondition { + constructor(array: Constant, element: Constant); + // (undocumented) + filterable: true; +} + +// @beta +export function arrayContains(array: Constant, element: Constant): ArrayContains; + +// @beta +export function arrayContains(array: Constant, element: any): ArrayContains; + +// @beta +export function arrayContains(array: string, element: Constant): ArrayContains; + +// @beta +export function arrayContains(array: string, element: any): ArrayContains; + +// @beta (undocumented) +export class ArrayContainsAll extends FirestoreFunction implements FilterCondition { + constructor(array: Constant, values: Constant[]); + // (undocumented) + filterable: true; + } + +// @beta +export function arrayContainsAll(array: Constant, values: Constant[]): ArrayContainsAll; + +// @beta +export function arrayContainsAll(array: Constant, values: any[]): ArrayContainsAll; + +// @beta +export function arrayContainsAll(array: string, values: Constant[]): ArrayContainsAll; + +// @beta +export function arrayContainsAll(array: string, values: any[]): ArrayContainsAll; + +// @beta (undocumented) +export class ArrayContainsAny extends FirestoreFunction implements FilterCondition { + constructor(array: Constant, values: Constant[]); + // (undocumented) + filterable: true; + } + +// @beta +export function arrayContainsAny(array: Constant, values: Constant[]): ArrayContainsAny; + +// @beta +export function arrayContainsAny(array: Constant, values: any[]): ArrayContainsAny; + +// @beta +export function arrayContainsAny(array: string, values: Constant[]): ArrayContainsAny; + +// @beta +export function arrayContainsAny(array: string, values: any[]): ArrayContainsAny; + +// @beta (undocumented) +export class ArrayElement extends FirestoreFunction { + constructor(); +} + +// @beta (undocumented) +export class ArrayLength extends FirestoreFunction { + constructor(array: Constant); + } + +// @beta +export function arrayLength(array: Constant): ArrayLength; + +// @beta (undocumented) +export class ArrayReverse extends FirestoreFunction { + constructor(array: Constant); + } + +// @beta +export function ascending(expr: Constant): Ordering; + +// @beta (undocumented) +export class Avg extends FirestoreFunction implements Accumulator { + constructor(value: Constant, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta (undocumented) +export class ByteLength extends FirestoreFunction { + constructor(value: Constant); + } + +// @beta +export function byteLength(expr: Constant): ByteLength; + +// @beta +export function byteLength(field: string): ByteLength; + +// @beta (undocumented) +export class CharLength extends FirestoreFunction { + constructor(value: Constant); + } + +// @beta +export function charLength(field: string): CharLength; + +// @beta +export function charLength(expr: Constant): CharLength; + +// @beta (undocumented) +export class CollectionGroupSource implements Stage { + constructor(collectionId: string); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class CollectionSource implements Stage { + constructor(collectionPath: string); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class Cond extends FirestoreFunction implements FilterCondition { + constructor(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function cond(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant): Cond; + +// @beta +export class Constant { + add(other: Constant): Add; + add(other: any): Add; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + static of(value: number): Constant; + static of(value: string): Constant; + static of(value: boolean): Constant; + static of(value: null): Constant; + static of(value: undefined): Constant; + static of(value: GeoPoint): Constant; + static of(value: Timestamp): Constant; + static of(value: Date): Constant; + static of(value: Uint8Array): Constant; + static of(value: DocumentReference): Constant; + static of(value: any[]): Constant; + static of(value: Map): Constant; + static of(value: VectorValue): Constant; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + static vector(value: number[] | VectorValue): Constant; + vectorLength(): VectorLength; +} + +// @beta (undocumented) +export class CosineDistance extends FirestoreFunction { + constructor(vector1: Constant, vector2: Constant); + } + +// @beta +export function cosineDistance(expr: string, other: number[]): CosineDistance; + +// @beta +export function cosineDistance(expr: string, other: VectorValue): CosineDistance; + +// @beta +export function cosineDistance(expr: string, other: Constant): CosineDistance; + +// @beta +export function cosineDistance(expr: Constant, other: number[]): CosineDistance; + +// @beta +export function cosineDistance(expr: Constant, other: VectorValue): CosineDistance; + +// @beta +export function cosineDistance(expr: Constant, other: Constant): CosineDistance; + +// @beta (undocumented) +export class Count extends FirestoreFunction implements Accumulator { + constructor(value: Constant | undefined, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function countAll(): Count; + +// @beta (undocumented) +export class DatabaseSource implements Stage { + // (undocumented) + name: string; +} + +// @beta +export function descending(expr: Constant): Ordering; + +// @beta (undocumented) +export class Distinct implements Stage { + constructor(groups: Map); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class Divide extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function divide(left: Constant, right: Constant): Divide; + +// @beta +export function divide(left: Constant, right: any): Divide; + +// @beta +export function divide(left: string, right: Constant): Divide; + +// @beta +export function divide(left: string, right: any): Divide; + +// @public +export interface DocumentData { + [field: string]: any; +} + +// @public +export class DocumentReference { + readonly converter: FirestoreDataConverter | null; + readonly firestore: Firestore; + get id(): string; + get parent(): Query; + get path(): string; + readonly type = "document"; + withConverter(converter: FirestoreDataConverter): DocumentReference; + withConverter(converter: null): DocumentReference; +} + +// @beta (undocumented) +export class DocumentsSource implements Stage { + constructor(docPaths: string[]); + // (undocumented) + name: string; + // (undocumented) + static of(refs: DocumentReference[]): DocumentsSource; +} + +// @beta (undocumented) +export class DotProduct extends FirestoreFunction { + constructor(vector1: Constant, vector2: Constant); + } + +// @beta +export function dotProduct(expr: string, other: number[]): DotProduct; + +// @beta +export function dotProduct(expr: string, other: VectorValue): DotProduct; + +// @beta +export function dotProduct(expr: string, other: Constant): DotProduct; + +// @beta +export function dotProduct(expr: Constant, other: number[]): DotProduct; + +// @beta +export function dotProduct(expr: Constant, other: VectorValue): DotProduct; + +// @beta +export function dotProduct(expr: Constant, other: Constant): DotProduct; + +// @beta (undocumented) +export class EndsWith extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, suffix: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function endsWith(expr: string, suffix: string): EndsWith; + +// @beta +export function endsWith(expr: string, suffix: Constant): EndsWith; + +// @beta +export function endsWith(expr: Constant, suffix: string): EndsWith; + +// @beta +export function endsWith(expr: Constant, suffix: Constant): EndsWith; + +// @beta (undocumented) +export class Eq extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function eq(left: Constant, right: Constant): Eq; + +// @beta +export function eq(left: Constant, right: any): Eq; + +// @beta +export function eq(left: string, right: Constant): Eq; + +// @beta +export function eq(left: string, right: any): Eq; + +// @beta (undocumented) +export class EqAny extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, others: Constant[]); + // (undocumented) + filterable: true; + } + +// @beta +export function eqAny(element: Constant, others: Constant[]): EqAny; + +// @beta +export function eqAny(element: Constant, others: any[]): EqAny; + +// @beta +export function eqAny(element: string, others: Constant[]): EqAny; + +// @beta +export function eqAny(element: string, others: any[]): EqAny; + +// @beta (undocumented) +export class EuclideanDistance extends FirestoreFunction { + constructor(vector1: Constant, vector2: Constant); + } + +// @beta +export function euclideanDistance(expr: string, other: number[]): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: string, other: VectorValue): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: string, other: Constant): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: Constant, other: number[]): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: Constant, other: VectorValue): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: Constant, other: Constant): EuclideanDistance; + +// @beta +export function execute(pipeline: Pipeline): Promise>>; + +// @beta (undocumented) +export class Exists extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant); + // (undocumented) + filterable: true; +} + +// @beta +export function exists(value: Constant): Exists; + +// @beta +export function exists(field: string): Exists; + +// @beta +export type ExprType = 'Field' | 'Constant' | 'Function' | 'ListOfExprs' | 'ExprWithAlias'; + +// @beta (undocumented) +export class ExprWithAlias implements Selectable { + constructor(expr: T, alias: string); + add(other: Constant): Add; + add(other: any): Add; + // (undocumented) + alias: string; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + expr: T; + // (undocumented) + exprType: ExprType; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + // (undocumented) + selectable: true; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + +// @beta +export class Field implements Selectable { + add(other: Constant): Add; + add(other: any): Add; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + // (undocumented) + fieldName(): string; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + static of(name: string): Field; + // (undocumented) + static of(path: FieldPath): Field; + // (undocumented) + static of(pipeline: Pipeline, name: string): Field; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + // (undocumented) + selectable: true; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + +// @public +export class FieldPath { + constructor(...fieldNames: string[]); + isEqual(other: FieldPath): boolean; +} + +// @beta (undocumented) +export class Fields implements Selectable { + add(other: Constant): Add; + add(other: any): Add; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + // (undocumented) + fieldList(): Field[]; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + // (undocumented) + static of(name: string, ...others: string[]): Fields; + // (undocumented) + static ofAll(): Fields; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + // (undocumented) + selectable: true; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + +// @public +export abstract class FieldValue { + abstract isEqual(other: FieldValue): boolean; +} + +// @beta +export interface FilterCondition { + // (undocumented) + filterable: true; +} + +// @beta +export type FilterExpr = Constant & FilterCondition; + +// @beta (undocumented) +export class FindNearest implements Stage { + // (undocumented) + name: string; +} + +// @beta (undocumented) +export interface FindNearestOptions { + // (undocumented) + distanceField?: string; + // (undocumented) + distanceMeasure: 'euclidean' | 'cosine' | 'dot_product'; + // (undocumented) + field: Field; + // (undocumented) + limit?: number; + // (undocumented) + vectorValue: VectorValue | number[]; +} + +// @public +export class Firestore { + get app(): FirebaseApp; + toJSON(): object; + type: 'firestore-lite' | 'firestore'; +} + +// @public +export interface FirestoreDataConverter { + fromFirestore(snapshot: QueryDocumentSnapshot): AppModelType; + toFirestore(modelObject: WithFieldValue): WithFieldValue; + toFirestore(modelObject: PartialWithFieldValue, options: SetOptions): PartialWithFieldValue; +} + +// @beta +export class FirestoreFunction { + constructor(name: string, params: Constant[]); + add(other: Constant): Add; + add(other: any): Add; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + +// @beta +export function genericFunction(name: string, params: Constant[]): FirestoreFunction; + +// @beta (undocumented) +export class GenericStage implements Stage { + constructor(name: string, params: unknown[]); + // (undocumented) + name: string; +} + +// @public +export class GeoPoint { + constructor(latitude: number, longitude: number); + isEqual(other: GeoPoint): boolean; + get latitude(): number; + get longitude(): number; + toJSON(): { + latitude: number; + longitude: number; + }; +} + +// @beta (undocumented) +export class Gt extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function gt(left: Constant, right: Constant): Gt; + +// @beta +export function gt(left: Constant, right: any): Gt; + +// @beta +export function gt(left: string, right: Constant): Gt; + +// @beta +export function gt(left: string, right: any): Gt; + +// @beta (undocumented) +export class Gte extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function gte(left: Constant, right: Constant): Gte; + +// @beta +export function gte(left: Constant, right: any): Gte; + +// @beta +export function gte(left: string, right: Constant): Gte; + +// @beta +export function gte(left: string, right: any): Gte; + +// @beta (undocumented) +export class IsNan extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant); + // (undocumented) + filterable: true; +} + +// @beta +export function isNan(value: Constant): IsNan; + +// @beta +export function isNan(value: string): IsNan; + +// @beta (undocumented) +export class Like extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, pattern: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function like(left: string, pattern: string): Like; + +// @beta +export function like(left: string, pattern: Constant): Like; + +// @beta +export function like(left: Constant, pattern: string): Like; + +// @beta +export function like(left: Constant, pattern: Constant): Like; + +// @beta (undocumented) +export class Limit implements Stage { + constructor(limit: number); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class LogicalMaximum extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function logicalMaximum(left: Constant, right: Constant): LogicalMaximum; + +// @beta +export function logicalMaximum(left: Constant, right: any): LogicalMaximum; + +// @beta +export function logicalMaximum(left: string, right: Constant): LogicalMaximum; + +// @beta +export function logicalMaximum(left: string, right: any): LogicalMaximum; + +// @beta (undocumented) +export class LogicalMinimum extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function logicalMinimum(left: Constant, right: Constant): LogicalMinimum; + +// @beta +export function logicalMinimum(left: Constant, right: any): LogicalMinimum; + +// @beta +export function logicalMinimum(left: string, right: Constant): LogicalMinimum; + +// @beta +export function logicalMinimum(left: string, right: any): LogicalMinimum; + +// @beta (undocumented) +export class Lt extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function lt(left: Constant, right: Constant): Lt; + +// @beta +export function lt(left: Constant, right: any): Lt; + +// @beta +export function lt(left: string, right: Constant): Lt; + +// @beta +export function lt(left: string, right: any): Lt; + +// @beta (undocumented) +export class Lte extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function lte(left: Constant, right: Constant): Lte; + +// @beta +export function lte(left: Constant, right: any): Lte; + +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Constant" which is marked as @beta +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Lte" which is marked as @beta +// +// @public +export function lte(left: string, right: Constant): Lte; + +// @beta +export function lte(left: string, right: any): Lte; + +// @beta (undocumented) +export class MapGet extends FirestoreFunction { + constructor(map: Constant, name: string); +} + +// @beta +export function mapGet(mapField: string, subField: string): MapGet; + +// @beta +export function mapGet(mapExpr: Constant, subField: string): MapGet; + +// @beta (undocumented) +export class Maximum extends FirestoreFunction implements Accumulator { + constructor(value: Constant, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function maximum(value: Constant): Maximum; + +// @beta +export function maximum(value: string): Maximum; + +// @beta (undocumented) +export class Minimum extends FirestoreFunction implements Accumulator { + constructor(value: Constant, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function minimum(value: Constant): Minimum; + +// @beta +export function minimum(value: string): Minimum; + +// @beta (undocumented) +export class Mod extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function mod(left: Constant, right: Constant): Mod; + +// @beta +export function mod(left: Constant, right: any): Mod; + +// @beta +export function mod(left: string, right: Constant): Mod; + +// @beta +export function mod(left: string, right: any): Mod; + +// @beta (undocumented) +export class Multiply extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function multiply(left: Constant, right: Constant): Multiply; + +// @beta +export function multiply(left: Constant, right: any): Multiply; + +// @beta +export function multiply(left: string, right: Constant): Multiply; + +// @beta +export function multiply(left: string, right: any): Multiply; + +// @beta (undocumented) +export class Neq extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function neq(left: Constant, right: Constant): Neq; + +// @beta +export function neq(left: Constant, right: any): Neq; + +// @beta +export function neq(left: string, right: Constant): Neq; + +// @beta +export function neq(left: string, right: any): Neq; + +// @beta (undocumented) +export class Not extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant); + // (undocumented) + filterable: true; +} + +// @beta +export function not(filter: FilterExpr): Not; + +// @beta +export function notEqAny(element: Constant, others: Constant[]): FirestoreFunction; + +// @beta +export function notEqAny(element: Constant, others: any[]): FirestoreFunction; + +// @beta +export function notEqAny(element: string, others: Constant[]): FirestoreFunction; + +// @beta +export function notEqAny(element: string, others: any[]): FirestoreFunction; + +// @beta (undocumented) +export class Offset implements Stage { + constructor(offset: number); + // (undocumented) + name: string; + } + +// @beta (undocumented) +export class Or extends FirestoreFunction implements FilterCondition { + constructor(conditions: FilterExpr[]); + // (undocumented) + filterable: true; +} + +// @beta +export class Ordering { + constructor(expr: Constant, direction: 'ascending' | 'descending'); + } + +// @public +export type PartialWithFieldValue = Partial | (T extends Primitive ? T : T extends {} ? { + [K in keyof T]?: PartialWithFieldValue | FieldValue; +} : never); + +// @public +export class Pipeline { + /* Excluded from this release type: _db */ + // Warning: (ae-incompatible-release-tags) The symbol "addFields" is marked as @public, but its signature references "Selectable" which is marked as @beta + addFields(...fields: Selectable[]): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta + aggregate(...accumulators: AccumulatorTarget[]): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + aggregate(options: { + accumulators: AccumulatorTarget[]; + groups?: Array; + }): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta + distinct(...groups: Array): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta + execute(): Promise>>; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "findNearest" is marked as @public, but its signature references "FindNearestOptions" which is marked as @beta + // + // (undocumented) + findNearest(options: FindNearestOptions): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + genericStage(name: string, params: any[]): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + limit(limit: number): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + offset(offset: number): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "select" is marked as @public, but its signature references "Selectable" which is marked as @beta + select(...selections: Array): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "sort" is marked as @public, but its signature references "Ordering" which is marked as @beta + sort(...orderings: Ordering[]): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // (undocumented) + sort(options: { + orderings: Ordering[]; + }): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "FilterCondition" which is marked as @beta + // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "Constant" which is marked as @beta + where(condition: FilterCondition & Constant): Pipeline; +} + +// Warning: (ae-incompatible-release-tags) The symbol "pipeline" is marked as @public, but its signature references "PipelineSource" which is marked as @beta +// +// @public +export function pipeline(firestore: Firestore): PipelineSource; + +// @public +export function pipeline(query: Query): Pipeline; + +// @beta +export class PipelineResult { + /* Excluded from this release type: _ref */ + /* Excluded from this release type: _fields */ + /* Excluded from this release type: __constructor */ + get createTime(): Timestamp | undefined; + data(): AppModelType | undefined; + get executionTime(): Timestamp; + get(fieldPath: string | FieldPath): any; + get id(): string | undefined; + get ref(): DocumentReference | undefined; + get updateTime(): Timestamp | undefined; +} + +// @beta +export class PipelineSource { + /* Excluded from this release type: _db */ + /* Excluded from this release type: _userDataReader */ + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + /* Excluded from this release type: __constructor */ + // (undocumented) + collection(collectionPath: string): Pipeline; + // (undocumented) + collectionGroup(collectionId: string): Pipeline; + // (undocumented) + database(): Pipeline; + // (undocumented) + documents(docs: DocumentReference[]): Pipeline; +} + +// @public +export type Primitive = string | number | boolean | undefined | null; + +// @public +export class Query { + protected constructor(); + readonly converter: FirestoreDataConverter | null; + readonly firestore: Firestore; + readonly type: 'query' | 'collection'; + withConverter(converter: null): Query; + withConverter(converter: FirestoreDataConverter): Query; +} + +// @public +export class QueryDocumentSnapshot { + // @override + data(): AppModelType; + exists(): this is QueryDocumentSnapshot; + get(fieldPath: string | FieldPath); + get id(): string; + get ref(): DocumentReference; +} + +// @beta (undocumented) +export class RegexContains extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, pattern: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function regexContains(left: string, pattern: string): RegexContains; + +// @beta +export function regexContains(left: string, pattern: Constant): RegexContains; + +// @beta +export function regexContains(left: Constant, pattern: string): RegexContains; + +// @beta +export function regexContains(left: Constant, pattern: Constant): RegexContains; + +// @beta (undocumented) +export class RegexMatch extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, pattern: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function regexMatch(left: string, pattern: string): RegexMatch; + +// @beta +export function regexMatch(left: string, pattern: Constant): RegexMatch; + +// @beta +export function regexMatch(left: Constant, pattern: string): RegexMatch; + +// @beta +export function regexMatch(left: Constant, pattern: Constant): RegexMatch; + +// @beta (undocumented) +export class ReplaceAll extends FirestoreFunction { + constructor(value: Constant, find: Constant, replace: Constant); + } + +// @beta +export function replaceAll(value: Constant, find: string, replace: string): ReplaceAll; + +// @beta +export function replaceAll(value: Constant, find: Constant, replace: Constant): ReplaceAll; + +// @beta +export function replaceAll(field: string, find: string, replace: string): ReplaceAll; + +// @beta (undocumented) +export class ReplaceFirst extends FirestoreFunction { + constructor(value: Constant, find: Constant, replace: Constant); + } + +// @beta +export function replaceFirst(value: Constant, find: string, replace: string): ReplaceFirst; + +// @beta +export function replaceFirst(value: Constant, find: Constant, replace: Constant): ReplaceFirst; + +// @beta +export function replaceFirst(field: string, find: string, replace: string): ReplaceFirst; + +// @beta (undocumented) +export class Reverse extends FirestoreFunction { + constructor(value: Constant); + } + +// @beta +export function reverse(expr: Constant): Reverse; + +// @beta +export function reverse(field: string): Reverse; + +// @beta (undocumented) +export class Select implements Stage { + constructor(projections: Map); + // (undocumented) + name: string; + } + +// @beta +export interface Selectable { + // (undocumented) + selectable: true; +} + +// @beta +export type SelectableExpr = Constant & Selectable; + +// @public +export type SetOptions = { + readonly merge?: boolean; +} | { + readonly mergeFields?: Array; +}; + +// @beta (undocumented) +export class Sort implements Stage { + constructor(orders: Ordering[]); + // (undocumented) + name: string; + } + +// @beta (undocumented) +export interface Stage { + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class StartsWith extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, prefix: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function startsWith(expr: string, prefix: string): StartsWith; + +// @beta +export function startsWith(expr: string, prefix: Constant): StartsWith; + +// @beta +export function startsWith(expr: Constant, prefix: string): StartsWith; + +// @beta +export function startsWith(expr: Constant, prefix: Constant): StartsWith; + +// @beta (undocumented) +export class StrConcat extends FirestoreFunction { + constructor(first: Constant, rest: Constant[]); + } + +// @beta +export function strConcat(first: string, ...elements: Array): StrConcat; + +// @beta +export function strConcat(first: Constant, ...elements: Array): StrConcat; + +// @beta (undocumented) +export class StrContains extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, substring: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function strContains(left: string, substring: string): StrContains; + +// @beta +export function strContains(left: string, substring: Constant): StrContains; + +// @beta +export function strContains(left: Constant, substring: string): StrContains; + +// @beta +export function strContains(left: Constant, substring: Constant): StrContains; + +// @beta (undocumented) +export class Subtract extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function subtract(left: Constant, right: Constant): Subtract; + +// @beta +export function subtract(left: Constant, right: any): Subtract; + +// @beta +export function subtract(left: string, right: Constant): Subtract; + +// @beta +export function subtract(left: string, right: any): Subtract; + +// @beta (undocumented) +export class Sum extends FirestoreFunction implements Accumulator { + constructor(value: Constant, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @public +export class Timestamp { + constructor( + seconds: number, + nanoseconds: number); + static fromDate(date: Date): Timestamp; + static fromMillis(milliseconds: number): Timestamp; + isEqual(other: Timestamp): boolean; + readonly nanoseconds: number; + static now(): Timestamp; + readonly seconds: number; + toDate(): Date; + toJSON(): { + seconds: number; + nanoseconds: number; + }; + toMillis(): number; + toString(): string; + valueOf(): string; +} + +// @beta (undocumented) +export class TimestampAdd extends FirestoreFunction { + constructor(timestamp: Constant, unit: Constant, amount: Constant); + } + +// @beta +export function timestampAdd(timestamp: Constant, unit: Constant, amount: Constant): TimestampAdd; + +// @beta +export function timestampAdd(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + +// @beta +export function timestampAdd(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + +// @beta (undocumented) +export class TimestampSub extends FirestoreFunction { + constructor(timestamp: Constant, unit: Constant, amount: Constant); + } + +// @beta +export function timestampSub(timestamp: Constant, unit: Constant, amount: Constant): TimestampSub; + +// @beta +export function timestampSub(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + +// @beta +export function timestampSub(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + +// @beta (undocumented) +export class TimestampToUnixMicros extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function timestampToUnixMicros(expr: Constant): TimestampToUnixMicros; + +// @beta +export function timestampToUnixMicros(field: string): TimestampToUnixMicros; + +// @beta (undocumented) +export class TimestampToUnixMillis extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function timestampToUnixMillis(expr: Constant): TimestampToUnixMillis; + +// @beta +export function timestampToUnixMillis(field: string): TimestampToUnixMillis; + +// @beta (undocumented) +export class TimestampToUnixSeconds extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function timestampToUnixSeconds(expr: Constant): TimestampToUnixSeconds; + +// @beta +export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; + +// @beta (undocumented) +export class ToLower extends FirestoreFunction { + constructor(expr: Constant); + } + +// @beta +export function toLower(expr: string): ToLower; + +// @beta +export function toLower(expr: Constant): ToLower; + +// @beta (undocumented) +export class ToUpper extends FirestoreFunction { + constructor(expr: Constant); + } + +// @beta +export function toUpper(expr: string): ToUpper; + +// @beta +export function toUpper(expr: Constant): ToUpper; + +// @beta (undocumented) +export class Trim extends FirestoreFunction { + constructor(expr: Constant); + } + +// @beta +export function trim(expr: string): Trim; + +// @beta +export function trim(expr: Constant): Trim; + +// @beta (undocumented) +export class UnixMicrosToTimestamp extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function unixMicrosToTimestamp(expr: Constant): UnixMicrosToTimestamp; + +// @beta +export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; + +// @beta (undocumented) +export class UnixMillisToTimestamp extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function unixMillisToTimestamp(expr: Constant): UnixMillisToTimestamp; + +// @beta +export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; + +// @beta (undocumented) +export class UnixSecondsToTimestamp extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function unixSecondsToTimestamp(expr: Constant): UnixSecondsToTimestamp; + +// @beta +export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; + +// @public (undocumented) +export function useFluentPipelines(): void; + +// @beta (undocumented) +export class VectorLength extends FirestoreFunction { + constructor(value: Constant); + } + +// @beta +export function vectorLength(expr: Constant): VectorLength; + +// @beta +export function vectorLength(field: string): VectorLength; + +// @public +export class VectorValue { + /* Excluded from this release type: __constructor */ + isEqual(other: VectorValue): boolean; + toArray(): number[]; +} + +// @beta (undocumented) +export class Where implements Stage { + constructor(condition: FilterCondition & Constant); + // (undocumented) + name: string; +} + +// @public +export type WithFieldValue = T | (T extends Primitive ? T : T extends {} ? { + [K in keyof T]: WithFieldValue | FieldValue; +} : never); + +// @beta (undocumented) +export class Xor extends FirestoreFunction implements FilterCondition { + constructor(conditions: FilterExpr[]); + // (undocumented) + filterable: true; +} + +// @beta +export function xor(left: FilterExpr, ...right: FilterExpr[]): Xor; + + +// Warnings were encountered during analysis: +// +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:8518:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:8519:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:8548:9 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta + +``` diff --git a/common/api-review/firestore-lite.api.md b/common/api-review/firestore-lite.api.md index 07af0bacd6e..4a9ef4c0171 100644 --- a/common/api-review/firestore-lite.api.md +++ b/common/api-review/firestore-lite.api.md @@ -9,54 +9,14 @@ import { FirebaseApp } from '@firebase/app'; import { FirebaseError } from '@firebase/util'; import { LogLevelString as LogLevel } from '@firebase/logger'; -// @beta -export interface Accumulator { - // (undocumented) - accumulator: true; -} - -// @beta -export type AccumulatorTarget = ExprWithAlias; - -// @beta (undocumented) -export class Add extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } - -// @beta -export function add(left: Constant, right: Constant): Add; - -// @beta -export function add(left: Constant, right: any): Add; - -// @beta -export function add(left: string, right: Constant): Add; - -// @beta -export function add(left: string, right: any): Add; - // @public export function addDoc(reference: CollectionReference, data: WithFieldValue): Promise>; -// @beta (undocumented) -export class AddFields implements Stage { - constructor(fields: Map); - // (undocumented) - name: string; -} - // @public export type AddPrefixToKeys> = { [K in keyof T & string as `${Prefix}.${K}`]+?: string extends K ? any : T[K]; }; -// @beta (undocumented) -export class Aggregate implements Stage { - constructor(accumulators: Map, groups: Map); - // (undocumented) - name: string; -} - // @public export class AggregateField { readonly aggregateType: AggregateType; @@ -93,138 +53,18 @@ export type AggregateSpecData = { // @public export type AggregateType = 'count' | 'avg' | 'sum'; -// @beta (undocumented) -export class And extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterExpr[]); - // (undocumented) - filterable: true; -} - // @public export function and(...queryConstraints: QueryFilterConstraint[]): QueryCompositeFilterConstraint; -// @beta (undocumented) -export class ArrayConcat extends FirestoreFunction { - constructor(array: Constant, elements: Constant[]); - } - -// @beta -export function arrayConcat(array: Constant, elements: Constant[]): ArrayConcat; - -// @beta -export function arrayConcat(array: Constant, elements: any[]): ArrayConcat; - -// @beta -export function arrayConcat(array: string, elements: Constant[]): ArrayConcat; - -// @beta -export function arrayConcat(array: string, elements: any[]): ArrayConcat; - -// @beta (undocumented) -export class ArrayContains extends FirestoreFunction implements FilterCondition { - constructor(array: Constant, element: Constant); - // (undocumented) - filterable: true; -} - -// @beta -export function arrayContains(array: Constant, element: Constant): ArrayContains; - -// @beta -export function arrayContains(array: Constant, element: any): ArrayContains; - -// @beta -export function arrayContains(array: string, element: Constant): ArrayContains; - -// @beta -export function arrayContains(array: string, element: any): ArrayContains; - -// @beta (undocumented) -export class ArrayContainsAll extends FirestoreFunction implements FilterCondition { - constructor(array: Constant, values: Constant[]); - // (undocumented) - filterable: true; - } - -// @beta -export function arrayContainsAll(array: Constant, values: Constant[]): ArrayContainsAll; - -// @beta -export function arrayContainsAll(array: Constant, values: any[]): ArrayContainsAll; - -// @beta -export function arrayContainsAll(array: string, values: Constant[]): ArrayContainsAll; - -// @beta -export function arrayContainsAll(array: string, values: any[]): ArrayContainsAll; - -// @beta (undocumented) -export class ArrayContainsAny extends FirestoreFunction implements FilterCondition { - constructor(array: Constant, values: Constant[]); - // (undocumented) - filterable: true; - } - -// @beta -export function arrayContainsAny(array: Constant, values: Constant[]): ArrayContainsAny; - -// @beta -export function arrayContainsAny(array: Constant, values: any[]): ArrayContainsAny; - -// @beta -export function arrayContainsAny(array: string, values: Constant[]): ArrayContainsAny; - -// @beta -export function arrayContainsAny(array: string, values: any[]): ArrayContainsAny; - -// @beta (undocumented) -export class ArrayElement extends FirestoreFunction { - constructor(); -} - -// @beta (undocumented) -export class ArrayLength extends FirestoreFunction { - constructor(array: Constant); - } - -// @beta -export function arrayLength(array: Constant): ArrayLength; - // @public export function arrayRemove(...elements: unknown[]): FieldValue; -// @beta (undocumented) -export class ArrayReverse extends FirestoreFunction { - constructor(array: Constant); - } - // @public export function arrayUnion(...elements: unknown[]): FieldValue; -// @beta -export function ascending(expr: Constant): Ordering; - // @public export function average(field: string | FieldPath): AggregateField; -// @beta (undocumented) -export class Avg extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); - // (undocumented) - accumulator: true; - } - -// @beta (undocumented) -export class ByteLength extends FirestoreFunction { - constructor(value: Constant); - } - -// @beta -export function byteLength(expr: Constant): ByteLength; - -// @beta -export function byteLength(field: string): ByteLength; - // @public export class Bytes { static fromBase64String(base64: string): Bytes; @@ -235,17 +75,6 @@ export class Bytes { toUint8Array(): Uint8Array; } -// @beta (undocumented) -export class CharLength extends FirestoreFunction { - constructor(value: Constant); - } - -// @beta -export function charLength(field: string): CharLength; - -// @beta -export function charLength(expr: Constant): CharLength; - // @public export type ChildUpdateFields = V extends Record ? AddPrefixToKeys> : never; @@ -261,13 +90,6 @@ export function collection(refer // @public export function collectionGroup(firestore: Firestore, collectionId: string): Query; -// @beta (undocumented) -export class CollectionGroupSource implements Stage { - constructor(collectionId: string); - // (undocumented) - name: string; -} - // @public export class CollectionReference extends Query { get id(): string; @@ -278,221 +100,20 @@ export class CollectionReference; } -// @beta (undocumented) -export class CollectionSource implements Stage { - constructor(collectionPath: string); - // (undocumented) - name: string; -} - -// @beta (undocumented) -export class Cond extends FirestoreFunction implements FilterCondition { - constructor(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function cond(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant): Cond; - // @public export function connectFirestoreEmulator(firestore: Firestore, host: string, port: number, options?: { mockUserToken?: EmulatorMockTokenOptions | string; }): void; -// @beta -export class Constant { - add(other: Constant): Add; - add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): FirestoreFunction; - // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - static of(value: number): Constant; - static of(value: string): Constant; - static of(value: boolean): Constant; - static of(value: null): Constant; - static of(value: undefined): Constant; - static of(value: GeoPoint): Constant; - static of(value: Timestamp): Constant; - static of(value: Date): Constant; - static of(value: Uint8Array): Constant; - static of(value: DocumentReference): Constant; - static of(value: any[]): Constant; - static of(value: Map): Constant; - static of(value: VectorValue): Constant; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - static vector(value: number[] | VectorValue): Constant; - vectorLength(): VectorLength; -} - -// @beta (undocumented) -export class CosineDistance extends FirestoreFunction { - constructor(vector1: Constant, vector2: Constant); - } - -// @beta -export function cosineDistance(expr: string, other: number[]): CosineDistance; - -// @beta -export function cosineDistance(expr: string, other: VectorValue): CosineDistance; - -// @beta -export function cosineDistance(expr: string, other: Constant): CosineDistance; - -// @beta -export function cosineDistance(expr: Constant, other: number[]): CosineDistance; - -// @beta -export function cosineDistance(expr: Constant, other: VectorValue): CosineDistance; - -// @beta -export function cosineDistance(expr: Constant, other: Constant): CosineDistance; - -// @beta (undocumented) -export class Count extends FirestoreFunction implements Accumulator { - constructor(value: Constant | undefined, distinct: boolean); - // (undocumented) - accumulator: true; - } - // @public export function count(): AggregateField; -// @beta -export function countAll(): Count; - -// @beta (undocumented) -export class DatabaseSource implements Stage { - // (undocumented) - name: string; -} - // @public export function deleteDoc(reference: DocumentReference): Promise; // @public export function deleteField(): FieldValue; -// @beta -export function descending(expr: Constant): Ordering; - -// @beta (undocumented) -export class Distinct implements Stage { - constructor(groups: Map); - // (undocumented) - name: string; -} - -// @beta (undocumented) -export class Divide extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } - -// @beta -export function divide(left: Constant, right: Constant): Divide; - -// @beta -export function divide(left: Constant, right: any): Divide; - -// @beta -export function divide(left: string, right: Constant): Divide; - -// @beta -export function divide(left: string, right: any): Divide; - // @public export function doc(firestore: Firestore, path: string, ...pathSegments: string[]): DocumentReference; @@ -532,38 +153,6 @@ export class DocumentSnapshot; } -// @beta (undocumented) -export class DocumentsSource implements Stage { - constructor(docPaths: string[]); - // (undocumented) - name: string; - // (undocumented) - static of(refs: DocumentReference[]): DocumentsSource; -} - -// @beta (undocumented) -export class DotProduct extends FirestoreFunction { - constructor(vector1: Constant, vector2: Constant); - } - -// @beta -export function dotProduct(expr: string, other: number[]): DotProduct; - -// @beta -export function dotProduct(expr: string, other: VectorValue): DotProduct; - -// @beta -export function dotProduct(expr: string, other: Constant): DotProduct; - -// @beta -export function dotProduct(expr: Constant, other: number[]): DotProduct; - -// @beta -export function dotProduct(expr: Constant, other: VectorValue): DotProduct; - -// @beta -export function dotProduct(expr: Constant, other: Constant): DotProduct; - export { EmulatorMockTokenOptions } // @public @@ -578,481 +167,17 @@ export function endBefore(snapsh // @public export function endBefore(...fieldValues: unknown[]): QueryEndAtConstraint; -// @beta (undocumented) -export class EndsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, suffix: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function endsWith(expr: string, suffix: string): EndsWith; - -// @beta -export function endsWith(expr: string, suffix: Constant): EndsWith; - -// @beta -export function endsWith(expr: Constant, suffix: string): EndsWith; - -// @beta -export function endsWith(expr: Constant, suffix: Constant): EndsWith; - -// @beta (undocumented) -export class Eq extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function eq(left: Constant, right: Constant): Eq; - -// @beta -export function eq(left: Constant, right: any): Eq; - -// @beta -export function eq(left: string, right: Constant): Eq; - -// @beta -export function eq(left: string, right: any): Eq; - -// @beta (undocumented) -export class EqAny extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, others: Constant[]); - // (undocumented) - filterable: true; - } - -// @beta -export function eqAny(element: Constant, others: Constant[]): EqAny; - -// @beta -export function eqAny(element: Constant, others: any[]): EqAny; - -// @beta -export function eqAny(element: string, others: Constant[]): EqAny; - -// @beta -export function eqAny(element: string, others: any[]): EqAny; - -// @beta (undocumented) -export class EuclideanDistance extends FirestoreFunction { - constructor(vector1: Constant, vector2: Constant); - } - -// @beta -export function euclideanDistance(expr: string, other: number[]): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: string, other: VectorValue): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: string, other: Constant): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: Constant, other: number[]): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: Constant, other: VectorValue): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: Constant, other: Constant): EuclideanDistance; - -// @beta -export function execute(pipeline: Pipeline): Promise>>; - -// @beta (undocumented) -export class Exists extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant); - // (undocumented) - filterable: true; -} - -// @beta -export function exists(value: Constant): Exists; - -// @beta -export function exists(field: string): Exists; - -// @beta -export type ExprType = 'Field' | 'Constant' | 'Function' | 'ListOfExprs' | 'ExprWithAlias'; - -// @beta (undocumented) -export class ExprWithAlias implements Selectable { - constructor(expr: T, alias: string); - add(other: Constant): Add; - add(other: any): Add; - // (undocumented) - alias: string; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - expr: T; - // (undocumented) - exprType: ExprType; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): FirestoreFunction; - // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; - // (undocumented) - selectable: true; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} - -// @beta -export class Field implements Selectable { - add(other: Constant): Add; - add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; - // (undocumented) - fieldName(): string; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): FirestoreFunction; - // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - static of(name: string): Field; - // (undocumented) - static of(path: FieldPath): Field; - // (undocumented) - static of(pipeline: Pipeline, name: string): Field; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; - // (undocumented) - selectable: true; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} - // @public export class FieldPath { constructor(...fieldNames: string[]); isEqual(other: FieldPath): boolean; } -// @beta (undocumented) -export class Fields implements Selectable { - add(other: Constant): Add; - add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; - // (undocumented) - fieldList(): Field[]; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): FirestoreFunction; - // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - // (undocumented) - static of(name: string, ...others: string[]): Fields; - // (undocumented) - static ofAll(): Fields; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; - // (undocumented) - selectable: true; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} - // @public export abstract class FieldValue { abstract isEqual(other: FieldValue): boolean; } -// @beta -export interface FilterCondition { - // (undocumented) - filterable: true; -} - -// @beta -export type FilterExpr = Constant & FilterCondition; - -// @beta (undocumented) -export class FindNearest implements Stage { - // (undocumented) - name: string; -} - -// @beta (undocumented) -export interface FindNearestOptions { - // (undocumented) - distanceField?: string; - // (undocumented) - distanceMeasure: 'euclidean' | 'cosine' | 'dot_product'; - // (undocumented) - field: Field; - // (undocumented) - limit?: number; - // (undocumented) - vectorValue: VectorValue | number[]; -} - // @public export class Firestore { get app(): FirebaseApp; @@ -1072,464 +197,71 @@ export class FirestoreError extends FirebaseError { readonly code: FirestoreErrorCode; readonly message: string; readonly stack?: string; -} - -// @public -export type FirestoreErrorCode = 'cancelled' | 'unknown' | 'invalid-argument' | 'deadline-exceeded' | 'not-found' | 'already-exists' | 'permission-denied' | 'resource-exhausted' | 'failed-precondition' | 'aborted' | 'out-of-range' | 'unimplemented' | 'internal' | 'unavailable' | 'data-loss' | 'unauthenticated'; - -// @beta -export class FirestoreFunction { - constructor(name: string, params: Constant[]); - add(other: Constant): Add; - add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): FirestoreFunction; - // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} - -// @beta -export function genericFunction(name: string, params: Constant[]): FirestoreFunction; - -// @beta (undocumented) -export class GenericStage implements Stage { - constructor(name: string, params: unknown[]); - // (undocumented) - name: string; -} - -// @public -export class GeoPoint { - constructor(latitude: number, longitude: number); - isEqual(other: GeoPoint): boolean; - get latitude(): number; - get longitude(): number; - toJSON(): { - latitude: number; - longitude: number; - }; -} - -// @public -export function getAggregate(query: Query, aggregateSpec: AggregateSpecType): Promise>; - -// @public -export function getCount(query: Query): Promise; -}, AppModelType, DbModelType>>; - -// @public -export function getDoc(reference: DocumentReference): Promise>; - -// @public -export function getDocs(query: Query): Promise>; - -// @public -export function getFirestore(): Firestore; - -// @public -export function getFirestore(app: FirebaseApp): Firestore; - -// @beta -export function getFirestore(databaseId: string): Firestore; - -// @beta -export function getFirestore(app: FirebaseApp, databaseId: string): Firestore; - -// @beta (undocumented) -export class Gt extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function gt(left: Constant, right: Constant): Gt; - -// @beta -export function gt(left: Constant, right: any): Gt; - -// @beta -export function gt(left: string, right: Constant): Gt; - -// @beta -export function gt(left: string, right: any): Gt; - -// @beta (undocumented) -export class Gte extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function gte(left: Constant, right: Constant): Gte; - -// @beta -export function gte(left: Constant, right: any): Gte; - -// @beta -export function gte(left: string, right: Constant): Gte; - -// @beta -export function gte(left: string, right: any): Gte; - -// @public -export function increment(n: number): FieldValue; - -// @public -export function initializeFirestore(app: FirebaseApp, settings: Settings): Firestore; - -// @beta -export function initializeFirestore(app: FirebaseApp, settings: Settings, databaseId?: string): Firestore; - -// @beta (undocumented) -export class IsNan extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant); - // (undocumented) - filterable: true; -} - -// @beta -export function isNan(value: Constant): IsNan; - -// @beta -export function isNan(value: string): IsNan; - -// @beta (undocumented) -export class Like extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, pattern: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function like(left: string, pattern: string): Like; - -// @beta -export function like(left: string, pattern: Constant): Like; - -// @beta -export function like(left: Constant, pattern: string): Like; - -// @beta -export function like(left: Constant, pattern: Constant): Like; - -// @beta (undocumented) -export class Limit implements Stage { - constructor(limit: number); - // (undocumented) - name: string; -} - -// @public -export function limit(limit: number): QueryLimitConstraint; - -// @public -export function limitToLast(limit: number): QueryLimitConstraint; - -// @beta (undocumented) -export class LogicalMaximum extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } - -// @beta -export function logicalMaximum(left: Constant, right: Constant): LogicalMaximum; - -// @beta -export function logicalMaximum(left: Constant, right: any): LogicalMaximum; - -// @beta -export function logicalMaximum(left: string, right: Constant): LogicalMaximum; - -// @beta -export function logicalMaximum(left: string, right: any): LogicalMaximum; - -// @beta (undocumented) -export class LogicalMinimum extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } - -// @beta -export function logicalMinimum(left: Constant, right: Constant): LogicalMinimum; - -// @beta -export function logicalMinimum(left: Constant, right: any): LogicalMinimum; - -// @beta -export function logicalMinimum(left: string, right: Constant): LogicalMinimum; - -// @beta -export function logicalMinimum(left: string, right: any): LogicalMinimum; - -export { LogLevel } - -// @beta (undocumented) -export class Lt extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function lt(left: Constant, right: Constant): Lt; - -// @beta -export function lt(left: Constant, right: any): Lt; - -// @beta -export function lt(left: string, right: Constant): Lt; - -// @beta -export function lt(left: string, right: any): Lt; - -// @beta (undocumented) -export class Lte extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function lte(left: Constant, right: Constant): Lte; - -// @beta -export function lte(left: Constant, right: any): Lte; - -// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Constant" which is marked as @beta -// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Lte" which is marked as @beta -// -// @public -export function lte(left: string, right: Constant): Lte; - -// @beta -export function lte(left: string, right: any): Lte; - -// @beta (undocumented) -export class MapGet extends FirestoreFunction { - constructor(map: Constant, name: string); -} - -// @beta -export function mapGet(mapField: string, subField: string): MapGet; - -// @beta -export function mapGet(mapExpr: Constant, subField: string): MapGet; - -// @beta (undocumented) -export class Maximum extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); - // (undocumented) - accumulator: true; - } - -// @beta -export function maximum(value: Constant): Maximum; - -// @beta -export function maximum(value: string): Maximum; - -// @beta (undocumented) -export class Minimum extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); - // (undocumented) - accumulator: true; - } - -// @beta -export function minimum(value: Constant): Minimum; +} -// @beta -export function minimum(value: string): Minimum; +// @public +export type FirestoreErrorCode = 'cancelled' | 'unknown' | 'invalid-argument' | 'deadline-exceeded' | 'not-found' | 'already-exists' | 'permission-denied' | 'resource-exhausted' | 'failed-precondition' | 'aborted' | 'out-of-range' | 'unimplemented' | 'internal' | 'unavailable' | 'data-loss' | 'unauthenticated'; -// @beta (undocumented) -export class Mod extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } +// @public +export class GeoPoint { + constructor(latitude: number, longitude: number); + isEqual(other: GeoPoint): boolean; + get latitude(): number; + get longitude(): number; + toJSON(): { + latitude: number; + longitude: number; + }; +} -// @beta -export function mod(left: Constant, right: Constant): Mod; +// @public +export function getAggregate(query: Query, aggregateSpec: AggregateSpecType): Promise>; -// @beta -export function mod(left: Constant, right: any): Mod; +// @public +export function getCount(query: Query): Promise; +}, AppModelType, DbModelType>>; -// @beta -export function mod(left: string, right: Constant): Mod; +// @public +export function getDoc(reference: DocumentReference): Promise>; -// @beta -export function mod(left: string, right: any): Mod; +// @public +export function getDocs(query: Query): Promise>; -// @beta (undocumented) -export class Multiply extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } +// @public +export function getFirestore(): Firestore; -// @beta -export function multiply(left: Constant, right: Constant): Multiply; +// @public +export function getFirestore(app: FirebaseApp): Firestore; // @beta -export function multiply(left: Constant, right: any): Multiply; +export function getFirestore(databaseId: string): Firestore; // @beta -export function multiply(left: string, right: Constant): Multiply; +export function getFirestore(app: FirebaseApp, databaseId: string): Firestore; -// @beta -export function multiply(left: string, right: any): Multiply; +// @public +export function increment(n: number): FieldValue; -// @beta (undocumented) -export class Neq extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); - // (undocumented) - filterable: true; - } +// @public +export function initializeFirestore(app: FirebaseApp, settings: Settings): Firestore; // @beta -export function neq(left: Constant, right: Constant): Neq; +export function initializeFirestore(app: FirebaseApp, settings: Settings, databaseId?: string): Firestore; -// @beta -export function neq(left: Constant, right: any): Neq; +// @public +export function limit(limit: number): QueryLimitConstraint; -// @beta -export function neq(left: string, right: Constant): Neq; +// @public +export function limitToLast(limit: number): QueryLimitConstraint; -// @beta -export function neq(left: string, right: any): Neq; +export { LogLevel } // @public export type NestedUpdateFields> = UnionToIntersection<{ [K in keyof T & string]: ChildUpdateFields; }[keyof T & string]>; -// @beta (undocumented) -export class Not extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant); - // (undocumented) - filterable: true; -} - -// @beta -export function not(filter: FilterExpr): Not; - -// @beta -export function notEqAny(element: Constant, others: Constant[]): FirestoreFunction; - -// @beta -export function notEqAny(element: Constant, others: any[]): FirestoreFunction; - -// @beta -export function notEqAny(element: string, others: Constant[]): FirestoreFunction; - -// @beta -export function notEqAny(element: string, others: any[]): FirestoreFunction; - -// @beta (undocumented) -export class Offset implements Stage { - constructor(offset: number); - // (undocumented) - name: string; - } - -// @beta (undocumented) -export class Or extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterExpr[]); - // (undocumented) - filterable: true; -} - // @public export function or(...queryConstraints: QueryFilterConstraint[]): QueryCompositeFilterConstraint; @@ -1539,114 +271,11 @@ export function orderBy(fieldPath: string | FieldPath, directionStr?: OrderByDir // @public export type OrderByDirection = 'desc' | 'asc'; -// @beta -export class Ordering { - constructor(expr: Constant, direction: 'ascending' | 'descending'); - } - // @public export type PartialWithFieldValue = Partial | (T extends Primitive ? T : T extends {} ? { [K in keyof T]?: PartialWithFieldValue | FieldValue; } : never); -// @public -export class Pipeline { - /* Excluded from this release type: _db */ - // Warning: (ae-incompatible-release-tags) The symbol "addFields" is marked as @public, but its signature references "Selectable" which is marked as @beta - addFields(...fields: Selectable[]): Pipeline; - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta - aggregate(...accumulators: AccumulatorTarget[]): Pipeline; - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - aggregate(options: { - accumulators: AccumulatorTarget[]; - groups?: Array; - }): Pipeline; - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta - distinct(...groups: Array): Pipeline; - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta - execute(): Promise>>; - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - // Warning: (ae-incompatible-release-tags) The symbol "findNearest" is marked as @public, but its signature references "FindNearestOptions" which is marked as @beta - // - // (undocumented) - findNearest(options: FindNearestOptions): Pipeline; - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - genericStage(name: string, params: any[]): Pipeline; - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - limit(limit: number): Pipeline; - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - offset(offset: number): Pipeline; - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - // Warning: (ae-incompatible-release-tags) The symbol "select" is marked as @public, but its signature references "Selectable" which is marked as @beta - select(...selections: Array): Pipeline; - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - // Warning: (ae-incompatible-release-tags) The symbol "sort" is marked as @public, but its signature references "Ordering" which is marked as @beta - sort(...orderings: Ordering[]): Pipeline; - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - // (undocumented) - sort(options: { - orderings: Ordering[]; - }): Pipeline; - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "FilterCondition" which is marked as @beta - // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "Constant" which is marked as @beta - where(condition: FilterCondition & Constant): Pipeline; -} - -// Warning: (ae-incompatible-release-tags) The symbol "pipeline" is marked as @public, but its signature references "PipelineSource" which is marked as @beta -// -// @public -export function pipeline(firestore: Firestore): PipelineSource; - -// @public -export function pipeline(query: Query): Pipeline; - -// @beta -export class PipelineResult { - /* Excluded from this release type: _ref */ - /* Excluded from this release type: _fields */ - /* Excluded from this release type: __constructor */ - get createTime(): Timestamp | undefined; - data(): AppModelType | undefined; - get executionTime(): Timestamp; - get(fieldPath: string | FieldPath): any; - get id(): string | undefined; - get ref(): DocumentReference | undefined; - get updateTime(): Timestamp | undefined; -} - -// @beta -export class PipelineSource { - /* Excluded from this release type: _db */ - /* Excluded from this release type: _userDataReader */ - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - /* Excluded from this release type: __constructor */ - // (undocumented) - collection(collectionPath: string): Pipeline; - // (undocumented) - collectionGroup(collectionId: string): Pipeline; - // (undocumented) - database(): Pipeline; - // (undocumented) - documents(docs: DocumentReference[]): Pipeline; -} - // @public export type Primitive = string | number | boolean | undefined | null; @@ -1731,102 +360,9 @@ export class QueryStartAtConstraint extends QueryConstraint { // @public export function refEqual(left: DocumentReference | CollectionReference, right: DocumentReference | CollectionReference): boolean; -// @beta (undocumented) -export class RegexContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, pattern: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function regexContains(left: string, pattern: string): RegexContains; - -// @beta -export function regexContains(left: string, pattern: Constant): RegexContains; - -// @beta -export function regexContains(left: Constant, pattern: string): RegexContains; - -// @beta -export function regexContains(left: Constant, pattern: Constant): RegexContains; - -// @beta (undocumented) -export class RegexMatch extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, pattern: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function regexMatch(left: string, pattern: string): RegexMatch; - -// @beta -export function regexMatch(left: string, pattern: Constant): RegexMatch; - -// @beta -export function regexMatch(left: Constant, pattern: string): RegexMatch; - -// @beta -export function regexMatch(left: Constant, pattern: Constant): RegexMatch; - -// @beta (undocumented) -export class ReplaceAll extends FirestoreFunction { - constructor(value: Constant, find: Constant, replace: Constant); - } - -// @beta -export function replaceAll(value: Constant, find: string, replace: string): ReplaceAll; - -// @beta -export function replaceAll(value: Constant, find: Constant, replace: Constant): ReplaceAll; - -// @beta -export function replaceAll(field: string, find: string, replace: string): ReplaceAll; - -// @beta (undocumented) -export class ReplaceFirst extends FirestoreFunction { - constructor(value: Constant, find: Constant, replace: Constant); - } - -// @beta -export function replaceFirst(value: Constant, find: string, replace: string): ReplaceFirst; - -// @beta -export function replaceFirst(value: Constant, find: Constant, replace: Constant): ReplaceFirst; - -// @beta -export function replaceFirst(field: string, find: string, replace: string): ReplaceFirst; - -// @beta (undocumented) -export class Reverse extends FirestoreFunction { - constructor(value: Constant); - } - -// @beta -export function reverse(expr: Constant): Reverse; - -// @beta -export function reverse(field: string): Reverse; - // @public export function runTransaction(firestore: Firestore, updateFunction: (transaction: Transaction) => Promise, options?: TransactionOptions): Promise; -// @beta (undocumented) -export class Select implements Stage { - constructor(projections: Map); - // (undocumented) - name: string; - } - -// @beta -export interface Selectable { - // (undocumented) - selectable: true; -} - -// @beta -export type SelectableExpr = Constant & Selectable; - // @public export function serverTimestamp(): FieldValue; @@ -1856,19 +392,6 @@ export interface Settings { // @public export function snapshotEqual(left: DocumentSnapshot | QuerySnapshot, right: DocumentSnapshot | QuerySnapshot): boolean; -// @beta (undocumented) -export class Sort implements Stage { - constructor(orders: Ordering[]); - // (undocumented) - name: string; - } - -// @beta (undocumented) -export interface Stage { - // (undocumented) - name: string; -} - // @public export function startAfter(snapshot: DocumentSnapshot): QueryStartAtConstraint; @@ -1881,79 +404,6 @@ export function startAt(snapshot // @public export function startAt(...fieldValues: unknown[]): QueryStartAtConstraint; -// @beta (undocumented) -export class StartsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, prefix: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function startsWith(expr: string, prefix: string): StartsWith; - -// @beta -export function startsWith(expr: string, prefix: Constant): StartsWith; - -// @beta -export function startsWith(expr: Constant, prefix: string): StartsWith; - -// @beta -export function startsWith(expr: Constant, prefix: Constant): StartsWith; - -// @beta (undocumented) -export class StrConcat extends FirestoreFunction { - constructor(first: Constant, rest: Constant[]); - } - -// @beta -export function strConcat(first: string, ...elements: Array): StrConcat; - -// @beta -export function strConcat(first: Constant, ...elements: Array): StrConcat; - -// @beta (undocumented) -export class StrContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, substring: Constant); - // (undocumented) - filterable: true; - } - -// @beta -export function strContains(left: string, substring: string): StrContains; - -// @beta -export function strContains(left: string, substring: Constant): StrContains; - -// @beta -export function strContains(left: Constant, substring: string): StrContains; - -// @beta -export function strContains(left: Constant, substring: Constant): StrContains; - -// @beta (undocumented) -export class Subtract extends FirestoreFunction { - constructor(left: Constant, right: Constant); - } - -// @beta -export function subtract(left: Constant, right: Constant): Subtract; - -// @beta -export function subtract(left: Constant, right: any): Subtract; - -// @beta -export function subtract(left: string, right: Constant): Subtract; - -// @beta -export function subtract(left: string, right: any): Subtract; - -// @beta (undocumented) -export class Sum extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); - // (undocumented) - accumulator: true; - } - // @public export function sum(field: string | FieldPath): AggregateField; @@ -1981,89 +431,6 @@ export class Timestamp { valueOf(): string; } -// @beta (undocumented) -export class TimestampAdd extends FirestoreFunction { - constructor(timestamp: Constant, unit: Constant, amount: Constant); - } - -// @beta -export function timestampAdd(timestamp: Constant, unit: Constant, amount: Constant): TimestampAdd; - -// @beta -export function timestampAdd(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - -// @beta -export function timestampAdd(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - -// @beta (undocumented) -export class TimestampSub extends FirestoreFunction { - constructor(timestamp: Constant, unit: Constant, amount: Constant); - } - -// @beta -export function timestampSub(timestamp: Constant, unit: Constant, amount: Constant): TimestampSub; - -// @beta -export function timestampSub(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - -// @beta -export function timestampSub(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - -// @beta (undocumented) -export class TimestampToUnixMicros extends FirestoreFunction { - constructor(input: Constant); - } - -// @beta -export function timestampToUnixMicros(expr: Constant): TimestampToUnixMicros; - -// @beta -export function timestampToUnixMicros(field: string): TimestampToUnixMicros; - -// @beta (undocumented) -export class TimestampToUnixMillis extends FirestoreFunction { - constructor(input: Constant); - } - -// @beta -export function timestampToUnixMillis(expr: Constant): TimestampToUnixMillis; - -// @beta -export function timestampToUnixMillis(field: string): TimestampToUnixMillis; - -// @beta (undocumented) -export class TimestampToUnixSeconds extends FirestoreFunction { - constructor(input: Constant); - } - -// @beta -export function timestampToUnixSeconds(expr: Constant): TimestampToUnixSeconds; - -// @beta -export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; - -// @beta (undocumented) -export class ToLower extends FirestoreFunction { - constructor(expr: Constant); - } - -// @beta -export function toLower(expr: string): ToLower; - -// @beta -export function toLower(expr: Constant): ToLower; - -// @beta (undocumented) -export class ToUpper extends FirestoreFunction { - constructor(expr: Constant); - } - -// @beta -export function toUpper(expr: string): ToUpper; - -// @beta -export function toUpper(expr: Constant): ToUpper; - // @public export class Transaction { delete(documentRef: DocumentReference): this; @@ -2079,53 +446,9 @@ export interface TransactionOptions { readonly maxAttempts?: number; } -// @beta (undocumented) -export class Trim extends FirestoreFunction { - constructor(expr: Constant); - } - -// @beta -export function trim(expr: string): Trim; - -// @beta -export function trim(expr: Constant): Trim; - // @public export type UnionToIntersection = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never; -// @beta (undocumented) -export class UnixMicrosToTimestamp extends FirestoreFunction { - constructor(input: Constant); - } - -// @beta -export function unixMicrosToTimestamp(expr: Constant): UnixMicrosToTimestamp; - -// @beta -export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; - -// @beta (undocumented) -export class UnixMillisToTimestamp extends FirestoreFunction { - constructor(input: Constant); - } - -// @beta -export function unixMillisToTimestamp(expr: Constant): UnixMillisToTimestamp; - -// @beta -export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; - -// @beta (undocumented) -export class UnixSecondsToTimestamp extends FirestoreFunction { - constructor(input: Constant); - } - -// @beta -export function unixSecondsToTimestamp(expr: Constant): UnixSecondsToTimestamp; - -// @beta -export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; - // @public export type UpdateData = T extends Primitive ? T : T extends {} ? { [K in keyof T]?: UpdateData | FieldValue; @@ -2137,23 +460,9 @@ export function updateDoc(refere // @public export function updateDoc(reference: DocumentReference, field: string | FieldPath, value: unknown, ...moreFieldsAndValues: unknown[]): Promise; -// @public (undocumented) -export function useFluentPipelines(): void; - // @public export function vector(values?: number[]): VectorValue; -// @beta (undocumented) -export class VectorLength extends FirestoreFunction { - constructor(value: Constant); - } - -// @beta -export function vectorLength(expr: Constant): VectorLength; - -// @beta -export function vectorLength(field: string): VectorLength; - // @public export class VectorValue { /* Excluded from this release type: __constructor */ @@ -2161,13 +470,6 @@ export class VectorValue { toArray(): number[]; } -// @beta (undocumented) -export class Where implements Stage { - constructor(condition: FilterCondition & Constant); - // (undocumented) - name: string; -} - // @public export function where(fieldPath: string | FieldPath, opStr: WhereFilterOp, value: unknown): QueryFieldFilterConstraint; @@ -2192,21 +494,5 @@ export class WriteBatch { // @public export function writeBatch(firestore: Firestore): WriteBatch; -// @beta (undocumented) -export class Xor extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterExpr[]); - // (undocumented) - filterable: true; -} - -// @beta -export function xor(left: FilterExpr, ...right: FilterExpr[]): Xor; - - -// Warnings were encountered during analysis: -// -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/index.d.ts:9244:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/index.d.ts:9245:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/index.d.ts:9274:9 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta ``` diff --git a/packages/firestore/externs.json b/packages/firestore/externs.json index f7fbbabeb14..22da710fe3a 100644 --- a/packages/firestore/externs.json +++ b/packages/firestore/externs.json @@ -17,7 +17,9 @@ "packages/app-check-interop-types/index.d.ts", "packages/auth-interop-types/index.d.ts", "packages/firestore/dist/lite/internal.d.ts", + "packages/firestore/dist/lite/internal.pipelines.d.ts", "packages/firestore/dist/internal.d.ts", + "packages/firestore/dist/internal.pipelines.d.ts", "packages/firestore-types/index.d.ts", "packages/firebase/compat/index.d.ts", "packages/component/dist/src/component.d.ts", diff --git a/packages/firestore/lite/index.ts b/packages/firestore/lite/index.ts index d001457ac50..b751f0a8254 100644 --- a/packages/firestore/lite/index.ts +++ b/packages/firestore/lite/index.ts @@ -27,173 +27,6 @@ import { registerFirestore } from './register'; registerFirestore(); -export { PipelineSource } from '../src/lite-api/pipeline-source'; - -export { PipelineResult } from '../src/lite-api/pipeline-result'; - -export { Pipeline } from '../src/lite-api/pipeline'; - -export { - useFluentPipelines, - pipeline, - execute -} from '../src/lite-api/pipeline_impl'; - -export { - Stage, - FindNearestOptions, - AddFields, - Aggregate, - Distinct, - CollectionSource, - CollectionGroupSource, - DatabaseSource, - DocumentsSource, - Where, - FindNearest, - Limit, - Offset, - Select, - Sort, - GenericStage -} from '../src/lite-api/stage'; - -export { - add, - subtract, - multiply, - divide, - mod, - eq, - neq, - lt, - lte, - gt, - gte, - arrayConcat, - arrayContains, - arrayContainsAny, - arrayContainsAll, - arrayLength, - eqAny, - notEqAny, - xor, - cond, - not, - logicalMaximum, - logicalMinimum, - exists, - isNan, - reverse, - replaceFirst, - replaceAll, - byteLength, - charLength, - like, - regexContains, - regexMatch, - strContains, - startsWith, - endsWith, - toLower, - toUpper, - trim, - strConcat, - mapGet, - countAll, - minimum, - maximum, - cosineDistance, - dotProduct, - euclideanDistance, - vectorLength, - unixMicrosToTimestamp, - timestampToUnixMicros, - unixMillisToTimestamp, - timestampToUnixMillis, - unixSecondsToTimestamp, - timestampToUnixSeconds, - timestampAdd, - timestampSub, - genericFunction, - ascending, - descending, - ExprWithAlias, - Field, - Fields, - Constant, - FirestoreFunction, - Add, - Subtract, - Multiply, - Divide, - Mod, - Eq, - Neq, - Lt, - Lte, - Gt, - Gte, - ArrayConcat, - ArrayReverse, - ArrayContains, - ArrayContainsAll, - ArrayContainsAny, - ArrayLength, - ArrayElement, - EqAny, - IsNan, - Exists, - Not, - And, - Or, - Xor, - Cond, - LogicalMaximum, - LogicalMinimum, - Reverse, - ReplaceFirst, - ReplaceAll, - CharLength, - ByteLength, - Like, - RegexContains, - RegexMatch, - StrContains, - StartsWith, - EndsWith, - ToLower, - ToUpper, - Trim, - StrConcat, - MapGet, - Count, - Sum, - Avg, - Minimum, - Maximum, - CosineDistance, - DotProduct, - EuclideanDistance, - VectorLength, - UnixMicrosToTimestamp, - TimestampToUnixMicros, - UnixMillisToTimestamp, - TimestampToUnixMillis, - UnixSecondsToTimestamp, - TimestampToUnixSeconds, - TimestampAdd, - TimestampSub, - Ordering, - ExprType, - AccumulatorTarget, - FilterExpr, - SelectableExpr, - Selectable, - FilterCondition, - Accumulator -} from '../src/lite-api/expressions'; - export { aggregateQuerySnapshotEqual, getCount, diff --git a/packages/firestore/lite/pipelines.ts b/packages/firestore/lite/pipelines.ts new file mode 100644 index 00000000000..f4f87206e21 --- /dev/null +++ b/packages/firestore/lite/pipelines.ts @@ -0,0 +1,215 @@ +/** + * Firestore Lite Pipelines + * + * @remarks Firestore Lite is a small online-only SDK that allows read + * and write access to your Firestore database. All operations connect + * directly to the backend, and `onSnapshot()` APIs are not supported. + * @packageDocumentation + */ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// External exports: ./index +// These external exports will be stripped from the dist/pipelines.d.ts file +// by the prune-dts script, in order to reduce type duplication. However, these +// types need to be exported here to ensure that api-extractor behaves +// correctly. If a type from api.ts is missing from this export, then +// api-extractor may rename it with a suffix `_#`, e.g. `YourType_2`. +export type { + Timestamp, + DocumentReference, + VectorValue, + GeoPoint, + FieldPath, + DocumentData, + Query, + Firestore, + FirestoreDataConverter, + WithFieldValue, + PartialWithFieldValue, + SetOptions, + QueryDocumentSnapshot, + Primitive, + FieldValue +} from './index'; + +export { PipelineSource } from '../src/lite-api/pipeline-source'; + +export { PipelineResult } from '../src/lite-api/pipeline-result'; + +export { Pipeline } from '../src/lite-api/pipeline'; + +export { + useFluentPipelines, + pipeline, + execute +} from '../src/lite-api/pipeline_impl'; + +export { + Stage, + FindNearestOptions, + AddFields, + Aggregate, + Distinct, + CollectionSource, + CollectionGroupSource, + DatabaseSource, + DocumentsSource, + Where, + FindNearest, + Limit, + Offset, + Select, + Sort, + GenericStage +} from '../src/lite-api/stage'; + +export { + add, + subtract, + multiply, + divide, + mod, + eq, + neq, + lt, + lte, + gt, + gte, + arrayConcat, + arrayContains, + arrayContainsAny, + arrayContainsAll, + arrayLength, + eqAny, + notEqAny, + xor, + cond, + not, + logicalMaximum, + logicalMinimum, + exists, + isNan, + reverse, + replaceFirst, + replaceAll, + byteLength, + charLength, + like, + regexContains, + regexMatch, + strContains, + startsWith, + endsWith, + toLower, + toUpper, + trim, + strConcat, + mapGet, + countAll, + minimum, + maximum, + cosineDistance, + dotProduct, + euclideanDistance, + vectorLength, + unixMicrosToTimestamp, + timestampToUnixMicros, + unixMillisToTimestamp, + timestampToUnixMillis, + unixSecondsToTimestamp, + timestampToUnixSeconds, + timestampAdd, + timestampSub, + genericFunction, + ascending, + descending, + ExprWithAlias, + Field, + Fields, + Constant, + FirestoreFunction, + Add, + Subtract, + Multiply, + Divide, + Mod, + Eq, + Neq, + Lt, + Lte, + Gt, + Gte, + ArrayConcat, + ArrayReverse, + ArrayContains, + ArrayContainsAll, + ArrayContainsAny, + ArrayLength, + ArrayElement, + EqAny, + IsNan, + Exists, + Not, + And, + Or, + Xor, + Cond, + LogicalMaximum, + LogicalMinimum, + Reverse, + ReplaceFirst, + ReplaceAll, + CharLength, + ByteLength, + Like, + RegexContains, + RegexMatch, + StrContains, + StartsWith, + EndsWith, + ToLower, + ToUpper, + Trim, + StrConcat, + MapGet, + Count, + Sum, + Avg, + Minimum, + Maximum, + CosineDistance, + DotProduct, + EuclideanDistance, + VectorLength, + UnixMicrosToTimestamp, + TimestampToUnixMicros, + UnixMillisToTimestamp, + TimestampToUnixMillis, + UnixSecondsToTimestamp, + TimestampToUnixSeconds, + TimestampAdd, + TimestampSub, + Ordering, + ExprType, + AccumulatorTarget, + FilterExpr, + SelectableExpr, + Selectable, + FilterCondition, + Accumulator +} from '../src/lite-api/expressions'; diff --git a/packages/firestore/package.json b/packages/firestore/package.json index 4a8d86241ee..e77c1303ba5 100644 --- a/packages/firestore/package.json +++ b/packages/firestore/package.json @@ -47,12 +47,13 @@ "test:travis": "ts-node --compiler-options='{\"module\":\"commonjs\"}' ../../scripts/emulator-testing/firestore-test-runner.ts", "test:minified": "(cd ../../integration/firestore ; yarn test)", "trusted-type-check": "tsec -p tsconfig.json --noEmit", - "api-report:main": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/index.d.ts --rollupDts ./dist/private.d.ts --untrimmedRollupDts ./dist/internal.d.ts --publicDts ./dist/index.d.ts", - "api-report:all-packages": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/all_packages.d.ts --rollupDts ./dist/private.all_packages.d.ts --untrimmedRollupDts ./dist/internal.all_packages.d.ts --publicDts ./dist/all_packages.d.ts", - "api-report:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-pipelines --packageRoot . --typescriptDts ./dist/firestore/src/pipelines.d.ts --rollupDts ./dist/private.pipelines.d.ts --untrimmedRollupDts ./dist/internal.pipelines.d.ts --publicDts ./dist/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", - "api-report:lite": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite --packageRoot . --typescriptDts ./dist/firestore/lite/index.d.ts --rollupDts ./dist/lite/private.d.ts --untrimmedRollupDts ./dist/lite/internal.d.ts --publicDts ./dist/lite/index.d.ts", + "api-report:main": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/index.d.ts --rollupDts ./dist/private.d.ts --untrimmedRollupDts ./dist/internal.d.ts --publicDts ./dist/index.d.ts", + "api-report:all-packages": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/all_packages.d.ts --rollupDts ./dist/private.all_packages.d.ts --untrimmedRollupDts ./dist/internal.all_packages.d.ts --publicDts ./dist/all_packages.d.ts", + "api-report:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-pipelines --packageRoot . --typescriptDts ./dist/firestore/src/pipelines.d.ts --rollupDts ./dist/private.pipelines.d.ts --untrimmedRollupDts ./dist/internal.pipelines.d.ts --publicDts ./dist/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", + "api-report:lite": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite --packageRoot . --typescriptDts ./dist/firestore/lite/index.d.ts --rollupDts ./dist/lite/private.d.ts --untrimmedRollupDts ./dist/lite/internal.d.ts --publicDts ./dist/lite/index.d.ts", + "api-report:lite:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite-pipelines --packageRoot . --typescriptDts ./dist/firestore/lite/pipelines.d.ts --rollupDts ./dist/lite/private.pipelines.d.ts --untrimmedRollupDts ./dist/lite/internal.pipelines.d.ts --publicDts ./dist/lite/pipelines.d.ts", "api-report:api-json": "rm -rf temp && api-extractor run --local --verbose", - "api-report": "run-s --npm-path npm api-report:main api-report:pipelines api-report:lite && yarn api-report:api-json", + "api-report": "run-s --npm-path npm api-report:main api-report:pipelines api-report:lite api-report:lite:pipelines && yarn api-report:api-json", "doc": "api-documenter markdown --input temp --output docs", "typings:public": "node ../../scripts/build/use_typings.js ./dist/all-packages.d.ts" }, @@ -111,11 +112,11 @@ }, "./package.json": "./package.json" }, - "main": "dist/index.node.cjs.js", - "main-esm": "dist/index.node.mjs", + "main": "dist/node-cjs/index.node.cjs.js", + "main-esm": "dist/node-esm/index.node.mjs", "react-native": "dist/index.rn.js", - "browser": "dist/index.esm2017.js", - "module": "dist/index.esm2017.js", + "browser": "dist/browser-esm2017/index.esm2017.js", + "module": "dist/browser-esm2017/index.esm2017.js", "license": "Apache-2.0", "files": [ "dist", diff --git a/packages/firestore/rollup.config.js b/packages/firestore/rollup.config.js index 395c2a88381..666328fc788 100644 --- a/packages/firestore/rollup.config.js +++ b/packages/firestore/rollup.config.js @@ -79,7 +79,10 @@ const allBuilds = [ }, // Node CJS build { - input: ['dist/intermediate/index.node.mjs', 'dist/intermediate/pipelines.node.mjs'], + input: [ + 'dist/intermediate/index.node.mjs', + 'dist/intermediate/pipelines.node.mjs' + ], output: { dir: 'dist/', entryFileNames: '[name].cjs.js', @@ -108,7 +111,10 @@ const allBuilds = [ }, // Node ESM build with build target reporting { - input: ['dist/intermediate/index.node.mjs', 'dist/intermediate/pipelines.node.mjs'], + input: [ + 'dist/intermediate/index.node.mjs', + 'dist/intermediate/pipelines.node.mjs' + ], output: { dir: 'dist/', entryFileNames: '[name].mjs', @@ -137,10 +143,7 @@ const allBuilds = [ format: 'es', sourcemap: true }, - plugins: [ - alias(util.generateAliasConfig('browser')), - ...browserPlugins - ], + plugins: [alias(util.generateAliasConfig('browser')), ...browserPlugins], external: util.resolveBrowserExterns, treeshake: { moduleSideEffects: false @@ -190,7 +193,7 @@ const allBuilds = [ }, // RN build { - input: ['./src/index.rn.ts', './src/pipelines.rn.ts',], + input: ['./src/index.rn.ts', './src/pipelines.rn.ts'], output: { dir: 'dist/', entryFileNames: '[name].js', diff --git a/packages/firestore/rollup.config.lite.js b/packages/firestore/rollup.config.lite.js index 25209966fe8..4ad08fb754e 100644 --- a/packages/firestore/rollup.config.lite.js +++ b/packages/firestore/rollup.config.lite.js @@ -56,9 +56,11 @@ const allBuilds = [ // this is an intermediate build used to generate the actual esm and cjs builds // which add build target reporting { - input: './lite/index.ts', + input: ['./lite/index.ts', './lite/pipelines.ts'], output: { - file: path.resolve('./lite', pkg['main-esm']), + dir: 'dist/intermediate/lite/', + entryFileNames: '[name].node.mjs', + chunkFileNames: 'common-[hash].node.mjs', format: 'es', sourcemap: true }, @@ -77,9 +79,14 @@ const allBuilds = [ }, // Node CJS build { - input: path.resolve('./lite', pkg['main-esm']), + input: [ + 'dist/intermediate/lite/index.node.mjs', + 'dist/intermediate/lite/pipelines.node.mjs' + ], output: { - file: path.resolve('./lite', pkg.main), + dir: 'dist/lite/', + entryFileNames: '[name].cjs.js', + chunkFileNames: 'common-[hash].node.cjs.js', format: 'cjs', sourcemap: true }, @@ -102,9 +109,14 @@ const allBuilds = [ }, // Node ESM build { - input: path.resolve('./lite', pkg['main-esm']), + input: [ + 'dist/intermediate/lite/index.node.mjs', + 'dist/intermediate/lite/pipelines.node.mjs' + ], output: { - file: path.resolve('./lite', pkg['main-esm']), + dir: 'dist/lite/', + entryFileNames: '[name].mjs', + chunkFileNames: 'common-[hash].node.mjs', format: 'es', sourcemap: true }, @@ -121,9 +133,11 @@ const allBuilds = [ // this is an intermediate build used to generate the actual esm and cjs builds // which add build target reporting { - input: './lite/index.ts', + input: ['./lite/index.ts', './lite/pipelines.ts'], output: { - file: path.resolve('./lite', pkg.browser), + dir: 'dist/intermediate/lite/', + entryFileNames: '[name].browser.js', + chunkFileNames: 'common-[hash].browser.js', format: 'es', sourcemap: true }, @@ -142,10 +156,15 @@ const allBuilds = [ }, // Convert es2017 build to CJS { - input: path.resolve('./lite', pkg.browser), + input: [ + 'dist/intermediate/lite/index.browser.js', + 'dist/intermediate/lite/pipelines.browser.js' + ], output: [ { - file: './dist/lite/index.cjs.js', + dir: 'dist/lite/', + entryFileNames: '[name].cjs.js', + chunkFileNames: 'common-[hash].cjs.js', format: 'es', sourcemap: true } @@ -161,10 +180,15 @@ const allBuilds = [ }, // Browser es2017 build { - input: path.resolve('./lite', pkg.browser), + input: [ + 'dist/intermediate/lite/index.browser.js', + 'dist/intermediate/lite/pipelines.browser.js' + ], output: [ { - file: path.resolve('./lite', pkg.browser), + dir: 'dist/lite/', + entryFileNames: '[name].esm2017.js', + chunkFileNames: 'common-[hash].esm2017.js', format: 'es', sourcemap: true } @@ -180,9 +204,11 @@ const allBuilds = [ }, // RN build { - input: './lite/index.ts', + input: ['./lite/index.ts', './lite/pipelines.ts'], output: { - file: path.resolve('./lite', pkg['react-native']), + dir: 'dist/lite/', + entryFileNames: '[name].rn.esm2017.js', + chunkFileNames: 'common-[hash].rn.esm2017.js', format: 'es', sourcemap: true }, diff --git a/packages/firestore/rollup.shared.js b/packages/firestore/rollup.shared.js index 6443f917a7b..1b33ddf0b1b 100644 --- a/packages/firestore/rollup.shared.js +++ b/packages/firestore/rollup.shared.js @@ -108,10 +108,6 @@ const publicIdentifiers = extractPublicIdentifiers(externsPaths); // manually add `_delegate` because we don't have typings for the compat package publicIdentifiers.add('_delegate'); - -console.log(`==== publicIdentifiers`) -console.log(JSON.stringify(publicIdentifiers, null, 2)) - /** * Transformers that remove calls to `debugAssert` and messages for 'fail` and * `hardAssert`. diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index becdab092c1..d5de1e25b34 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -174,7 +174,7 @@ export { TimestampToUnixSeconds, TimestampAdd, TimestampSub, - Ordering, + Ordering } from './lite-api/expressions'; export type { From db00e407beea93564b07d88246e2516613b4021d Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:55:22 -0700 Subject: [PATCH 03/75] Fix issue with external exports --- .../firestore-lite-pipelines.api.md | 139 ++---------------- packages/firestore/package.json | 2 +- 2 files changed, 15 insertions(+), 126 deletions(-) diff --git a/common/api-review/firestore-lite-pipelines.api.md b/common/api-review/firestore-lite-pipelines.api.md index 73432fc2965..aea9018ae4c 100644 --- a/common/api-review/firestore-lite-pipelines.api.md +++ b/common/api-review/firestore-lite-pipelines.api.md @@ -277,13 +277,17 @@ export class Constant { static of(value: boolean): Constant; static of(value: null): Constant; static of(value: undefined): Constant; + // Warning: (ae-forgotten-export) The symbol "GeoPoint" needs to be exported by the entry point pipelines.d.ts static of(value: GeoPoint): Constant; + // Warning: (ae-forgotten-export) The symbol "Timestamp" needs to be exported by the entry point pipelines.d.ts static of(value: Timestamp): Constant; static of(value: Date): Constant; static of(value: Uint8Array): Constant; + // Warning: (ae-forgotten-export) The symbol "DocumentReference" needs to be exported by the entry point pipelines.d.ts static of(value: DocumentReference): Constant; static of(value: any[]): Constant; static of(value: Map): Constant; + // Warning: (ae-forgotten-export) The symbol "VectorValue" needs to be exported by the entry point pipelines.d.ts static of(value: VectorValue): Constant; regexContains(pattern: string): RegexContains; regexContains(pattern: Constant): RegexContains; @@ -385,23 +389,6 @@ export function divide(left: string, right: Constant): Divide; // @beta export function divide(left: string, right: any): Divide; -// @public -export interface DocumentData { - [field: string]: any; -} - -// @public -export class DocumentReference { - readonly converter: FirestoreDataConverter | null; - readonly firestore: Firestore; - get id(): string; - get parent(): Query; - get path(): string; - readonly type = "document"; - withConverter(converter: FirestoreDataConverter): DocumentReference; - withConverter(converter: null): DocumentReference; -} - // @beta (undocumented) export class DocumentsSource implements Stage { constructor(docPaths: string[]); @@ -718,6 +705,8 @@ export class Field implements Selectable { // (undocumented) notEqAny(...others: any[]): FirestoreFunction; static of(name: string): Field; + // Warning: (ae-forgotten-export) The symbol "FieldPath" needs to be exported by the entry point pipelines.d.ts + // // (undocumented) static of(path: FieldPath): Field; // (undocumented) @@ -757,12 +746,6 @@ export class Field implements Selectable { vectorLength(): VectorLength; } -// @public -export class FieldPath { - constructor(...fieldNames: string[]); - isEqual(other: FieldPath): boolean; -} - // @beta (undocumented) export class Fields implements Selectable { add(other: Constant): Add; @@ -875,11 +858,6 @@ export class Fields implements Selectable { vectorLength(): VectorLength; } -// @public -export abstract class FieldValue { - abstract isEqual(other: FieldValue): boolean; -} - // @beta export interface FilterCondition { // (undocumented) @@ -909,20 +887,6 @@ export interface FindNearestOptions { vectorValue: VectorValue | number[]; } -// @public -export class Firestore { - get app(): FirebaseApp; - toJSON(): object; - type: 'firestore-lite' | 'firestore'; -} - -// @public -export interface FirestoreDataConverter { - fromFirestore(snapshot: QueryDocumentSnapshot): AppModelType; - toFirestore(modelObject: WithFieldValue): WithFieldValue; - toFirestore(modelObject: PartialWithFieldValue, options: SetOptions): PartialWithFieldValue; -} - // @beta export class FirestoreFunction { constructor(name: string, params: Constant[]); @@ -1038,18 +1002,6 @@ export class GenericStage implements Stage { name: string; } -// @public -export class GeoPoint { - constructor(latitude: number, longitude: number); - isEqual(other: GeoPoint): boolean; - get latitude(): number; - get longitude(): number; - toJSON(): { - latitude: number; - longitude: number; - }; -} - // @beta (undocumented) export class Gt extends FirestoreFunction implements FilterCondition { constructor(left: Constant, right: Constant); @@ -1333,11 +1285,8 @@ export class Ordering { constructor(expr: Constant, direction: 'ascending' | 'descending'); } -// @public -export type PartialWithFieldValue = Partial | (T extends Primitive ? T : T extends {} ? { - [K in keyof T]?: PartialWithFieldValue | FieldValue; -} : never); - +// Warning: (ae-forgotten-export) The symbol "DocumentData" needs to be exported by the entry point pipelines.d.ts +// // @public export class Pipeline { /* Excluded from this release type: _db */ @@ -1397,11 +1346,14 @@ export class Pipeline { where(condition: FilterCondition & Constant): Pipeline; } +// Warning: (ae-forgotten-export) The symbol "Firestore" needs to be exported by the entry point pipelines.d.ts // Warning: (ae-incompatible-release-tags) The symbol "pipeline" is marked as @public, but its signature references "PipelineSource" which is marked as @beta // // @public export function pipeline(firestore: Firestore): PipelineSource; +// Warning: (ae-forgotten-export) The symbol "Query" needs to be exported by the entry point pipelines.d.ts +// // @public export function pipeline(query: Query): Pipeline; @@ -1436,29 +1388,6 @@ export class PipelineSource { documents(docs: DocumentReference[]): Pipeline; } -// @public -export type Primitive = string | number | boolean | undefined | null; - -// @public -export class Query { - protected constructor(); - readonly converter: FirestoreDataConverter | null; - readonly firestore: Firestore; - readonly type: 'query' | 'collection'; - withConverter(converter: null): Query; - withConverter(converter: FirestoreDataConverter): Query; -} - -// @public -export class QueryDocumentSnapshot { - // @override - data(): AppModelType; - exists(): this is QueryDocumentSnapshot; - get(fieldPath: string | FieldPath); - get id(): string; - get ref(): DocumentReference; -} - // @beta (undocumented) export class RegexContains extends FirestoreFunction implements FilterCondition { constructor(expr: Constant, pattern: Constant); @@ -1552,13 +1481,6 @@ export interface Selectable { // @beta export type SelectableExpr = Constant & Selectable; -// @public -export type SetOptions = { - readonly merge?: boolean; -} | { - readonly mergeFields?: Array; -}; - // @beta (undocumented) export class Sort implements Stage { constructor(orders: Ordering[]); @@ -1645,27 +1567,6 @@ export class Sum extends FirestoreFunction implements Accumulator { accumulator: true; } -// @public -export class Timestamp { - constructor( - seconds: number, - nanoseconds: number); - static fromDate(date: Date): Timestamp; - static fromMillis(milliseconds: number): Timestamp; - isEqual(other: Timestamp): boolean; - readonly nanoseconds: number; - static now(): Timestamp; - readonly seconds: number; - toDate(): Date; - toJSON(): { - seconds: number; - nanoseconds: number; - }; - toMillis(): number; - toString(): string; - valueOf(): string; -} - // @beta (undocumented) export class TimestampAdd extends FirestoreFunction { constructor(timestamp: Constant, unit: Constant, amount: Constant); @@ -1807,13 +1708,6 @@ export function vectorLength(expr: Constant): VectorLength; // @beta export function vectorLength(field: string): VectorLength; -// @public -export class VectorValue { - /* Excluded from this release type: __constructor */ - isEqual(other: VectorValue): boolean; - toArray(): number[]; -} - // @beta (undocumented) export class Where implements Stage { constructor(condition: FilterCondition & Constant); @@ -1821,11 +1715,6 @@ export class Where implements Stage { name: string; } -// @public -export type WithFieldValue = T | (T extends Primitive ? T : T extends {} ? { - [K in keyof T]: WithFieldValue | FieldValue; -} : never); - // @beta (undocumented) export class Xor extends FirestoreFunction implements FilterCondition { constructor(conditions: FilterExpr[]); @@ -1839,8 +1728,8 @@ export function xor(left: FilterExpr, ...right: FilterExpr[]): Xor; // Warnings were encountered during analysis: // -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:8518:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:8519:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:8548:9 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:8118:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:8119:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:8148:9 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta ``` diff --git a/packages/firestore/package.json b/packages/firestore/package.json index e77c1303ba5..1e37ef43ab2 100644 --- a/packages/firestore/package.json +++ b/packages/firestore/package.json @@ -51,7 +51,7 @@ "api-report:all-packages": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/all_packages.d.ts --rollupDts ./dist/private.all_packages.d.ts --untrimmedRollupDts ./dist/internal.all_packages.d.ts --publicDts ./dist/all_packages.d.ts", "api-report:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-pipelines --packageRoot . --typescriptDts ./dist/firestore/src/pipelines.d.ts --rollupDts ./dist/private.pipelines.d.ts --untrimmedRollupDts ./dist/internal.pipelines.d.ts --publicDts ./dist/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", "api-report:lite": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite --packageRoot . --typescriptDts ./dist/firestore/lite/index.d.ts --rollupDts ./dist/lite/private.d.ts --untrimmedRollupDts ./dist/lite/internal.d.ts --publicDts ./dist/lite/index.d.ts", - "api-report:lite:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite-pipelines --packageRoot . --typescriptDts ./dist/firestore/lite/pipelines.d.ts --rollupDts ./dist/lite/private.pipelines.d.ts --untrimmedRollupDts ./dist/lite/internal.pipelines.d.ts --publicDts ./dist/lite/pipelines.d.ts", + "api-report:lite:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite-pipelines --packageRoot . --typescriptDts ./dist/firestore/lite/pipelines.d.ts --rollupDts ./dist/lite/private.pipelines.d.ts --untrimmedRollupDts ./dist/lite/internal.pipelines.d.ts --publicDts ./dist/lite/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", "api-report:api-json": "rm -rf temp && api-extractor run --local --verbose", "api-report": "run-s --npm-path npm api-report:main api-report:pipelines api-report:lite api-report:lite:pipelines && yarn api-report:api-json", "doc": "api-documenter markdown --input temp --output docs", From de97518cb78e0d73a5210f454e9e626c521e965f Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 20 Dec 2024 13:37:19 -0700 Subject: [PATCH 04/75] Refactor to support multiple entry points for the lite SDK. Fixes import issues and makes code organization across /pipelines and /lite/pipeliens --- packages/firestore/lite/pipelines/package.json | 14 ++++++++++++++ .../firestore/lite/{ => pipelines}/pipelines.ts | 14 +++++++------- packages/firestore/package.json | 8 ++++---- .../firestore/{src => pipelines}/pipelines.node.ts | 2 +- .../firestore/{src => pipelines}/pipelines.rn.ts | 2 +- packages/firestore/{src => pipelines}/pipelines.ts | 4 ++-- packages/firestore/rollup.config.js | 7 +++---- packages/firestore/rollup.config.lite.js | 6 +++--- .../test/integration/util/firebase_export.ts | 2 +- 9 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 packages/firestore/lite/pipelines/package.json rename packages/firestore/lite/{ => pipelines}/pipelines.ts (91%) rename packages/firestore/{src => pipelines}/pipelines.node.ts (94%) rename packages/firestore/{src => pipelines}/pipelines.rn.ts (94%) rename packages/firestore/{src => pipelines}/pipelines.ts (95%) diff --git a/packages/firestore/lite/pipelines/package.json b/packages/firestore/lite/pipelines/package.json new file mode 100644 index 00000000000..349e25e3ac3 --- /dev/null +++ b/packages/firestore/lite/pipelines/package.json @@ -0,0 +1,14 @@ +{ + "name": "@firebase/firestore-lite-pipelines", + "description": "Pipelines for the lite Firestore SDK", + "main": "../../dist/lite/pipelines.node.cjs.js", + "main-esm": "../../dist/lite/pipelines.node.mjs", + "module": "../../dist/lite/pipelines.browser.esm2017.js", + "browser": "../../dist/lite/pipelines.browser.esm2017.js", + "react-native": "../../dist/lite/pipelines.rn.esm2017.js", + "typings": "../../dist/lite/pipelines.d.ts", + "private": true, + "engines": { + "node": ">=18.0.0" + } +} diff --git a/packages/firestore/lite/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts similarity index 91% rename from packages/firestore/lite/pipelines.ts rename to packages/firestore/lite/pipelines/pipelines.ts index f4f87206e21..52c059055d9 100644 --- a/packages/firestore/lite/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -45,19 +45,19 @@ export type { QueryDocumentSnapshot, Primitive, FieldValue -} from './index'; +} from '../index'; -export { PipelineSource } from '../src/lite-api/pipeline-source'; +export { PipelineSource } from '../../src/lite-api/pipeline-source'; -export { PipelineResult } from '../src/lite-api/pipeline-result'; +export { PipelineResult } from '../../src/lite-api/pipeline-result'; -export { Pipeline } from '../src/lite-api/pipeline'; +export { Pipeline } from '../../src/lite-api/pipeline'; export { useFluentPipelines, pipeline, execute -} from '../src/lite-api/pipeline_impl'; +} from '../../src/lite-api/pipeline_impl'; export { Stage, @@ -76,7 +76,7 @@ export { Select, Sort, GenericStage -} from '../src/lite-api/stage'; +} from '../../src/lite-api/stage'; export { add, @@ -212,4 +212,4 @@ export { Selectable, FilterCondition, Accumulator -} from '../src/lite-api/expressions'; +} from '../../src/lite-api/expressions'; diff --git a/packages/firestore/package.json b/packages/firestore/package.json index 1e37ef43ab2..72504a9f729 100644 --- a/packages/firestore/package.json +++ b/packages/firestore/package.json @@ -49,11 +49,11 @@ "trusted-type-check": "tsec -p tsconfig.json --noEmit", "api-report:main": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/index.d.ts --rollupDts ./dist/private.d.ts --untrimmedRollupDts ./dist/internal.d.ts --publicDts ./dist/index.d.ts", "api-report:all-packages": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/all_packages.d.ts --rollupDts ./dist/private.all_packages.d.ts --untrimmedRollupDts ./dist/internal.all_packages.d.ts --publicDts ./dist/all_packages.d.ts", - "api-report:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-pipelines --packageRoot . --typescriptDts ./dist/firestore/src/pipelines.d.ts --rollupDts ./dist/private.pipelines.d.ts --untrimmedRollupDts ./dist/internal.pipelines.d.ts --publicDts ./dist/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", + "api-report:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-pipelines --packageRoot . --typescriptDts ./dist/firestore/pipelines/pipelines.d.ts --rollupDts ./dist/private.pipelines.d.ts --untrimmedRollupDts ./dist/internal.pipelines.d.ts --publicDts ./dist/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", "api-report:lite": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite --packageRoot . --typescriptDts ./dist/firestore/lite/index.d.ts --rollupDts ./dist/lite/private.d.ts --untrimmedRollupDts ./dist/lite/internal.d.ts --publicDts ./dist/lite/index.d.ts", - "api-report:lite:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite-pipelines --packageRoot . --typescriptDts ./dist/firestore/lite/pipelines.d.ts --rollupDts ./dist/lite/private.pipelines.d.ts --untrimmedRollupDts ./dist/lite/internal.pipelines.d.ts --publicDts ./dist/lite/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", + "api-report:lite:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite-pipelines --packageRoot . --typescriptDts ./dist/firestore/lite/pipelines/pipelines.d.ts --rollupDts ./dist/lite/private.pipelines.d.ts --untrimmedRollupDts ./dist/lite/internal.pipelines.d.ts --publicDts ./dist/lite/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", "api-report:api-json": "rm -rf temp && api-extractor run --local --verbose", - "api-report": "run-s --npm-path npm api-report:main api-report:pipelines api-report:lite api-report:lite:pipelines && yarn api-report:api-json", + "api-report": "run-s --npm-path npm api-report:main api-report:pipelines api-report:all-packages api-report:lite api-report:lite:pipelines && yarn api-report:api-json", "doc": "api-documenter markdown --input temp --output docs", "typings:public": "node ../../scripts/build/use_typings.js ./dist/all-packages.d.ts" }, @@ -164,7 +164,7 @@ "bugs": { "url": "https://github.com/firebase/firebase-js-sdk/issues" }, - "types": "dist/all_packages.d.ts", + "types": "dist/index.d.ts", "nyc": { "extension": [ ".ts" diff --git a/packages/firestore/src/pipelines.node.ts b/packages/firestore/pipelines/pipelines.node.ts similarity index 94% rename from packages/firestore/src/pipelines.node.ts rename to packages/firestore/pipelines/pipelines.node.ts index 411006f56a1..fc0e91de0fc 100644 --- a/packages/firestore/src/pipelines.node.ts +++ b/packages/firestore/pipelines/pipelines.node.ts @@ -15,4 +15,4 @@ * limitations under the License. */ -export * from './api_pipelines'; +export * from '../src/api_pipelines'; diff --git a/packages/firestore/src/pipelines.rn.ts b/packages/firestore/pipelines/pipelines.rn.ts similarity index 94% rename from packages/firestore/src/pipelines.rn.ts rename to packages/firestore/pipelines/pipelines.rn.ts index f53cc1a0656..d5d4597190d 100644 --- a/packages/firestore/src/pipelines.rn.ts +++ b/packages/firestore/pipelines/pipelines.rn.ts @@ -15,4 +15,4 @@ * limitations under the License. */ -export * from './api_pipelines'; +export * from '../src/api_pipelines'; diff --git a/packages/firestore/src/pipelines.ts b/packages/firestore/pipelines/pipelines.ts similarity index 95% rename from packages/firestore/src/pipelines.ts rename to packages/firestore/pipelines/pipelines.ts index 22d29e03748..478535e2a16 100644 --- a/packages/firestore/src/pipelines.ts +++ b/packages/firestore/pipelines/pipelines.ts @@ -45,6 +45,6 @@ export type { Primitive, FieldValue, SnapshotMetadata -} from './api'; +} from '../src/api'; -export * from './api_pipelines'; +export * from '../src/api_pipelines'; diff --git a/packages/firestore/rollup.config.js b/packages/firestore/rollup.config.js index 666328fc788..cac0a9c741b 100644 --- a/packages/firestore/rollup.config.js +++ b/packages/firestore/rollup.config.js @@ -51,7 +51,6 @@ const browserPlugins = [ cacheDir: tmp.dirSync(), abortOnError: true, transformers: [util.removeAssertAndPrefixInternalTransformer] - //transformers: [util.removeAssertTransformer] }), json({ preferConst: true }), terser(util.manglePrivatePropertiesOptions) @@ -62,7 +61,7 @@ const allBuilds = [ // this is an intermediate build used to generate the actual esm and cjs builds // which add build target reporting { - input: ['./src/index.node.ts', './src/pipelines.node.ts'], + input: ['./src/index.node.ts', './pipelines/pipelines.node.ts'], output: { dir: 'dist/intermediate', entryFileNames: '[name].mjs', @@ -135,7 +134,7 @@ const allBuilds = [ // this is an intermediate build used to generate the actual esm and cjs builds // which add build target reporting { - input: ['./src/index.ts', './src/pipelines.ts'], + input: ['./src/index.ts', './pipelines/pipelines.ts'], output: { dir: 'dist/intermediate', entryFileNames: '[name].js', @@ -193,7 +192,7 @@ const allBuilds = [ }, // RN build { - input: ['./src/index.rn.ts', './src/pipelines.rn.ts'], + input: ['./src/index.rn.ts', './pipelines/pipelines.rn.ts'], output: { dir: 'dist/', entryFileNames: '[name].js', diff --git a/packages/firestore/rollup.config.lite.js b/packages/firestore/rollup.config.lite.js index 4ad08fb754e..2c7707c3ba0 100644 --- a/packages/firestore/rollup.config.lite.js +++ b/packages/firestore/rollup.config.lite.js @@ -56,7 +56,7 @@ const allBuilds = [ // this is an intermediate build used to generate the actual esm and cjs builds // which add build target reporting { - input: ['./lite/index.ts', './lite/pipelines.ts'], + input: ['./lite/index.ts', './lite/pipelines/pipelines.ts'], output: { dir: 'dist/intermediate/lite/', entryFileNames: '[name].node.mjs', @@ -133,7 +133,7 @@ const allBuilds = [ // this is an intermediate build used to generate the actual esm and cjs builds // which add build target reporting { - input: ['./lite/index.ts', './lite/pipelines.ts'], + input: ['./lite/index.ts', './lite/pipelines/pipelines.ts'], output: { dir: 'dist/intermediate/lite/', entryFileNames: '[name].browser.js', @@ -204,7 +204,7 @@ const allBuilds = [ }, // RN build { - input: ['./lite/index.ts', './lite/pipelines.ts'], + input: ['./lite/index.ts', './lite/pipelines/pipelines.ts'], output: { dir: 'dist/lite/', entryFileNames: '[name].rn.esm2017.js', diff --git a/packages/firestore/test/integration/util/firebase_export.ts b/packages/firestore/test/integration/util/firebase_export.ts index d986cf49d74..a6739dfe72f 100644 --- a/packages/firestore/test/integration/util/firebase_export.ts +++ b/packages/firestore/test/integration/util/firebase_export.ts @@ -51,5 +51,5 @@ export function newTestFirestore( } export * from '../../../src'; -export * from '../../../src/pipelines'; +export * from '../../../pipelines/pipelines'; export { PrivateSettings }; From 9c373ece5aed0b51869eb95ca9f19d15fb526656 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:44:06 -0700 Subject: [PATCH 05/75] Type and comment cleanup --- packages/firestore/src/core/pipeline-util.ts | 2 +- .../firestore/src/lite-api/expressions.ts | 74 +++++++++---------- packages/firestore/src/lite-api/pipeline.ts | 2 +- packages/firestore/src/lite-api/stage.ts | 2 +- 4 files changed, 37 insertions(+), 43 deletions(-) diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index 38c291a4710..ed5f1c6a9ea 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -174,7 +174,7 @@ export function isFirestoreValue(obj: any): obj is ProtoValue { export function toPipelineFilterCondition( f: FilterInternal -): FilterCondition & Expr { +): FilterCondition { if (f instanceof FieldFilterInternal) { const field = Field.of(f.field.toString()); if (isNanValue(f.value)) { diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 3ec68601e9e..7d0a7bcf371 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -48,7 +48,7 @@ import { VectorValue } from './vector_value'; * * An interface that represents a selectable expression. */ -export interface Selectable { +export interface Selectable extends Expr { selectable: true; } @@ -57,7 +57,7 @@ export interface Selectable { * * An interface that represents a filter condition. */ -export interface FilterCondition { +export interface FilterCondition extends Expr { filterable: true; } @@ -66,7 +66,7 @@ export interface FilterCondition { * * An interface that represents an accumulator. */ -export interface Accumulator { +export interface Accumulator extends Expr { accumulator: true; /** * @private @@ -80,21 +80,7 @@ export interface Accumulator { * * An accumulator target, which is an expression with an alias that also implements the Accumulator interface. */ -export type AccumulatorTarget = ExprWithAlias; - -/** - * @beta - * - * A filter expression, which is an expression that also implements the FilterCondition interface. - */ -export type FilterExpr = Expr & FilterCondition; - -/** - * @beta - * - * A selectable expression, which is an expression that also implements the Selectable interface. - */ -export type SelectableExpr = Expr & Selectable; +export type AccumulatorTarget = ExprWithAlias; /** * @beta @@ -126,6 +112,8 @@ export type ExprType = * method calls to create complex expressions. */ export abstract class Expr implements ProtoSerializable, UserData { + abstract exprType: ExprType; + /** * Creates an expression that adds this expression to another expression. * @@ -666,21 +654,21 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param arrays The array expressions to concatenate. * @return A new `Expr` representing the concatenated array. */ - arrayConcat(arrays: Expr[]): ArrayConcat; + arrayConcat(...arrays: Expr[]): ArrayConcat; /** - * Creates an expression that concatenates an array expression with one or more other arrays. + * Creates an expression that concatenates an array with one or more other arrays. * * ```typescript * // Combine the 'tags' array with a new array and an array field * Field.of("tags").arrayConcat(Arrays.asList("newTag1", "newTag2"), Field.of("otherTag")); * ``` * - * @param arrays The array expressions or values to concatenate. - * @return A new `Expr` representing the concatenated array. + * @param arrays The arrays to concatenate. + * @return A new `Expr` representing the concatenated arrays. */ - arrayConcat(arrays: any[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat { + arrayConcat(...arrays: any[][]): ArrayConcat; + arrayConcat(...arrays: any[]): ArrayConcat { const exprValues = arrays.map(value => value instanceof Expr ? value : Constant.of(value) ); @@ -1839,7 +1827,7 @@ export class ExprWithAlias extends Expr implements Selectable { exprType: ExprType = 'ExprWithAlias'; selectable = true as const; - constructor(public expr: T, public alias: string) { + constructor(readonly expr: T, readonly alias: string) { super(); } @@ -2557,7 +2545,7 @@ export class Not extends FirestoreFunction implements FilterCondition { * @beta */ export class And extends FirestoreFunction implements FilterCondition { - constructor(private conditions: FilterExpr[]) { + constructor(private conditions: FilterCondition[]) { super('and', conditions); } @@ -2568,7 +2556,7 @@ export class And extends FirestoreFunction implements FilterCondition { * @beta */ export class Or extends FirestoreFunction implements FilterCondition { - constructor(private conditions: FilterExpr[]) { + constructor(private conditions: FilterCondition[]) { super('or', conditions); } filterable = true as const; @@ -2578,7 +2566,7 @@ export class Or extends FirestoreFunction implements FilterCondition { * @beta */ export class Xor extends FirestoreFunction implements FilterCondition { - constructor(private conditions: FilterExpr[]) { + constructor(private conditions: FilterCondition[]) { super('xor', conditions); } filterable = true as const; @@ -2587,9 +2575,9 @@ export class Xor extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class Cond extends FirestoreFunction implements FilterCondition { +export class Cond extends FirestoreFunction { constructor( - private condition: FilterExpr, + private condition: FilterCondition, private thenExpr: Expr, private elseExpr: Expr ) { @@ -4321,8 +4309,8 @@ export function arrayContainsAny( * Creates an expression that checks if an array expression contains all the specified elements. * * ```typescript - * // Check if the 'tags' array contains both of the values from field 'tag1', 'tag2' and "tag3" - * arrayContainsAll(Field.of("tags"), [Field.of("tag1"), "SciFi", "Adventure"]); + * // Check if the "tags" array contains all of the values: "SciFi", "Adventure", and the value from field "tag1" + * arrayContainsAll(Field.of("tags"), [Field.of("tag1"), Constant.of("SciFi"), Constant.of("Adventure")]); * ``` * * @param array The array expression to check. @@ -4337,7 +4325,7 @@ export function arrayContainsAll(array: Expr, values: Expr[]): ArrayContainsAll; * Creates an expression that checks if an array expression contains all the specified elements. * * ```typescript - * // Check if the 'tags' array contains both of the values from field 'tag1', 'tag2' and "tag3" + * // Check if the "tags" array contains all of the values: "SciFi", "Adventure", and the value from field "tag1" * arrayContainsAll(Field.of("tags"), [Field.of("tag1"), "SciFi", "Adventure"]); * ``` * @@ -4583,7 +4571,7 @@ export function notEqAny(element: Expr | string, others: any[]): NotEqAny { * @param right Additional filter conditions to 'XOR' together. * @return A new {@code Expr} representing the logical 'XOR' operation. */ -export function xor(left: FilterExpr, ...right: FilterExpr[]): Xor { +export function xor(left: FilterCondition, ...right: FilterCondition[]): Xor { return new Xor([left, ...right]); } @@ -4605,7 +4593,7 @@ export function xor(left: FilterExpr, ...right: FilterExpr[]): Xor { * @return A new {@code Expr} representing the conditional expression. */ export function cond( - condition: FilterExpr, + condition: FilterCondition, thenExpr: Expr, elseExpr: Expr ): Cond { @@ -4625,7 +4613,7 @@ export function cond( * @param filter The filter condition to negate. * @return A new {@code Expr} representing the negated filter condition. */ -export function not(filter: FilterExpr): Not { +export function not(filter: FilterCondition): Not { return new Not(filter); } @@ -6691,7 +6679,10 @@ export function genericFunction( * @param right Additional filter conditions to 'AND' together. * @return A new {@code Expr} representing the logical 'AND' operation. */ -export function andFunction(left: FilterExpr, ...right: FilterExpr[]): And { +export function andFunction( + left: FilterCondition, + ...right: FilterCondition[] +): And { return new And([left, ...right]); } @@ -6710,7 +6701,10 @@ export function andFunction(left: FilterExpr, ...right: FilterExpr[]): And { * @param right Additional filter conditions to 'OR' together. * @return A new {@code Expr} representing the logical 'OR' operation. */ -export function orFunction(left: FilterExpr, ...right: FilterExpr[]): Or { +export function orFunction( + left: FilterCondition, + ...right: FilterCondition[] +): Or { return new Or([left, ...right]); } @@ -6759,8 +6753,8 @@ export function descending(expr: Expr): Ordering { */ export class Ordering { constructor( - private expr: Expr, - private direction: 'ascending' | 'descending' + readonly expr: Expr, + readonly direction: 'ascending' | 'descending' ) {} /** diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index a1b9ad481e9..f8ee619e1f5 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -351,7 +351,7 @@ export class Pipeline * @param condition The {@link FilterCondition} to apply. * @return A new Pipeline object with this stage appended to the stage list. */ - where(condition: FilterCondition & Expr): Pipeline { + where(condition: FilterCondition): Pipeline { const copy = this.stages.map(s => s); this.readUserData('where', condition); copy.push(new Where(condition)); diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index b4fe237f79c..4d43abdb486 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -204,7 +204,7 @@ export class DocumentsSource implements Stage { export class Where implements Stage { name = 'where'; - constructor(private condition: FilterCondition & Expr) {} + constructor(private condition: FilterCondition) {} /** * @internal From 8b0374509ef9480becb106034ec66cd26e067989 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:06:37 -0700 Subject: [PATCH 06/75] Make PipelineSource generic and remove useFluentPipelines --- .../firestore/lite/pipelines/pipelines.ts | 3 - packages/firestore/src/api/pipeline-source.ts | 100 ------------------ packages/firestore/src/api/pipeline.ts | 31 +++++- packages/firestore/src/api/pipeline_impl.ts | 77 +++++--------- packages/firestore/src/api_pipelines.ts | 4 +- packages/firestore/src/lite-api/database.ts | 2 - .../firestore/src/lite-api/pipeline-source.ts | 63 +++-------- packages/firestore/src/lite-api/pipeline.ts | 31 +++++- .../firestore/src/lite-api/pipeline_impl.ts | 63 ++++------- .../test/integration/api/pipeline.test.ts | 5 - 10 files changed, 116 insertions(+), 263 deletions(-) delete mode 100644 packages/firestore/src/api/pipeline-source.ts diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index 52c059055d9..7285e5c9761 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -54,7 +54,6 @@ export { PipelineResult } from '../../src/lite-api/pipeline-result'; export { Pipeline } from '../../src/lite-api/pipeline'; export { - useFluentPipelines, pipeline, execute } from '../../src/lite-api/pipeline_impl'; @@ -207,8 +206,6 @@ export { Ordering, ExprType, AccumulatorTarget, - FilterExpr, - SelectableExpr, Selectable, FilterCondition, Accumulator diff --git a/packages/firestore/src/api/pipeline-source.ts b/packages/firestore/src/api/pipeline-source.ts deleted file mode 100644 index 3ad66cab9e9..00000000000 --- a/packages/firestore/src/api/pipeline-source.ts +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { PipelineSource as LitePipelineSoure } from '../lite-api/pipeline-source'; -import { - CollectionGroupSource, - CollectionSource, - DatabaseSource, - DocumentsSource -} from '../lite-api/stage'; -import { UserDataReader } from '../lite-api/user_data_reader'; -import { AbstractUserDataWriter } from '../lite-api/user_data_writer'; -import { DocumentKey } from '../model/document_key'; -import { cast } from '../util/input_validation'; - -import { Firestore } from './database'; -import { Pipeline } from './pipeline'; -import { DocumentReference } from './reference'; - -/** - * Represents the source of a Firestore {@link Pipeline}. - * @beta - */ -export class PipelineSource extends LitePipelineSoure { - /** - * @internal - * @private - * @param _db - * @param _userDataReader - * @param _userDataWriter - * @param _documentReferenceFactory - */ - // eslint-disable-next-line @typescript-eslint/no-useless-constructor - constructor( - _db: Firestore, - _userDataReader: UserDataReader, - _userDataWriter: AbstractUserDataWriter, - _documentReferenceFactory: (id: DocumentKey) => DocumentReference - ) { - super(_db, _userDataReader, _userDataWriter, _documentReferenceFactory); - } - - collection(collectionPath: string): Pipeline { - const _db = cast(this._db, Firestore); - return new Pipeline( - _db, - this._userDataReader, - this._userDataWriter, - this._documentReferenceFactory, - [new CollectionSource(collectionPath)] - ); - } - - collectionGroup(collectionId: string): Pipeline { - const _db = cast(this._db, Firestore); - return new Pipeline( - _db, - this._userDataReader, - this._userDataWriter, - this._documentReferenceFactory, - [new CollectionGroupSource(collectionId)] - ); - } - - database(): Pipeline { - const _db = cast(this._db, Firestore); - return new Pipeline( - _db, - this._userDataReader, - this._userDataWriter, - this._documentReferenceFactory, - [new DatabaseSource()] - ); - } - - documents(docs: DocumentReference[]): Pipeline { - const _db = cast(this._db, Firestore); - return new Pipeline( - _db, - this._userDataReader, - this._userDataWriter, - this._documentReferenceFactory, - [DocumentsSource.of(docs)] - ); - } -} diff --git a/packages/firestore/src/api/pipeline.ts b/packages/firestore/src/api/pipeline.ts index de2cb16d9aa..948285575f3 100644 --- a/packages/firestore/src/api/pipeline.ts +++ b/packages/firestore/src/api/pipeline.ts @@ -23,7 +23,9 @@ import { UserDataReader } from '../lite-api/user_data_reader'; import { AbstractUserDataWriter } from '../lite-api/user_data_writer'; import { DocumentKey } from '../model/document_key'; -import { Firestore } from './database'; +import {ensureFirestoreConfigured, Firestore} from './database'; +import {cast} from "../util/input_validation"; +import {firestoreClientExecutePipeline} from "../core/firestore_client"; export class Pipeline< AppModelType = DocumentData @@ -119,8 +121,29 @@ export class Pipeline< * @return A Promise representing the asynchronous pipeline execution. */ execute(): Promise>> { - throw new Error( - 'Pipelines not initialized. Your application must call `useFluentPipelines()` before using Firestore Pipeline features.' - ); + const firestore = cast(this._db, Firestore); + const client = ensureFirestoreConfigured(firestore); + return firestoreClientExecutePipeline(client, this).then(result => { + const docs = result + // Currently ignore any response from ExecutePipeline that does + // not contain any document data in the `fields` property. + .filter(element => !!element.fields) + .map( + element => + new PipelineResult( + this._userDataWriter, + element.key?.path + ? this._documentReferenceFactory(element.key) + : undefined, + element.fields, + element.executionTime?.toTimestamp(), + element.createTime?.toTimestamp(), + element.updateTime?.toTimestamp() + //this.converter + ) + ); + + return docs; + }); } } diff --git a/packages/firestore/src/api/pipeline_impl.ts b/packages/firestore/src/api/pipeline_impl.ts index 5d58266b343..76e51b3258d 100644 --- a/packages/firestore/src/api/pipeline_impl.ts +++ b/packages/firestore/src/api/pipeline_impl.ts @@ -16,7 +16,7 @@ */ import { Pipeline } from '../api/pipeline'; -import { PipelineSource } from '../api/pipeline-source'; +import { PipelineSource } from '../lite-api/pipeline-source'; import { firestoreClientExecutePipeline } from '../core/firestore_client'; import { Pipeline as LitePipeline } from '../lite-api/pipeline'; import { PipelineResult } from '../lite-api/pipeline-result'; @@ -27,10 +27,11 @@ import { cast } from '../util/input_validation'; import { Firestore, ensureFirestoreConfigured } from './database'; import { DocumentReference, Query } from './reference'; import { ExpUserDataWriter } from './user_data_writer'; +import {Stage} from "../lite-api/stage"; declare module './database' { interface Firestore { - pipeline(): PipelineSource; + pipeline(): PipelineSource; } } @@ -38,7 +39,7 @@ declare module './database' { * Experimental Modular API for console testing. * @param firestore */ -export function pipeline(firestore: Firestore): PipelineSource; +export function pipeline(firestore: Firestore): PipelineSource; /** * Experimental Modular API for console testing. @@ -48,17 +49,19 @@ export function pipeline(query: Query): Pipeline; export function pipeline( firestoreOrQuery: Firestore | Query -): PipelineSource | Pipeline { +): PipelineSource | Pipeline { if (firestoreOrQuery instanceof Firestore) { const firestore = firestoreOrQuery; - return new PipelineSource( - firestore, - newUserDataReader(firestore), - new ExpUserDataWriter(firestore), - (key: DocumentKey) => { - return new DocumentReference(firestore, null, key); - } - ); + return new PipelineSource((stages: Stage[]) => { + return new Pipeline( + firestore, + newUserDataReader(firestore), + new ExpUserDataWriter(firestore), + (key: DocumentKey) => { + return new DocumentReference(firestore, null, key); + }, + stages); + }); } else { let result; const query = firestoreOrQuery; @@ -75,45 +78,19 @@ export function pipeline( return result; } } -export function useFluentPipelines(): void { - Firestore.prototype.pipeline = function (): PipelineSource { - return pipeline(this); - }; - Query.prototype.pipeline = function (): Pipeline { - return pipeline(this); - }; - - Pipeline.prototype.execute = function (): Promise { - return execute(this); - }; +export function execute( + pipeline: LitePipeline +): Promise> { + return pipeline.execute(); } -export function execute( - pipeline: LitePipeline -): Promise>> { - const firestore = cast(pipeline._db, Firestore); - const client = ensureFirestoreConfigured(firestore); - return firestoreClientExecutePipeline(client, pipeline).then(result => { - const docs = result - // Currently ignore any response from ExecutePipeline that does - // not contain any document data in the `fields` property. - .filter(element => !!element.fields) - .map( - element => - new PipelineResult( - pipeline._userDataWriter, - element.key?.path - ? pipeline._documentReferenceFactory(element.key) - : undefined, - element.fields, - element.executionTime?.toTimestamp(), - element.createTime?.toTimestamp(), - element.updateTime?.toTimestamp() - //this.converter - ) - ); +// Augument the Firestore class with the pipeline() factory method +Firestore.prototype.pipeline = function (): PipelineSource { + return pipeline(this); +}; - return docs; - }); -} +// Augument the Query class with the pipeline() factory method +Query.prototype.pipeline = function (): Pipeline { + return pipeline(this); +}; diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index d5de1e25b34..b089e91533e 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -21,7 +21,7 @@ export { PipelineResult } from './lite-api/pipeline-result'; export { Pipeline } from './api/pipeline'; -export { useFluentPipelines, pipeline, execute } from './api/pipeline_impl'; +export { pipeline, execute } from './api/pipeline_impl'; export { Stage, @@ -180,8 +180,6 @@ export { export type { ExprType, AccumulatorTarget, - FilterExpr, - SelectableExpr, Selectable, FilterCondition, Accumulator diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index 33b6afa8092..9ea4d4ec52e 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -41,8 +41,6 @@ import { cast } from '../util/input_validation'; import { logWarn } from '../util/log'; import { FirestoreService, removeComponents } from './components'; -// `import type` to avoid bundling the source for -// pipelines if `useFluentPipelines()` is not called import { DEFAULT_HOST, FirestoreSettingsImpl, diff --git a/packages/firestore/src/lite-api/pipeline-source.ts b/packages/firestore/src/lite-api/pipeline-source.ts index 99da8fee8c6..57b93c44a9d 100644 --- a/packages/firestore/src/lite-api/pipeline-source.ts +++ b/packages/firestore/src/lite-api/pipeline-source.ts @@ -15,92 +15,53 @@ * limitations under the License. */ -import { DocumentKey } from '../model/document_key'; - -import { Firestore } from './database'; import { Pipeline } from './pipeline'; import { DocumentReference } from './reference'; import { CollectionGroupSource, CollectionSource, DatabaseSource, - DocumentsSource + DocumentsSource, Stage } from './stage'; -import { UserDataReader } from './user_data_reader'; -import { AbstractUserDataWriter } from './user_data_writer'; /** * Represents the source of a Firestore {@link Pipeline}. * @beta */ -export class PipelineSource { +export class PipelineSource { /** * @internal * @private - * @param _db - * @param _userDataReader - * @param _userDataWriter - * @param _documentReferenceFactory + * @param _createPipeline */ constructor( /** * @internal * @private */ - public _db: Firestore, - /** - * @internal - * @private - */ - public _userDataReader: UserDataReader, - /** - * @internal - * @private - */ - public _userDataWriter: AbstractUserDataWriter, - /** - * @internal - * @private - */ - public _documentReferenceFactory: (id: DocumentKey) => DocumentReference + public _createPipeline: (stages: Stage[]) => PipelineType ) {} - collection(collectionPath: string): Pipeline { - return new Pipeline( - this._db, - this._userDataReader, - this._userDataWriter, - this._documentReferenceFactory, + collection(collectionPath: string): PipelineType { + return this._createPipeline( [new CollectionSource(collectionPath)] ); } - collectionGroup(collectionId: string): Pipeline { - return new Pipeline( - this._db, - this._userDataReader, - this._userDataWriter, - this._documentReferenceFactory, + collectionGroup(collectionId: string): PipelineType { + return this._createPipeline( [new CollectionGroupSource(collectionId)] ); } - database(): Pipeline { - return new Pipeline( - this._db, - this._userDataReader, - this._userDataWriter, - this._documentReferenceFactory, + database(): PipelineType { + return this._createPipeline( [new DatabaseSource()] ); } - documents(docs: DocumentReference[]): Pipeline { - return new Pipeline( - this._db, - this._userDataReader, - this._userDataWriter, - this._documentReferenceFactory, + documents(docs: DocumentReference[]): PipelineType { + return this._createPipeline( [DocumentsSource.of(docs)] ); } diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index f8ee619e1f5..1e43a3d0d0e 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -64,6 +64,11 @@ import { UserDataSource } from './user_data_reader'; import { AbstractUserDataWriter } from './user_data_writer'; +import {cast} from "../util/input_validation"; +import {ensureFirestoreConfigured} from "../api/database"; +import {firestoreClientExecutePipeline} from "../core/firestore_client"; +import {getDatastore} from "./components"; +import {invokeExecutePipeline} from "../remote/datastore"; interface ReadableUserData { _readUserData(dataReader: UserDataReader): void; @@ -819,9 +824,29 @@ export class Pipeline * @return A Promise representing the asynchronous pipeline execution. */ execute(): Promise>> { - throw new Error( - 'Pipelines not initialized. Your application must call `useFluentPipelines()` before using Firestore Pipeline features.' - ); + const datastore = getDatastore(this._db); + return invokeExecutePipeline(datastore, this).then(result => { + const docs = result + // Currently ignore any response from ExecutePipeline that does + // not contain any document data in the `fields` property. + .filter(element => !!element.fields) + .map( + element => + new PipelineResult( + this._userDataWriter, + element.key?.path + ? this._documentReferenceFactory(element.key) + : undefined, + element.fields, + element.executionTime?.toTimestamp(), + element.createTime?.toTimestamp(), + element.updateTime?.toTimestamp() + //this.converter + ) + ); + + return docs; + }); } /** diff --git a/packages/firestore/src/lite-api/pipeline_impl.ts b/packages/firestore/src/lite-api/pipeline_impl.ts index f3556dc6f09..965a8d25c47 100644 --- a/packages/firestore/src/lite-api/pipeline_impl.ts +++ b/packages/firestore/src/lite-api/pipeline_impl.ts @@ -26,10 +26,11 @@ import { PipelineSource } from './pipeline-source'; import { DocumentReference, Query } from './reference'; import { LiteUserDataWriter } from './reference_impl'; import { newUserDataReader } from './user_data_reader'; +import {Stage} from "./stage"; declare module './database' { interface Firestore { - pipeline(): PipelineSource; + pipeline(): PipelineSource; } } @@ -47,36 +48,14 @@ declare module './reference' { export function execute( pipeline: Pipeline ): Promise>> { - const datastore = getDatastore(pipeline._db); - return invokeExecutePipeline(datastore, pipeline).then(result => { - const docs = result - // Currently ignore any response from ExecutePipeline that does - // not contain any document data in the `fields` property. - .filter(element => !!element.fields) - .map( - element => - new PipelineResult( - pipeline._userDataWriter, - element.key?.path - ? pipeline._documentReferenceFactory(element.key) - : undefined, - element.fields, - element.executionTime?.toTimestamp(), - element.createTime?.toTimestamp(), - element.updateTime?.toTimestamp() - //this.converter - ) - ); - - return docs; - }); + return pipeline.execute(); } /** * Experimental Modular API for console testing. * @param firestore */ -export function pipeline(firestore: Firestore): PipelineSource; +export function pipeline(firestore: Firestore): PipelineSource; /** * Experimental Modular API for console testing. @@ -86,19 +65,21 @@ export function pipeline(query: Query): Pipeline; export function pipeline( firestoreOrQuery: Firestore | Query -): PipelineSource | Pipeline { +): PipelineSource | Pipeline { if (firestoreOrQuery instanceof Firestore) { const db = firestoreOrQuery; const userDataWriter = new LiteUserDataWriter(db); const userDataReader = newUserDataReader(db); - return new PipelineSource( - db, - userDataReader, - userDataWriter, - (key: DocumentKey) => { - return new DocumentReference(db, null, key); - } - ); + return new PipelineSource((stages: Stage[]) => { + return new Pipeline( + db, + userDataReader, + userDataWriter, + (key: DocumentKey) => { + return new DocumentReference(db, null, key); + }, + stages); + }); } else { let pipeline; const query = firestoreOrQuery; @@ -119,12 +100,10 @@ export function pipeline( } } -export function useFluentPipelines(): void { - Firestore.prototype.pipeline = function (): PipelineSource { - return pipeline(this); - }; +Firestore.prototype.pipeline = function (): PipelineSource { + return pipeline(this); +}; - Query.prototype.pipeline = function (): Pipeline { - return pipeline(this); - }; -} +Query.prototype.pipeline = function (): Pipeline { + return pipeline(this); +}; diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index ddedc966eb4..d6edba1718b 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -55,7 +55,6 @@ import { setDoc, startsWith, subtract, - useFluentPipelines, setLogLevel, cond, eqAny, @@ -266,10 +265,6 @@ apiDescribe('Pipelines', persistence => { }); describe('fluent API', () => { - before(() => { - useFluentPipelines(); - }); - it('empty results as expected', async () => { const result = await firestore .pipeline() From 2e1c8f6f22e9a61508cd64af48271c912c79e1a7 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:27:15 -0700 Subject: [PATCH 07/75] Remove converter and placeholders for converter. --- packages/firestore/src/api/pipeline.ts | 23 +-- .../firestore/src/core/firestore_client.ts | 2 +- .../firestore/src/lite-api/pipeline-result.ts | 25 +-- packages/firestore/src/lite-api/pipeline.ts | 143 ++++-------------- .../firestore/src/lite-api/pipeline_impl.ts | 6 +- packages/firestore/src/remote/datastore.ts | 2 +- 6 files changed, 46 insertions(+), 155 deletions(-) diff --git a/packages/firestore/src/api/pipeline.ts b/packages/firestore/src/api/pipeline.ts index 948285575f3..835576a7fe0 100644 --- a/packages/firestore/src/api/pipeline.ts +++ b/packages/firestore/src/api/pipeline.ts @@ -29,7 +29,7 @@ import {firestoreClientExecutePipeline} from "../core/firestore_client"; export class Pipeline< AppModelType = DocumentData -> extends LitePipeline { +> extends LitePipeline { /** * @internal * @private @@ -38,25 +38,20 @@ export class Pipeline< * @param userDataWriter * @param documentReferenceFactory * @param stages - * @param converter */ constructor( db: Firestore, userDataReader: UserDataReader, userDataWriter: AbstractUserDataWriter, documentReferenceFactory: (id: DocumentKey) => DocumentReference, - stages: Stage[], - // TODO(pipeline) support converter - //private converter: FirestorePipelineConverter = defaultPipelineConverter() - converter: unknown = {} + stages: Stage[] ) { super( db, userDataReader, userDataWriter, documentReferenceFactory, - stages, - converter + stages ); } @@ -78,14 +73,13 @@ export class Pipeline< documentReferenceFactory: (id: DocumentKey) => DocumentReference, stages: Stage[], converter: unknown = {} - ): Pipeline { - return new Pipeline( + ): Pipeline { + return new Pipeline( db, userDataReader, userDataWriter, documentReferenceFactory, - stages, - converter + stages ); } @@ -120,7 +114,7 @@ export class Pipeline< * * @return A Promise representing the asynchronous pipeline execution. */ - execute(): Promise>> { + execute(): Promise> { const firestore = cast(this._db, Firestore); const client = ensureFirestoreConfigured(firestore); return firestoreClientExecutePipeline(client, this).then(result => { @@ -130,7 +124,7 @@ export class Pipeline< .filter(element => !!element.fields) .map( element => - new PipelineResult( + new PipelineResult( this._userDataWriter, element.key?.path ? this._documentReferenceFactory(element.key) @@ -139,7 +133,6 @@ export class Pipeline< element.executionTime?.toTimestamp(), element.createTime?.toTimestamp(), element.updateTime?.toTimestamp() - //this.converter ) ); diff --git a/packages/firestore/src/core/firestore_client.ts b/packages/firestore/src/core/firestore_client.ts index ad485c7f77a..bb0771d2335 100644 --- a/packages/firestore/src/core/firestore_client.ts +++ b/packages/firestore/src/core/firestore_client.ts @@ -557,7 +557,7 @@ export function firestoreClientRunAggregateQuery( export function firestoreClientExecutePipeline( client: FirestoreClient, - pipeline: Pipeline + pipeline: Pipeline ): Promise { const deferred = new Deferred(); diff --git a/packages/firestore/src/lite-api/pipeline-result.ts b/packages/firestore/src/lite-api/pipeline-result.ts index f3951099ba2..dc0a6412481 100644 --- a/packages/firestore/src/lite-api/pipeline-result.ts +++ b/packages/firestore/src/lite-api/pipeline-result.ts @@ -72,8 +72,6 @@ export class PipelineResult { executionTime?: Timestamp, createTime?: Timestamp, updateTime?: Timestamp - // TODO converter - //readonly converter: FirestorePipelineConverter = defaultPipelineConverter() ) { this._ref = ref; this._userDataWriter = userDataWriter; @@ -160,26 +158,9 @@ export class PipelineResult { return undefined; } - // TODO(pipelines) - // We only want to use the converter and create a new QueryDocumentSnapshot - // if a converter has been provided. - // if (!!this.converter && this.converter !== defaultPipelineConverter()) { - // return this.converter.fromFirestore( - // new PipelineResult< DocumentData>( - // this._serializer, - // this.ref, - // this._fieldsProto, - // this._executionTime, - // this.createTime, - // this.updateTime, - // defaultPipelineConverter() - // ) - // ); - // } else {{ return this._userDataWriter.convertValue( this._fields.value ) as AppModelType; - //} } /** @@ -217,9 +198,9 @@ export class PipelineResult { } } -export function pipelineResultEqual( - left: PipelineResult, - right: PipelineResult +export function pipelineResultEqual( + left: PipelineResult, + right: PipelineResult ): boolean { if (left === right) { return true; diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index 1e43a3d0d0e..6b6553ae644 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -124,7 +124,7 @@ function isReadableUserData(value: any): value is ReadableUserData { /** * Base-class implementation */ -export class Pipeline +export class Pipeline implements ProtoSerializable { /** @@ -135,7 +135,6 @@ export class Pipeline * @param _userDataWriter * @param _documentReferenceFactory * @param stages - * @param converter */ constructor( /** @@ -154,10 +153,7 @@ export class Pipeline * @private */ public _documentReferenceFactory: (id: DocumentKey) => DocumentReference, - private stages: Stage[], - // TODO(pipeline) support converter - //private converter: FirestorePipelineConverter = defaultPipelineConverter() - private converter: unknown = {} + private stages: Stage[] ) {} /** @@ -186,7 +182,7 @@ export class Pipeline * @param fields The fields to add to the documents, specified as {@link Selectable}s. * @return A new Pipeline object with this stage appended to the stage list. */ - addFields(...fields: Selectable[]): Pipeline { + addFields(...fields: Selectable[]): Pipeline { const copy = this.stages.map(s => s); copy.push( new AddFields( @@ -198,8 +194,7 @@ export class Pipeline this.userDataReader, this._userDataWriter, this._documentReferenceFactory, - copy, - this.converter + copy ); } @@ -234,7 +229,7 @@ export class Pipeline * Selectable} expressions or {@code string} values representing field names. * @return A new Pipeline object with this stage appended to the stage list. */ - select(...selections: Array): Pipeline { + select(...selections: Array): Pipeline { const copy = this.stages.map(s => s); let projections: Map = this.selectablesToMap(selections); projections = this.readUserData('select', projections); @@ -244,8 +239,7 @@ export class Pipeline this.userDataReader, this._userDataWriter, this._documentReferenceFactory, - copy, - this.converter + copy ); } @@ -304,7 +298,6 @@ export class Pipeline * @param userDataWriter * @param documentReferenceFactory * @param stages - * @param converter * @protected */ protected newPipeline( @@ -314,14 +307,13 @@ export class Pipeline documentReferenceFactory: (id: DocumentKey) => DocumentReference, stages: Stage[], converter: unknown = {} - ): Pipeline { - return new Pipeline( + ): Pipeline { + return new Pipeline( db, userDataReader, userDataWriter, documentReferenceFactory, - stages, - converter + stages ); } @@ -356,7 +348,7 @@ export class Pipeline * @param condition The {@link FilterCondition} to apply. * @return A new Pipeline object with this stage appended to the stage list. */ - where(condition: FilterCondition): Pipeline { + where(condition: FilterCondition): Pipeline { const copy = this.stages.map(s => s); this.readUserData('where', condition); copy.push(new Where(condition)); @@ -365,8 +357,7 @@ export class Pipeline this.userDataReader, this._userDataWriter, this._documentReferenceFactory, - copy, - this.converter + copy ); } @@ -390,7 +381,7 @@ export class Pipeline * @param offset The number of documents to skip. * @return A new Pipeline object with this stage appended to the stage list. */ - offset(offset: number): Pipeline { + offset(offset: number): Pipeline { const copy = this.stages.map(s => s); copy.push(new Offset(offset)); return this.newPipeline( @@ -398,8 +389,7 @@ export class Pipeline this.userDataReader, this._userDataWriter, this._documentReferenceFactory, - copy, - this.converter + copy ); } @@ -428,7 +418,7 @@ export class Pipeline * @param limit The maximum number of documents to return. * @return A new Pipeline object with this stage appended to the stage list. */ - limit(limit: number): Pipeline { + limit(limit: number): Pipeline { const copy = this.stages.map(s => s); copy.push(new Limit(limit)); return this.newPipeline( @@ -436,8 +426,7 @@ export class Pipeline this.userDataReader, this._userDataWriter, this._documentReferenceFactory, - copy, - this.converter + copy ); } @@ -469,7 +458,7 @@ export class Pipeline * value combinations or {@code string}s representing field names. * @return A new {@code Pipeline} object with this stage appended to the stage list. */ - distinct(...groups: Array): Pipeline { + distinct(...groups: Array): Pipeline { const copy = this.stages.map(s => s); copy.push( new Distinct( @@ -481,8 +470,7 @@ export class Pipeline this.userDataReader, this._userDataWriter, this._documentReferenceFactory, - copy, - this.converter + copy ); } @@ -508,7 +496,7 @@ export class Pipeline * and provide a name for the accumulated results. * @return A new Pipeline object with this stage appended to the stage list. */ - aggregate(...accumulators: AccumulatorTarget[]): Pipeline; + aggregate(...accumulators: AccumulatorTarget[]): Pipeline; /** * Performs optionally grouped aggregation operations on the documents from previous stages. * @@ -544,7 +532,7 @@ export class Pipeline aggregate(options: { accumulators: AccumulatorTarget[]; groups?: Array; - }): Pipeline; + }): Pipeline; aggregate( optionsOrTarget: | AccumulatorTarget @@ -553,7 +541,7 @@ export class Pipeline groups?: Array; }, ...rest: AccumulatorTarget[] - ): Pipeline { + ): Pipeline { const copy = this.stages.map(s => s); if ('accumulators' in optionsOrTarget) { copy.push( @@ -594,13 +582,11 @@ export class Pipeline this.userDataReader, this._userDataWriter, this._documentReferenceFactory, - copy, - this.converter + copy ); } - findNearest(options: FindNearestOptions): Pipeline; - findNearest(options: FindNearestOptions): Pipeline { + findNearest(options: FindNearestOptions): Pipeline { const copy = this.stages.map(s => s); const parseContext = this.userDataReader.createContext( UserDataSource.Argument, @@ -650,8 +636,8 @@ export class Pipeline * @param orders One or more {@link Ordering} instances specifying the sorting criteria. * @return A new {@code Pipeline} object with this stage appended to the stage list. */ - sort(...orderings: Ordering[]): Pipeline; - sort(options: { orderings: Ordering[] }): Pipeline; + sort(...orderings: Ordering[]): Pipeline; + sort(options: { orderings: Ordering[] }): Pipeline; sort( optionsOrOrderings: | Ordering @@ -659,7 +645,7 @@ export class Pipeline orderings: Ordering[]; }, ...rest: Ordering[] - ): Pipeline { + ): Pipeline { const copy = this.stages.map(s => s); // Option object if ('orderings' in optionsOrOrderings) { @@ -683,8 +669,7 @@ export class Pipeline this.userDataReader, this._userDataWriter, this._documentReferenceFactory, - copy, - this.converter + copy ); } @@ -708,7 +693,7 @@ export class Pipeline * @param params A list of parameters to configure the generic stage's behavior. * @return A new {@code Pipeline} object with this stage appended to the stage list. */ - genericStage(name: string, params: any[]): Pipeline { + genericStage(name: string, params: any[]): Pipeline { const copy = this.stages.map(s => s); params.forEach(param => { if (isReadableUserData(param)) { @@ -721,77 +706,10 @@ export class Pipeline this.userDataReader, this._userDataWriter, this._documentReferenceFactory, - copy, - this.converter + copy ); } - // TODO(pipeline) support converter - // withConverter(converter: null): Pipeline; - // withConverter( - // converter: FirestorePipelineConverter - // ): Pipeline; - // /** - // * Applies a custom data converter to this Query, allowing you to use your - // * own custom model objects with Firestore. When you call get() on the - // * returned Query, the provided converter will convert between Firestore - // * data of type `NewDbModelType` and your custom type `NewAppModelType`. - // * - // * Using the converter allows you to specify generic type arguments when - // * storing and retrieving objects from Firestore. - // * - // * Passing in `null` as the converter parameter removes the current - // * converter. - // * - // * @example - // * ``` - // * class Post { - // * constructor(readonly title: string, readonly author: string) {} - // * - // * toString(): string { - // * return this.title + ', by ' + this.author; - // * } - // * } - // * - // * const postConverter = { - // * toFirestore(post: Post): FirebaseFirestore.DocumentData { - // * return {title: post.title, author: post.author}; - // * }, - // * fromFirestore( - // * snapshot: FirebaseFirestore.QueryDocumentSnapshot - // * ): Post { - // * const data = snapshot.data(); - // * return new Post(data.title, data.author); - // * } - // * }; - // * - // * const postSnap = await Firestore() - // * .collection('posts') - // * .withConverter(postConverter) - // * .doc().get(); - // * const post = postSnap.data(); - // * if (post !== undefined) { - // * post.title; // string - // * post.toString(); // Should be defined - // * post.someNonExistentProperty; // TS error - // * } - // * - // * ``` - // * @param {FirestoreDataConverter | null} converter Converts objects to and - // * from Firestore. Passing in `null` removes the current converter. - // * @return A Query that uses the provided converter. - // */ - // withConverter( - // converter: FirestorePipelineConverter | null - // ): Pipeline { - // const copy = this.stages.map(s => s); - // return this.newPipeline( - // this.db, - // copy, - // converter ?? defaultPipelineConverter() - // ); - // } - /** * Executes this pipeline and returns a Promise to represent the asynchronous operation. * @@ -823,7 +741,7 @@ export class Pipeline * * @return A Promise representing the asynchronous pipeline execution. */ - execute(): Promise>> { + execute(): Promise> { const datastore = getDatastore(this._db); return invokeExecutePipeline(datastore, this).then(result => { const docs = result @@ -832,7 +750,7 @@ export class Pipeline .filter(element => !!element.fields) .map( element => - new PipelineResult( + new PipelineResult( this._userDataWriter, element.key?.path ? this._documentReferenceFactory(element.key) @@ -841,7 +759,6 @@ export class Pipeline element.executionTime?.toTimestamp(), element.createTime?.toTimestamp(), element.updateTime?.toTimestamp() - //this.converter ) ); diff --git a/packages/firestore/src/lite-api/pipeline_impl.ts b/packages/firestore/src/lite-api/pipeline_impl.ts index 965a8d25c47..1f436c75a28 100644 --- a/packages/firestore/src/lite-api/pipeline_impl.ts +++ b/packages/firestore/src/lite-api/pipeline_impl.ts @@ -45,9 +45,9 @@ declare module './reference' { * @param pipeline Execute this pipeline. * @beta */ -export function execute( - pipeline: Pipeline -): Promise>> { +export function execute( + pipeline: Pipeline +): Promise> { return pipeline.execute(); } diff --git a/packages/firestore/src/remote/datastore.ts b/packages/firestore/src/remote/datastore.ts index 5fbff4392ac..00c1e7fca9e 100644 --- a/packages/firestore/src/remote/datastore.ts +++ b/packages/firestore/src/remote/datastore.ts @@ -241,7 +241,7 @@ export async function invokeBatchGetDocumentsRpc( export async function invokeExecutePipeline( datastore: Datastore, - pipeline: Pipeline + pipeline: Pipeline ): Promise { const datastoreImpl = debugCast(datastore, DatastoreImpl); const executePipelineRequest = pipeline._toProto(datastoreImpl.serializer); From d67807eb7fe9a49351a46bc3ca027c4089b5b1fc Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:40:45 -0700 Subject: [PATCH 08/75] cleanup: remove documentReferenceFactory --- packages/firestore/src/api/pipeline.ts | 8 +------ packages/firestore/src/api/pipeline_impl.ts | 3 --- packages/firestore/src/lite-api/pipeline.ts | 22 ++----------------- .../firestore/src/lite-api/pipeline_impl.ts | 3 --- 4 files changed, 3 insertions(+), 33 deletions(-) diff --git a/packages/firestore/src/api/pipeline.ts b/packages/firestore/src/api/pipeline.ts index 835576a7fe0..e4aa11a451d 100644 --- a/packages/firestore/src/api/pipeline.ts +++ b/packages/firestore/src/api/pipeline.ts @@ -36,21 +36,18 @@ export class Pipeline< * @param db * @param userDataReader * @param userDataWriter - * @param documentReferenceFactory * @param stages */ constructor( db: Firestore, userDataReader: UserDataReader, userDataWriter: AbstractUserDataWriter, - documentReferenceFactory: (id: DocumentKey) => DocumentReference, stages: Stage[] ) { super( db, userDataReader, userDataWriter, - documentReferenceFactory, stages ); } @@ -61,7 +58,6 @@ export class Pipeline< * @param db * @param userDataReader * @param userDataWriter - * @param documentReferenceFactory * @param stages * @param converter * @protected @@ -70,7 +66,6 @@ export class Pipeline< db: Firestore, userDataReader: UserDataReader, userDataWriter: AbstractUserDataWriter, - documentReferenceFactory: (id: DocumentKey) => DocumentReference, stages: Stage[], converter: unknown = {} ): Pipeline { @@ -78,7 +73,6 @@ export class Pipeline< db, userDataReader, userDataWriter, - documentReferenceFactory, stages ); } @@ -127,7 +121,7 @@ export class Pipeline< new PipelineResult( this._userDataWriter, element.key?.path - ? this._documentReferenceFactory(element.key) + ? new DocumentReference(firestore, null, element.key) : undefined, element.fields, element.executionTime?.toTimestamp(), diff --git a/packages/firestore/src/api/pipeline_impl.ts b/packages/firestore/src/api/pipeline_impl.ts index 76e51b3258d..4a434952c69 100644 --- a/packages/firestore/src/api/pipeline_impl.ts +++ b/packages/firestore/src/api/pipeline_impl.ts @@ -57,9 +57,6 @@ export function pipeline( firestore, newUserDataReader(firestore), new ExpUserDataWriter(firestore), - (key: DocumentKey) => { - return new DocumentReference(firestore, null, key); - }, stages); }); } else { diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index 6b6553ae644..dfa5143d162 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -69,6 +69,7 @@ import {ensureFirestoreConfigured} from "../api/database"; import {firestoreClientExecutePipeline} from "../core/firestore_client"; import {getDatastore} from "./components"; import {invokeExecutePipeline} from "../remote/datastore"; +import {firestore} from "../../test/util/api_helpers"; interface ReadableUserData { _readUserData(dataReader: UserDataReader): void; @@ -133,7 +134,6 @@ export class Pipeline * @param _db * @param userDataReader * @param _userDataWriter - * @param _documentReferenceFactory * @param stages */ constructor( @@ -148,11 +148,6 @@ export class Pipeline * @private */ public _userDataWriter: AbstractUserDataWriter, - /** - * @internal - * @private - */ - public _documentReferenceFactory: (id: DocumentKey) => DocumentReference, private stages: Stage[] ) {} @@ -193,7 +188,6 @@ export class Pipeline this._db, this.userDataReader, this._userDataWriter, - this._documentReferenceFactory, copy ); } @@ -238,7 +232,6 @@ export class Pipeline this._db, this.userDataReader, this._userDataWriter, - this._documentReferenceFactory, copy ); } @@ -296,7 +289,6 @@ export class Pipeline * @param db * @param userDataReader * @param userDataWriter - * @param documentReferenceFactory * @param stages * @protected */ @@ -304,7 +296,6 @@ export class Pipeline db: Firestore, userDataReader: UserDataReader, userDataWriter: AbstractUserDataWriter, - documentReferenceFactory: (id: DocumentKey) => DocumentReference, stages: Stage[], converter: unknown = {} ): Pipeline { @@ -312,7 +303,6 @@ export class Pipeline db, userDataReader, userDataWriter, - documentReferenceFactory, stages ); } @@ -356,7 +346,6 @@ export class Pipeline this._db, this.userDataReader, this._userDataWriter, - this._documentReferenceFactory, copy ); } @@ -388,7 +377,6 @@ export class Pipeline this._db, this.userDataReader, this._userDataWriter, - this._documentReferenceFactory, copy ); } @@ -425,7 +413,6 @@ export class Pipeline this._db, this.userDataReader, this._userDataWriter, - this._documentReferenceFactory, copy ); } @@ -469,7 +456,6 @@ export class Pipeline this._db, this.userDataReader, this._userDataWriter, - this._documentReferenceFactory, copy ); } @@ -581,7 +567,6 @@ export class Pipeline this._db, this.userDataReader, this._userDataWriter, - this._documentReferenceFactory, copy ); } @@ -607,7 +592,6 @@ export class Pipeline this._db, this.userDataReader, this._userDataWriter, - this._documentReferenceFactory, copy ); } @@ -668,7 +652,6 @@ export class Pipeline this._db, this.userDataReader, this._userDataWriter, - this._documentReferenceFactory, copy ); } @@ -705,7 +688,6 @@ export class Pipeline this._db, this.userDataReader, this._userDataWriter, - this._documentReferenceFactory, copy ); } @@ -753,7 +735,7 @@ export class Pipeline new PipelineResult( this._userDataWriter, element.key?.path - ? this._documentReferenceFactory(element.key) + ? new DocumentReference(this._db, null,element.key) : undefined, element.fields, element.executionTime?.toTimestamp(), diff --git a/packages/firestore/src/lite-api/pipeline_impl.ts b/packages/firestore/src/lite-api/pipeline_impl.ts index 1f436c75a28..1bb4f8ac4f9 100644 --- a/packages/firestore/src/lite-api/pipeline_impl.ts +++ b/packages/firestore/src/lite-api/pipeline_impl.ts @@ -75,9 +75,6 @@ export function pipeline( db, userDataReader, userDataWriter, - (key: DocumentKey) => { - return new DocumentReference(db, null, key); - }, stages); }); } else { From ea5c8e1af7802cc6d37eb87f134b84cfe3c1e13f Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:43:15 -0700 Subject: [PATCH 09/75] Linting and formatting --- .../firestore/lite/pipelines/pipelines.ts | 5 +-- packages/firestore/src/api/pipeline.ts | 44 +++---------------- packages/firestore/src/api/pipeline_impl.ts | 17 +++---- packages/firestore/src/core/pipeline-util.ts | 5 +-- .../firestore/src/lite-api/pipeline-source.ts | 20 +++------ packages/firestore/src/lite-api/pipeline.ts | 26 +++-------- .../firestore/src/lite-api/pipeline_impl.ts | 18 ++------ 7 files changed, 33 insertions(+), 102 deletions(-) diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index 7285e5c9761..1c32c4939e8 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -53,10 +53,7 @@ export { PipelineResult } from '../../src/lite-api/pipeline-result'; export { Pipeline } from '../../src/lite-api/pipeline'; -export { - pipeline, - execute -} from '../../src/lite-api/pipeline_impl'; +export { pipeline, execute } from '../../src/lite-api/pipeline_impl'; export { Stage, diff --git a/packages/firestore/src/api/pipeline.ts b/packages/firestore/src/api/pipeline.ts index e4aa11a451d..aaddf00274b 100644 --- a/packages/firestore/src/api/pipeline.ts +++ b/packages/firestore/src/api/pipeline.ts @@ -15,43 +15,18 @@ * limitations under the License. */ +import { firestoreClientExecutePipeline } from '../core/firestore_client'; import { Pipeline as LitePipeline } from '../lite-api/pipeline'; import { PipelineResult } from '../lite-api/pipeline-result'; -import { DocumentData, DocumentReference } from '../lite-api/reference'; +import { DocumentReference } from '../lite-api/reference'; import { Stage } from '../lite-api/stage'; import { UserDataReader } from '../lite-api/user_data_reader'; import { AbstractUserDataWriter } from '../lite-api/user_data_writer'; -import { DocumentKey } from '../model/document_key'; +import { cast } from '../util/input_validation'; -import {ensureFirestoreConfigured, Firestore} from './database'; -import {cast} from "../util/input_validation"; -import {firestoreClientExecutePipeline} from "../core/firestore_client"; - -export class Pipeline< - AppModelType = DocumentData -> extends LitePipeline { - /** - * @internal - * @private - * @param db - * @param userDataReader - * @param userDataWriter - * @param stages - */ - constructor( - db: Firestore, - userDataReader: UserDataReader, - userDataWriter: AbstractUserDataWriter, - stages: Stage[] - ) { - super( - db, - userDataReader, - userDataWriter, - stages - ); - } +import { ensureFirestoreConfigured, Firestore } from './database'; +export class Pipeline extends LitePipeline { /** * @internal * @private @@ -69,12 +44,7 @@ export class Pipeline< stages: Stage[], converter: unknown = {} ): Pipeline { - return new Pipeline( - db, - userDataReader, - userDataWriter, - stages - ); + return new Pipeline(db, userDataReader, userDataWriter, stages); } /** @@ -108,7 +78,7 @@ export class Pipeline< * * @return A Promise representing the asynchronous pipeline execution. */ - execute(): Promise> { + execute(): Promise { const firestore = cast(this._db, Firestore); const client = ensureFirestoreConfigured(firestore); return firestoreClientExecutePipeline(client, this).then(result => { diff --git a/packages/firestore/src/api/pipeline_impl.ts b/packages/firestore/src/api/pipeline_impl.ts index 4a434952c69..c0b15d19955 100644 --- a/packages/firestore/src/api/pipeline_impl.ts +++ b/packages/firestore/src/api/pipeline_impl.ts @@ -16,18 +16,16 @@ */ import { Pipeline } from '../api/pipeline'; -import { PipelineSource } from '../lite-api/pipeline-source'; -import { firestoreClientExecutePipeline } from '../core/firestore_client'; import { Pipeline as LitePipeline } from '../lite-api/pipeline'; import { PipelineResult } from '../lite-api/pipeline-result'; +import { PipelineSource } from '../lite-api/pipeline-source'; +import { Stage } from '../lite-api/stage'; import { newUserDataReader } from '../lite-api/user_data_reader'; -import { DocumentKey } from '../model/document_key'; import { cast } from '../util/input_validation'; -import { Firestore, ensureFirestoreConfigured } from './database'; -import { DocumentReference, Query } from './reference'; +import { Firestore } from './database'; +import { Query } from './reference'; import { ExpUserDataWriter } from './user_data_writer'; -import {Stage} from "../lite-api/stage"; declare module './database' { interface Firestore { @@ -57,7 +55,8 @@ export function pipeline( firestore, newUserDataReader(firestore), new ExpUserDataWriter(firestore), - stages); + stages + ); }); } else { let result; @@ -76,9 +75,7 @@ export function pipeline( } } -export function execute( - pipeline: LitePipeline -): Promise> { +export function execute(pipeline: LitePipeline): Promise { return pipeline.execute(); } diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index ed5f1c6a9ea..0c0c34ecc67 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -17,7 +17,6 @@ import { Constant, - Expr, Field, FilterCondition, not, @@ -172,9 +171,7 @@ export function isFirestoreValue(obj: any): obj is ProtoValue { return false; } -export function toPipelineFilterCondition( - f: FilterInternal -): FilterCondition { +export function toPipelineFilterCondition(f: FilterInternal): FilterCondition { if (f instanceof FieldFilterInternal) { const field = Field.of(f.field.toString()); if (isNanValue(f.value)) { diff --git a/packages/firestore/src/lite-api/pipeline-source.ts b/packages/firestore/src/lite-api/pipeline-source.ts index 57b93c44a9d..856096037f8 100644 --- a/packages/firestore/src/lite-api/pipeline-source.ts +++ b/packages/firestore/src/lite-api/pipeline-source.ts @@ -15,13 +15,13 @@ * limitations under the License. */ -import { Pipeline } from './pipeline'; import { DocumentReference } from './reference'; import { CollectionGroupSource, CollectionSource, DatabaseSource, - DocumentsSource, Stage + DocumentsSource, + Stage } from './stage'; /** @@ -43,26 +43,18 @@ export class PipelineSource { ) {} collection(collectionPath: string): PipelineType { - return this._createPipeline( - [new CollectionSource(collectionPath)] - ); + return this._createPipeline([new CollectionSource(collectionPath)]); } collectionGroup(collectionId: string): PipelineType { - return this._createPipeline( - [new CollectionGroupSource(collectionId)] - ); + return this._createPipeline([new CollectionGroupSource(collectionId)]); } database(): PipelineType { - return this._createPipeline( - [new DatabaseSource()] - ); + return this._createPipeline([new DatabaseSource()]); } documents(docs: DocumentReference[]): PipelineType { - return this._createPipeline( - [DocumentsSource.of(docs)] - ); + return this._createPipeline([DocumentsSource.of(docs)]); } } diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index dfa5143d162..b6cfcb0aa99 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -17,19 +17,20 @@ /* eslint @typescript-eslint/no-explicit-any: 0 */ -import { DocumentKey } from '../model/document_key'; import { ObjectValue } from '../model/object_value'; import { ExecutePipelineRequest, StructuredPipeline, Stage as ProtoStage } from '../protos/firestore_proto_api'; +import { invokeExecutePipeline } from '../remote/datastore'; import { getEncodedDatabaseId, JsonProtoSerializer, ProtoSerializable } from '../remote/serializer'; +import { getDatastore } from './components'; import { Firestore } from './database'; import { Accumulator, @@ -43,7 +44,7 @@ import { Selectable } from './expressions'; import { PipelineResult } from './pipeline-result'; -import { DocumentData, DocumentReference } from './reference'; +import { DocumentReference } from './reference'; import { AddFields, Aggregate, @@ -64,12 +65,6 @@ import { UserDataSource } from './user_data_reader'; import { AbstractUserDataWriter } from './user_data_writer'; -import {cast} from "../util/input_validation"; -import {ensureFirestoreConfigured} from "../api/database"; -import {firestoreClientExecutePipeline} from "../core/firestore_client"; -import {getDatastore} from "./components"; -import {invokeExecutePipeline} from "../remote/datastore"; -import {firestore} from "../../test/util/api_helpers"; interface ReadableUserData { _readUserData(dataReader: UserDataReader): void; @@ -125,9 +120,7 @@ function isReadableUserData(value: any): value is ReadableUserData { /** * Base-class implementation */ -export class Pipeline - implements ProtoSerializable -{ +export class Pipeline implements ProtoSerializable { /** * @internal * @private @@ -299,12 +292,7 @@ export class Pipeline stages: Stage[], converter: unknown = {} ): Pipeline { - return new Pipeline( - db, - userDataReader, - userDataWriter, - stages - ); + return new Pipeline(db, userDataReader, userDataWriter, stages); } /** @@ -723,7 +711,7 @@ export class Pipeline * * @return A Promise representing the asynchronous pipeline execution. */ - execute(): Promise> { + execute(): Promise { const datastore = getDatastore(this._db); return invokeExecutePipeline(datastore, this).then(result => { const docs = result @@ -735,7 +723,7 @@ export class Pipeline new PipelineResult( this._userDataWriter, element.key?.path - ? new DocumentReference(this._db, null,element.key) + ? new DocumentReference(this._db, null, element.key) : undefined, element.fields, element.executionTime?.toTimestamp(), diff --git a/packages/firestore/src/lite-api/pipeline_impl.ts b/packages/firestore/src/lite-api/pipeline_impl.ts index 1bb4f8ac4f9..98b121ad485 100644 --- a/packages/firestore/src/lite-api/pipeline_impl.ts +++ b/packages/firestore/src/lite-api/pipeline_impl.ts @@ -15,18 +15,14 @@ * limitations under the License. */ -import { DocumentKey } from '../model/document_key'; -import { invokeExecutePipeline } from '../remote/datastore'; - -import { getDatastore } from './components'; import { Firestore } from './database'; import { Pipeline } from './pipeline'; import { PipelineResult } from './pipeline-result'; import { PipelineSource } from './pipeline-source'; -import { DocumentReference, Query } from './reference'; +import { Query } from './reference'; import { LiteUserDataWriter } from './reference_impl'; +import { Stage } from './stage'; import { newUserDataReader } from './user_data_reader'; -import {Stage} from "./stage"; declare module './database' { interface Firestore { @@ -45,9 +41,7 @@ declare module './reference' { * @param pipeline Execute this pipeline. * @beta */ -export function execute( - pipeline: Pipeline -): Promise> { +export function execute(pipeline: Pipeline): Promise { return pipeline.execute(); } @@ -71,11 +65,7 @@ export function pipeline( const userDataWriter = new LiteUserDataWriter(db); const userDataReader = newUserDataReader(db); return new PipelineSource((stages: Stage[]) => { - return new Pipeline( - db, - userDataReader, - userDataWriter, - stages); + return new Pipeline(db, userDataReader, userDataWriter, stages); }); } else { let pipeline; From f251a0409e5dc6ffd023bb4cf08966d9d09c2aef Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 9 Jan 2025 16:34:20 -0700 Subject: [PATCH 10/75] Update the typings export for pipelines and lite pipelines so that it auguments the Firestore and Query classes. --- .../firestore/lite/pipelines/pipelines.d.ts | 28 +++++++++++++++++ packages/firestore/package.json | 2 +- packages/firestore/pipelines/package.json | 2 +- packages/firestore/pipelines/pipelines.d.ts | 31 +++++++++++++++++++ packages/firestore/src/api/pipeline_impl.ts | 10 ++---- 5 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 packages/firestore/lite/pipelines/pipelines.d.ts create mode 100644 packages/firestore/pipelines/pipelines.d.ts diff --git a/packages/firestore/lite/pipelines/pipelines.d.ts b/packages/firestore/lite/pipelines/pipelines.d.ts new file mode 100644 index 00000000000..f9375092bf9 --- /dev/null +++ b/packages/firestore/lite/pipelines/pipelines.d.ts @@ -0,0 +1,28 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {PipelineSource, Pipeline} from "../../dist/lite/pipelines"; + +// Augument the Firestore class with the pipeline() method. +// This is stripped from dist/lite/pipelines.d.ts during the build +// so it needs to be re-added here. +declare module '@firebase/firestore' { + interface Firestore { + pipeline(): PipelineSource; + } +} + +export * from "../../dist/lite/pipelines"; diff --git a/packages/firestore/package.json b/packages/firestore/package.json index 72504a9f729..a615a5559a5 100644 --- a/packages/firestore/package.json +++ b/packages/firestore/package.json @@ -98,7 +98,7 @@ "default": "./dist/lite/pipelines.browser.esm2017.js" }, "./pipelines": { - "types": "./dist/pipelines.d.ts", + "types": "./pipelines/pipelines.d.ts", "node": { "require": "./dist/pipelines.node.cjs.js", "import": "./dist/pipelines.node.mjs" diff --git a/packages/firestore/pipelines/package.json b/packages/firestore/pipelines/package.json index d0485164ad8..aab036bfdb0 100644 --- a/packages/firestore/pipelines/package.json +++ b/packages/firestore/pipelines/package.json @@ -6,7 +6,7 @@ "module": "../dist/pipelines.browser.esm2017.js", "browser": "../dist/pipelines.browser.esm2017.js", "react-native": "../dist/pipelines.rn.esm2017.js", - "typings": "../dist/pipelines.d.ts", + "typings": "./pipelines.d.ts", "private": true, "engines": { "node": ">=18.0.0" diff --git a/packages/firestore/pipelines/pipelines.d.ts b/packages/firestore/pipelines/pipelines.d.ts new file mode 100644 index 00000000000..5e7944e5731 --- /dev/null +++ b/packages/firestore/pipelines/pipelines.d.ts @@ -0,0 +1,31 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {PipelineSource, Pipeline} from "../dist/pipelines"; + +// Augument the Firestore and Query classes with the pipeline() method. +// This is stripped from dist/lite/pipelines.d.ts during the build +// so it needs to be re-added here. +declare module '@firebase/firestore' { + interface Firestore { + pipeline(): PipelineSource; + } + interface Query { + pipeline(): Pipeline; + } +} + +export * from "../dist/pipelines"; diff --git a/packages/firestore/src/api/pipeline_impl.ts b/packages/firestore/src/api/pipeline_impl.ts index c0b15d19955..a8cdf38cf0d 100644 --- a/packages/firestore/src/api/pipeline_impl.ts +++ b/packages/firestore/src/api/pipeline_impl.ts @@ -27,12 +27,6 @@ import { Firestore } from './database'; import { Query } from './reference'; import { ExpUserDataWriter } from './user_data_writer'; -declare module './database' { - interface Firestore { - pipeline(): PipelineSource; - } -} - /** * Experimental Modular API for console testing. * @param firestore @@ -79,12 +73,12 @@ export function execute(pipeline: LitePipeline): Promise { return pipeline.execute(); } -// Augument the Firestore class with the pipeline() factory method +// Augment the Firestore class with the pipeline() factory method Firestore.prototype.pipeline = function (): PipelineSource { return pipeline(this); }; -// Augument the Query class with the pipeline() factory method +// Augment the Query class with the pipeline() factory method Query.prototype.pipeline = function (): Pipeline { return pipeline(this); }; From 718ba98f81d7a099b66175415770d1a0a940fed9 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 10 Jan 2025 12:25:51 -0700 Subject: [PATCH 11/75] Add missing Expr export --- packages/firestore/src/api_pipelines.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index b089e91533e..90fe836932f 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -107,6 +107,7 @@ export { genericFunction, ascending, descending, + Expr, ExprWithAlias, Field, Fields, From 99ca19326d12e7030aa19dced69eb50f61ac1e66 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 10 Jan 2025 13:48:26 -0700 Subject: [PATCH 12/75] Lint fixes --- packages/firestore/.eslintrc.js | 2 +- packages/firestore/lite/pipelines/pipelines.d.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/firestore/.eslintrc.js b/packages/firestore/.eslintrc.js index 5dd443333d9..9ffb1d0279b 100644 --- a/packages/firestore/.eslintrc.js +++ b/packages/firestore/.eslintrc.js @@ -24,7 +24,7 @@ module.exports = { tsconfigRootDir: __dirname }, plugins: ['import'], - ignorePatterns: ['compat/*'], + ignorePatterns: ['compat/*', 'pipelines.d.ts'], rules: { 'no-console': ['error', { allow: ['warn', 'error'] }], '@typescript-eslint/no-unused-vars': [ diff --git a/packages/firestore/lite/pipelines/pipelines.d.ts b/packages/firestore/lite/pipelines/pipelines.d.ts index f9375092bf9..e1243ebe907 100644 --- a/packages/firestore/lite/pipelines/pipelines.d.ts +++ b/packages/firestore/lite/pipelines/pipelines.d.ts @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {PipelineSource, Pipeline} from "../../dist/lite/pipelines"; +import { PipelineSource, Pipeline } from '../../dist/lite/pipelines'; // Augument the Firestore class with the pipeline() method. // This is stripped from dist/lite/pipelines.d.ts during the build @@ -25,4 +25,4 @@ declare module '@firebase/firestore' { } } -export * from "../../dist/lite/pipelines"; +export * from '../../dist/lite/pipelines'; From c911f97fc059e48243f67198ddb28818779a10af Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 10 Jan 2025 13:54:34 -0700 Subject: [PATCH 13/75] TODO cleanup --- .../firestore/src/lite-api/expressions.ts | 1 - .../test/integration/api/pipeline.test.ts | 34 ------------------- 2 files changed, 35 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 7d0a7bcf371..65434c2f287 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -2118,7 +2118,6 @@ export class Constant extends Expr { */ static of(value: DocumentReference): Constant; - // TODO(pipeline) if we make this public, then the Proto types should also be documented /** * Creates a `Constant` instance for a Firestore proto value. * @private diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index d6edba1718b..07da8990d94 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -907,40 +907,6 @@ apiDescribe('Pipelines', persistence => { const proto = _internalPipelineToExecutePipelineRequestProto(pipeline); expect(proto).not.to.be.null; }); - - // TODO(pipeline) support converter - // it('pipeline converter works', async () => { - // interface AppModel {myTitle: string; myAuthor: string; myPublished: number} - // const converter: FirestorePipelineConverter = { - // fromFirestore(result: FirebaseFirestore.PipelineResult): AppModel { - // return { - // myTitle: result.data()!.title as string, - // myAuthor: result.data()!.author as string, - // myPublished: result.data()!.published as number, - // }; - // }, - // }; - // - // const results = await firestore - // .pipeline() - // .collection(randomCol.path) - // .sort(Field.of('published').ascending()) - // .limit(2) - // .withConverter(converter) - // .execute(); - // - // const objs = results.map(r => r.data()); - // expect(objs[0]).to.deep.equal({ - // myAuthor: 'Jane Austen', - // myPublished: 1813, - // myTitle: 'Pride and Prejudice', - // }); - // expect(objs[1]).to.deep.equal({ - // myAuthor: 'Fyodor Dostoevsky', - // myPublished: 1866, - // myTitle: 'Crime and Punishment', - // }); - // }); }); describe('modular API', () => { From 229b0c76aa44c898426fd3f06ec78b52fa105988 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 10 Jan 2025 15:15:08 -0700 Subject: [PATCH 14/75] update api review --- .../firestore-lite-pipelines.api.md | 1117 ++++++++------ common/api-review/firestore-pipelines.api.md | 977 ++++-------- common/api-review/firestore.api.md | 1329 ++++++++++++++++- 3 files changed, 2313 insertions(+), 1110 deletions(-) diff --git a/common/api-review/firestore-lite-pipelines.api.md b/common/api-review/firestore-lite-pipelines.api.md index aea9018ae4c..aa7e062f068 100644 --- a/common/api-review/firestore-lite-pipelines.api.md +++ b/common/api-review/firestore-lite-pipelines.api.md @@ -10,119 +10,220 @@ import { FirebaseApp } from '@firebase/app'; export interface Accumulator { // (undocumented) accumulator: true; + add(other: Accumulator): Add; + add(other: any): Add; + arrayConcat(...arrays: Accumulator[]): ArrayConcat; + arrayConcat(...arrays: any[][]): ArrayConcat; + arrayContains(element: Accumulator): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Accumulator): CosineDistance; + // Warning: (ae-forgotten-export) The symbol "VectorValue" needs to be exported by the entry point pipelines.d.ts + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Accumulator): Divide; + divide(other: any): Divide; + dotProduct(other: Accumulator): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Accumulator): EndsWith; + eq(other: Accumulator): Eq; + eq(other: any): Eq; + eqAny(...others: Accumulator[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Accumulator): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + gt(other: Accumulator): Gt; + gt(other: any): Gt; + gte(other: Accumulator): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Accumulator): Like; + logicalMaximum(other: Accumulator): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Accumulator): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Accumulator): Lt; + lt(other: any): Lt; + lte(other: Accumulator): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Accumulator): Mod; + mod(other: any): Mod; + multiply(other: Accumulator): Multiply; + multiply(other: any): Multiply; + neq(other: Accumulator): Neq; + neq(other: any): Neq; + notEqAny(...others: Accumulator[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Accumulator): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Accumulator): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; + reverse(): Reverse; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Accumulator): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Accumulator): StrContains; + subtract(other: Accumulator): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; } // @beta -export type AccumulatorTarget = ExprWithAlias; +export type AccumulatorTarget = ExprWithAlias; // @beta (undocumented) export class Add extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); } // @beta -export function add(left: Constant, right: Constant): Add; +export function add(left: Accumulator, right: Accumulator): Add; // @beta -export function add(left: Constant, right: any): Add; +export function add(left: Accumulator, right: any): Add; // @beta -export function add(left: string, right: Constant): Add; +export function add(left: string, right: Accumulator): Add; // @beta export function add(left: string, right: any): Add; // @beta (undocumented) export class AddFields implements Stage { - constructor(fields: Map); + constructor(fields: Map); // (undocumented) name: string; } // @beta (undocumented) export class Aggregate implements Stage { - constructor(accumulators: Map, groups: Map); + constructor(accumulators: Map, groups: Map); // (undocumented) name: string; } // @beta (undocumented) export class And extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterExpr[]); + constructor(conditions: (FilterCondition)[]); // (undocumented) filterable: true; } // @beta (undocumented) export class ArrayConcat extends FirestoreFunction { - constructor(array: Constant, elements: Constant[]); + constructor(array: Accumulator, elements: Accumulator[]); } // @beta -export function arrayConcat(array: Constant, elements: Constant[]): ArrayConcat; +export function arrayConcat(array: Accumulator, elements: Accumulator[]): ArrayConcat; // @beta -export function arrayConcat(array: Constant, elements: any[]): ArrayConcat; +export function arrayConcat(array: Accumulator, elements: any[]): ArrayConcat; // @beta -export function arrayConcat(array: string, elements: Constant[]): ArrayConcat; +export function arrayConcat(array: string, elements: Accumulator[]): ArrayConcat; // @beta export function arrayConcat(array: string, elements: any[]): ArrayConcat; // @beta (undocumented) export class ArrayContains extends FirestoreFunction implements FilterCondition { - constructor(array: Constant, element: Constant); + constructor(array: Accumulator, element: Accumulator); // (undocumented) filterable: true; } // @beta -export function arrayContains(array: Constant, element: Constant): ArrayContains; +export function arrayContains(array: Accumulator, element: Accumulator): ArrayContains; // @beta -export function arrayContains(array: Constant, element: any): ArrayContains; +export function arrayContains(array: Accumulator, element: any): ArrayContains; // @beta -export function arrayContains(array: string, element: Constant): ArrayContains; +export function arrayContains(array: string, element: Accumulator): ArrayContains; // @beta export function arrayContains(array: string, element: any): ArrayContains; // @beta (undocumented) export class ArrayContainsAll extends FirestoreFunction implements FilterCondition { - constructor(array: Constant, values: Constant[]); + constructor(array: Accumulator, values: Accumulator[]); // (undocumented) filterable: true; } // @beta -export function arrayContainsAll(array: Constant, values: Constant[]): ArrayContainsAll; +export function arrayContainsAll(array: Accumulator, values: Accumulator[]): ArrayContainsAll; // @beta -export function arrayContainsAll(array: Constant, values: any[]): ArrayContainsAll; +export function arrayContainsAll(array: Accumulator, values: any[]): ArrayContainsAll; // @beta -export function arrayContainsAll(array: string, values: Constant[]): ArrayContainsAll; +export function arrayContainsAll(array: string, values: Accumulator[]): ArrayContainsAll; // @beta export function arrayContainsAll(array: string, values: any[]): ArrayContainsAll; // @beta (undocumented) export class ArrayContainsAny extends FirestoreFunction implements FilterCondition { - constructor(array: Constant, values: Constant[]); + constructor(array: Accumulator, values: Accumulator[]); // (undocumented) filterable: true; } // @beta -export function arrayContainsAny(array: Constant, values: Constant[]): ArrayContainsAny; +export function arrayContainsAny(array: Accumulator, values: Accumulator[]): ArrayContainsAny; // @beta -export function arrayContainsAny(array: Constant, values: any[]): ArrayContainsAny; +export function arrayContainsAny(array: Accumulator, values: any[]): ArrayContainsAny; // @beta -export function arrayContainsAny(array: string, values: Constant[]): ArrayContainsAny; +export function arrayContainsAny(array: string, values: Accumulator[]): ArrayContainsAny; // @beta export function arrayContainsAny(array: string, values: any[]): ArrayContainsAny; @@ -134,48 +235,48 @@ export class ArrayElement extends FirestoreFunction { // @beta (undocumented) export class ArrayLength extends FirestoreFunction { - constructor(array: Constant); + constructor(array: Accumulator); } // @beta -export function arrayLength(array: Constant): ArrayLength; +export function arrayLength(array: Accumulator): ArrayLength; // @beta (undocumented) export class ArrayReverse extends FirestoreFunction { - constructor(array: Constant); + constructor(array: Accumulator); } // @beta -export function ascending(expr: Constant): Ordering; +export function ascending(expr: Accumulator): Ordering; // @beta (undocumented) export class Avg extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); + constructor(value: Accumulator, distinct: boolean); // (undocumented) accumulator: true; } // @beta (undocumented) export class ByteLength extends FirestoreFunction { - constructor(value: Constant); + constructor(value: Accumulator); } // @beta -export function byteLength(expr: Constant): ByteLength; +export function byteLength(expr: Accumulator): ByteLength; // @beta export function byteLength(field: string): ByteLength; // @beta (undocumented) export class CharLength extends FirestoreFunction { - constructor(value: Constant); + constructor(value: Accumulator); } // @beta export function charLength(field: string): CharLength; // @beta -export function charLength(expr: Constant): CharLength; +export function charLength(expr: Accumulator): CharLength; // @beta (undocumented) export class CollectionGroupSource implements Stage { @@ -192,26 +293,26 @@ export class CollectionSource implements Stage { } // @beta (undocumented) -export class Cond extends FirestoreFunction implements FilterCondition { - constructor(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant); +export class Cond extends FirestoreFunction { + constructor(condition: FilterCondition, thenExpr: Accumulator, elseExpr: Accumulator); // (undocumented) filterable: true; } // @beta -export function cond(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant): Cond; +export function cond(condition: FilterCondition, thenExpr: Accumulator, elseExpr: Accumulator): Cond; // @beta export class Constant { - add(other: Constant): Add; + add(other: Accumulator): Add; add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; + arrayConcat(...arrays: Accumulator[]): ArrayConcat; + arrayConcat(...arrays: any[][]): ArrayConcat; + arrayContains(element: Accumulator): ArrayContains; arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; arrayContainsAny(...values: any[]): ArrayContainsAny; arrayLength(): ArrayLength; as(name: string): ExprWithAlias; @@ -219,57 +320,57 @@ export class Constant { avg(): Avg; byteLength(): ByteLength; charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: Accumulator): CosineDistance; cosineDistance(other: VectorValue): CosineDistance; cosineDistance(other: number[]): CosineDistance; count(): Count; descending(): Ordering; - divide(other: Constant): Divide; + divide(other: Accumulator): Divide; divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; + dotProduct(other: Accumulator): DotProduct; dotProduct(other: VectorValue): DotProduct; // (undocumented) dotProduct(other: number[]): DotProduct; endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; + endsWith(suffix: Accumulator): EndsWith; + eq(other: Accumulator): Eq; eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; + eqAny(...others: Accumulator[]): EqAny; // (undocumented) eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: Accumulator): EuclideanDistance; euclideanDistance(other: VectorValue): EuclideanDistance; // (undocumented) euclideanDistance(other: number[]): EuclideanDistance; exists(): Exists; // (undocumented) exprType: ExprType; - gt(other: Constant): Gt; + gt(other: Accumulator): Gt; gt(other: any): Gt; - gte(other: Constant): Gte; + gte(other: Accumulator): Gte; gte(other: any): Gte; isNaN(): IsNan; like(pattern: string): Like; // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; + like(pattern: Accumulator): Like; + logicalMaximum(other: Accumulator): LogicalMaximum; logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: Accumulator): LogicalMinimum; logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; + lt(other: Accumulator): Lt; lt(other: any): Lt; - lte(other: Constant): Lte; + lte(other: Accumulator): Lte; lte(other: any): Lte; mapGet(subfield: string): MapGet; maximum(): Maximum; minimum(): Minimum; - mod(other: Constant): Mod; + mod(other: Accumulator): Mod; mod(other: any): Mod; - multiply(other: Constant): Multiply; + multiply(other: Accumulator): Multiply; multiply(other: any): Multiply; - neq(other: Constant): Neq; + neq(other: Accumulator): Neq; neq(other: any): Neq; - notEqAny(...others: Constant[]): FirestoreFunction; + notEqAny(...others: Accumulator[]): FirestoreFunction; // (undocumented) notEqAny(...others: any[]): FirestoreFunction; static of(value: number): Constant; @@ -287,28 +388,27 @@ export class Constant { static of(value: DocumentReference): Constant; static of(value: any[]): Constant; static of(value: Map): Constant; - // Warning: (ae-forgotten-export) The symbol "VectorValue" needs to be exported by the entry point pipelines.d.ts static of(value: VectorValue): Constant; regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; + regexContains(pattern: Accumulator): RegexContains; regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; + regexMatch(pattern: Accumulator): RegexMatch; replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; reverse(): Reverse; startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; + startsWith(prefix: Accumulator): StartsWith; + strConcat(...elements: Array): StrConcat; strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; + strContains(expr: Accumulator): StrContains; + subtract(other: Accumulator): Subtract; subtract(other: any): Subtract; sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; timestampToUnixMicros(): TimestampToUnixMicros; timestampToUnixMillis(): TimestampToUnixMillis; @@ -325,7 +425,7 @@ export class Constant { // @beta (undocumented) export class CosineDistance extends FirestoreFunction { - constructor(vector1: Constant, vector2: Constant); + constructor(vector1: Accumulator, vector2: Accumulator); } // @beta @@ -335,20 +435,20 @@ export function cosineDistance(expr: string, other: number[]): CosineDistance; export function cosineDistance(expr: string, other: VectorValue): CosineDistance; // @beta -export function cosineDistance(expr: string, other: Constant): CosineDistance; +export function cosineDistance(expr: string, other: Accumulator): CosineDistance; // @beta -export function cosineDistance(expr: Constant, other: number[]): CosineDistance; +export function cosineDistance(expr: Accumulator, other: number[]): CosineDistance; // @beta -export function cosineDistance(expr: Constant, other: VectorValue): CosineDistance; +export function cosineDistance(expr: Accumulator, other: VectorValue): CosineDistance; // @beta -export function cosineDistance(expr: Constant, other: Constant): CosineDistance; +export function cosineDistance(expr: Accumulator, other: Accumulator): CosineDistance; // @beta (undocumented) export class Count extends FirestoreFunction implements Accumulator { - constructor(value: Constant | undefined, distinct: boolean); + constructor(value: Accumulator | undefined, distinct: boolean); // (undocumented) accumulator: true; } @@ -363,28 +463,28 @@ export class DatabaseSource implements Stage { } // @beta -export function descending(expr: Constant): Ordering; +export function descending(expr: Accumulator): Ordering; // @beta (undocumented) export class Distinct implements Stage { - constructor(groups: Map); + constructor(groups: Map); // (undocumented) name: string; } // @beta (undocumented) export class Divide extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); } // @beta -export function divide(left: Constant, right: Constant): Divide; +export function divide(left: Accumulator, right: Accumulator): Divide; // @beta -export function divide(left: Constant, right: any): Divide; +export function divide(left: Accumulator, right: any): Divide; // @beta -export function divide(left: string, right: Constant): Divide; +export function divide(left: string, right: Accumulator): Divide; // @beta export function divide(left: string, right: any): Divide; @@ -400,7 +500,7 @@ export class DocumentsSource implements Stage { // @beta (undocumented) export class DotProduct extends FirestoreFunction { - constructor(vector1: Constant, vector2: Constant); + constructor(vector1: Accumulator, vector2: Accumulator); } // @beta @@ -410,20 +510,20 @@ export function dotProduct(expr: string, other: number[]): DotProduct; export function dotProduct(expr: string, other: VectorValue): DotProduct; // @beta -export function dotProduct(expr: string, other: Constant): DotProduct; +export function dotProduct(expr: string, other: Accumulator): DotProduct; // @beta -export function dotProduct(expr: Constant, other: number[]): DotProduct; +export function dotProduct(expr: Accumulator, other: number[]): DotProduct; // @beta -export function dotProduct(expr: Constant, other: VectorValue): DotProduct; +export function dotProduct(expr: Accumulator, other: VectorValue): DotProduct; // @beta -export function dotProduct(expr: Constant, other: Constant): DotProduct; +export function dotProduct(expr: Accumulator, other: Accumulator): DotProduct; // @beta (undocumented) export class EndsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, suffix: Constant); + constructor(expr: Accumulator, suffix: Accumulator); // (undocumented) filterable: true; } @@ -432,55 +532,55 @@ export class EndsWith extends FirestoreFunction implements FilterCondition { export function endsWith(expr: string, suffix: string): EndsWith; // @beta -export function endsWith(expr: string, suffix: Constant): EndsWith; +export function endsWith(expr: string, suffix: Accumulator): EndsWith; // @beta -export function endsWith(expr: Constant, suffix: string): EndsWith; +export function endsWith(expr: Accumulator, suffix: string): EndsWith; // @beta -export function endsWith(expr: Constant, suffix: Constant): EndsWith; +export function endsWith(expr: Accumulator, suffix: Accumulator): EndsWith; // @beta (undocumented) export class Eq extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); // (undocumented) filterable: true; } // @beta -export function eq(left: Constant, right: Constant): Eq; +export function eq(left: Accumulator, right: Accumulator): Eq; // @beta -export function eq(left: Constant, right: any): Eq; +export function eq(left: Accumulator, right: any): Eq; // @beta -export function eq(left: string, right: Constant): Eq; +export function eq(left: string, right: Accumulator): Eq; // @beta export function eq(left: string, right: any): Eq; // @beta (undocumented) export class EqAny extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, others: Constant[]); + constructor(left: Accumulator, others: Accumulator[]); // (undocumented) filterable: true; } // @beta -export function eqAny(element: Constant, others: Constant[]): EqAny; +export function eqAny(element: Accumulator, others: Accumulator[]): EqAny; // @beta -export function eqAny(element: Constant, others: any[]): EqAny; +export function eqAny(element: Accumulator, others: any[]): EqAny; // @beta -export function eqAny(element: string, others: Constant[]): EqAny; +export function eqAny(element: string, others: Accumulator[]): EqAny; // @beta export function eqAny(element: string, others: any[]): EqAny; // @beta (undocumented) export class EuclideanDistance extends FirestoreFunction { - constructor(vector1: Constant, vector2: Constant); + constructor(vector1: Accumulator, vector2: Accumulator); } // @beta @@ -490,29 +590,29 @@ export function euclideanDistance(expr: string, other: number[]): EuclideanDista export function euclideanDistance(expr: string, other: VectorValue): EuclideanDistance; // @beta -export function euclideanDistance(expr: string, other: Constant): EuclideanDistance; +export function euclideanDistance(expr: string, other: Accumulator): EuclideanDistance; // @beta -export function euclideanDistance(expr: Constant, other: number[]): EuclideanDistance; +export function euclideanDistance(expr: Accumulator, other: number[]): EuclideanDistance; // @beta -export function euclideanDistance(expr: Constant, other: VectorValue): EuclideanDistance; +export function euclideanDistance(expr: Accumulator, other: VectorValue): EuclideanDistance; // @beta -export function euclideanDistance(expr: Constant, other: Constant): EuclideanDistance; +export function euclideanDistance(expr: Accumulator, other: Accumulator): EuclideanDistance; // @beta -export function execute(pipeline: Pipeline): Promise>>; +export function execute(pipeline: Pipeline): Promise; // @beta (undocumented) export class Exists extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant); + constructor(expr: Accumulator); // (undocumented) filterable: true; } // @beta -export function exists(value: Constant): Exists; +export function exists(value: Accumulator): Exists; // @beta export function exists(field: string): Exists; @@ -521,19 +621,19 @@ export function exists(field: string): Exists; export type ExprType = 'Field' | 'Constant' | 'Function' | 'ListOfExprs' | 'ExprWithAlias'; // @beta (undocumented) -export class ExprWithAlias implements Selectable { +export class ExprWithAlias implements Selectable { constructor(expr: T, alias: string); - add(other: Constant): Add; + add(other: Accumulator): Add; add(other: any): Add; // (undocumented) - alias: string; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; + readonly alias: string; + arrayConcat(...arrays: Accumulator[]): ArrayConcat; + arrayConcat(...arrays: any[][]): ArrayConcat; + arrayContains(element: Accumulator): ArrayContains; arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; arrayContainsAny(...values: any[]): ArrayContainsAny; arrayLength(): ArrayLength; as(name: string): ExprWithAlias; @@ -541,83 +641,83 @@ export class ExprWithAlias implements Selectable { avg(): Avg; byteLength(): ByteLength; charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: Accumulator): CosineDistance; cosineDistance(other: VectorValue): CosineDistance; cosineDistance(other: number[]): CosineDistance; count(): Count; descending(): Ordering; - divide(other: Constant): Divide; + divide(other: Accumulator): Divide; divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; + dotProduct(other: Accumulator): DotProduct; dotProduct(other: VectorValue): DotProduct; // (undocumented) dotProduct(other: number[]): DotProduct; endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; + endsWith(suffix: Accumulator): EndsWith; + eq(other: Accumulator): Eq; eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; + eqAny(...others: Accumulator[]): EqAny; // (undocumented) eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: Accumulator): EuclideanDistance; euclideanDistance(other: VectorValue): EuclideanDistance; // (undocumented) euclideanDistance(other: number[]): EuclideanDistance; exists(): Exists; // (undocumented) - expr: T; + readonly expr: T; // (undocumented) exprType: ExprType; - gt(other: Constant): Gt; + gt(other: Accumulator): Gt; gt(other: any): Gt; - gte(other: Constant): Gte; + gte(other: Accumulator): Gte; gte(other: any): Gte; isNaN(): IsNan; like(pattern: string): Like; // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; + like(pattern: Accumulator): Like; + logicalMaximum(other: Accumulator): LogicalMaximum; logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: Accumulator): LogicalMinimum; logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; + lt(other: Accumulator): Lt; lt(other: any): Lt; - lte(other: Constant): Lte; + lte(other: Accumulator): Lte; lte(other: any): Lte; mapGet(subfield: string): MapGet; maximum(): Maximum; minimum(): Minimum; - mod(other: Constant): Mod; + mod(other: Accumulator): Mod; mod(other: any): Mod; - multiply(other: Constant): Multiply; + multiply(other: Accumulator): Multiply; multiply(other: any): Multiply; - neq(other: Constant): Neq; + neq(other: Accumulator): Neq; neq(other: any): Neq; - notEqAny(...others: Constant[]): FirestoreFunction; + notEqAny(...others: Accumulator[]): FirestoreFunction; // (undocumented) notEqAny(...others: any[]): FirestoreFunction; regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; + regexContains(pattern: Accumulator): RegexContains; regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; + regexMatch(pattern: Accumulator): RegexMatch; replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; reverse(): Reverse; // (undocumented) selectable: true; startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; + startsWith(prefix: Accumulator): StartsWith; + strConcat(...elements: Array): StrConcat; strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; + strContains(expr: Accumulator): StrContains; + subtract(other: Accumulator): Subtract; subtract(other: any): Subtract; sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; timestampToUnixMicros(): TimestampToUnixMicros; timestampToUnixMillis(): TimestampToUnixMillis; @@ -633,15 +733,15 @@ export class ExprWithAlias implements Selectable { // @beta export class Field implements Selectable { - add(other: Constant): Add; + add(other: Accumulator): Add; add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; + arrayConcat(...arrays: Accumulator[]): ArrayConcat; + arrayConcat(...arrays: any[][]): ArrayConcat; + arrayContains(element: Accumulator): ArrayContains; arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; arrayContainsAny(...values: any[]): ArrayContainsAny; arrayLength(): ArrayLength; as(name: string): ExprWithAlias; @@ -649,25 +749,25 @@ export class Field implements Selectable { avg(): Avg; byteLength(): ByteLength; charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: Accumulator): CosineDistance; cosineDistance(other: VectorValue): CosineDistance; cosineDistance(other: number[]): CosineDistance; count(): Count; descending(): Ordering; - divide(other: Constant): Divide; + divide(other: Accumulator): Divide; divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; + dotProduct(other: Accumulator): DotProduct; dotProduct(other: VectorValue): DotProduct; // (undocumented) dotProduct(other: number[]): DotProduct; endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; + endsWith(suffix: Accumulator): EndsWith; + eq(other: Accumulator): Eq; eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; + eqAny(...others: Accumulator[]): EqAny; // (undocumented) eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: Accumulator): EuclideanDistance; euclideanDistance(other: VectorValue): EuclideanDistance; // (undocumented) euclideanDistance(other: number[]): EuclideanDistance; @@ -676,32 +776,32 @@ export class Field implements Selectable { exprType: ExprType; // (undocumented) fieldName(): string; - gt(other: Constant): Gt; + gt(other: Accumulator): Gt; gt(other: any): Gt; - gte(other: Constant): Gte; + gte(other: Accumulator): Gte; gte(other: any): Gte; isNaN(): IsNan; like(pattern: string): Like; // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; + like(pattern: Accumulator): Like; + logicalMaximum(other: Accumulator): LogicalMaximum; logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: Accumulator): LogicalMinimum; logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; + lt(other: Accumulator): Lt; lt(other: any): Lt; - lte(other: Constant): Lte; + lte(other: Accumulator): Lte; lte(other: any): Lte; mapGet(subfield: string): MapGet; maximum(): Maximum; minimum(): Minimum; - mod(other: Constant): Mod; + mod(other: Accumulator): Mod; mod(other: any): Mod; - multiply(other: Constant): Multiply; + multiply(other: Accumulator): Multiply; multiply(other: any): Multiply; - neq(other: Constant): Neq; + neq(other: Accumulator): Neq; neq(other: any): Neq; - notEqAny(...others: Constant[]): FirestoreFunction; + notEqAny(...others: Accumulator[]): FirestoreFunction; // (undocumented) notEqAny(...others: any[]): FirestoreFunction; static of(name: string): Field; @@ -712,27 +812,27 @@ export class Field implements Selectable { // (undocumented) static of(pipeline: Pipeline, name: string): Field; regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; + regexContains(pattern: Accumulator): RegexContains; regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; + regexMatch(pattern: Accumulator): RegexMatch; replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; reverse(): Reverse; // (undocumented) selectable: true; startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; + startsWith(prefix: Accumulator): StartsWith; + strConcat(...elements: Array): StrConcat; strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; + strContains(expr: Accumulator): StrContains; + subtract(other: Accumulator): Subtract; subtract(other: any): Subtract; sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; timestampToUnixMicros(): TimestampToUnixMicros; timestampToUnixMillis(): TimestampToUnixMillis; @@ -748,15 +848,15 @@ export class Field implements Selectable { // @beta (undocumented) export class Fields implements Selectable { - add(other: Constant): Add; + add(other: Accumulator): Add; add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; + arrayConcat(...arrays: Accumulator[]): ArrayConcat; + arrayConcat(...arrays: any[][]): ArrayConcat; + arrayContains(element: Accumulator): ArrayContains; arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; arrayContainsAny(...values: any[]): ArrayContainsAny; arrayLength(): ArrayLength; as(name: string): ExprWithAlias; @@ -764,25 +864,25 @@ export class Fields implements Selectable { avg(): Avg; byteLength(): ByteLength; charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: Accumulator): CosineDistance; cosineDistance(other: VectorValue): CosineDistance; cosineDistance(other: number[]): CosineDistance; count(): Count; descending(): Ordering; - divide(other: Constant): Divide; + divide(other: Accumulator): Divide; divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; + dotProduct(other: Accumulator): DotProduct; dotProduct(other: VectorValue): DotProduct; // (undocumented) dotProduct(other: number[]): DotProduct; endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; + endsWith(suffix: Accumulator): EndsWith; + eq(other: Accumulator): Eq; eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; + eqAny(...others: Accumulator[]): EqAny; // (undocumented) eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: Accumulator): EuclideanDistance; euclideanDistance(other: VectorValue): EuclideanDistance; // (undocumented) euclideanDistance(other: number[]): EuclideanDistance; @@ -791,32 +891,32 @@ export class Fields implements Selectable { exprType: ExprType; // (undocumented) fieldList(): Field[]; - gt(other: Constant): Gt; + gt(other: Accumulator): Gt; gt(other: any): Gt; - gte(other: Constant): Gte; + gte(other: Accumulator): Gte; gte(other: any): Gte; isNaN(): IsNan; like(pattern: string): Like; // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; + like(pattern: Accumulator): Like; + logicalMaximum(other: Accumulator): LogicalMaximum; logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: Accumulator): LogicalMinimum; logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; + lt(other: Accumulator): Lt; lt(other: any): Lt; - lte(other: Constant): Lte; + lte(other: Accumulator): Lte; lte(other: any): Lte; mapGet(subfield: string): MapGet; maximum(): Maximum; minimum(): Minimum; - mod(other: Constant): Mod; + mod(other: Accumulator): Mod; mod(other: any): Mod; - multiply(other: Constant): Multiply; + multiply(other: Accumulator): Multiply; multiply(other: any): Multiply; - neq(other: Constant): Neq; + neq(other: Accumulator): Neq; neq(other: any): Neq; - notEqAny(...others: Constant[]): FirestoreFunction; + notEqAny(...others: Accumulator[]): FirestoreFunction; // (undocumented) notEqAny(...others: any[]): FirestoreFunction; // (undocumented) @@ -824,27 +924,27 @@ export class Fields implements Selectable { // (undocumented) static ofAll(): Fields; regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; + regexContains(pattern: Accumulator): RegexContains; regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; + regexMatch(pattern: Accumulator): RegexMatch; replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; reverse(): Reverse; // (undocumented) selectable: true; startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; + startsWith(prefix: Accumulator): StartsWith; + strConcat(...elements: Array): StrConcat; strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; + strContains(expr: Accumulator): StrContains; + subtract(other: Accumulator): Subtract; subtract(other: any): Subtract; sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; timestampToUnixMicros(): TimestampToUnixMicros; timestampToUnixMillis(): TimestampToUnixMillis; @@ -860,13 +960,110 @@ export class Fields implements Selectable { // @beta export interface FilterCondition { + add(other: Accumulator): Add; + add(other: any): Add; + arrayConcat(...arrays: Accumulator[]): ArrayConcat; + arrayConcat(...arrays: any[][]): ArrayConcat; + arrayContains(element: Accumulator): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Accumulator): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Accumulator): Divide; + divide(other: any): Divide; + dotProduct(other: Accumulator): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Accumulator): EndsWith; + eq(other: Accumulator): Eq; + eq(other: any): Eq; + eqAny(...others: Accumulator[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Accumulator): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; // (undocumented) filterable: true; + gt(other: Accumulator): Gt; + gt(other: any): Gt; + gte(other: Accumulator): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Accumulator): Like; + logicalMaximum(other: Accumulator): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Accumulator): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Accumulator): Lt; + lt(other: any): Lt; + lte(other: Accumulator): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Accumulator): Mod; + mod(other: any): Mod; + multiply(other: Accumulator): Multiply; + multiply(other: any): Multiply; + neq(other: Accumulator): Neq; + neq(other: any): Neq; + notEqAny(...others: Accumulator[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Accumulator): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Accumulator): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; + reverse(): Reverse; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Accumulator): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Accumulator): StrContains; + subtract(other: Accumulator): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; } -// @beta -export type FilterExpr = Constant & FilterCondition; - // @beta (undocumented) export class FindNearest implements Stage { // (undocumented) @@ -889,16 +1086,16 @@ export interface FindNearestOptions { // @beta export class FirestoreFunction { - constructor(name: string, params: Constant[]); - add(other: Constant): Add; + constructor(name: string, params: Accumulator[]); + add(other: Accumulator): Add; add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; + arrayConcat(...arrays: Accumulator[]): ArrayConcat; + arrayConcat(...arrays: any[][]): ArrayConcat; + arrayContains(element: Accumulator): ArrayContains; arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; arrayContainsAny(...values: any[]): ArrayContainsAny; arrayLength(): ArrayLength; as(name: string): ExprWithAlias; @@ -906,79 +1103,79 @@ export class FirestoreFunction { avg(): Avg; byteLength(): ByteLength; charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: Accumulator): CosineDistance; cosineDistance(other: VectorValue): CosineDistance; cosineDistance(other: number[]): CosineDistance; count(): Count; descending(): Ordering; - divide(other: Constant): Divide; + divide(other: Accumulator): Divide; divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; + dotProduct(other: Accumulator): DotProduct; dotProduct(other: VectorValue): DotProduct; // (undocumented) dotProduct(other: number[]): DotProduct; endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; + endsWith(suffix: Accumulator): EndsWith; + eq(other: Accumulator): Eq; eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; + eqAny(...others: Accumulator[]): EqAny; // (undocumented) eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: Accumulator): EuclideanDistance; euclideanDistance(other: VectorValue): EuclideanDistance; // (undocumented) euclideanDistance(other: number[]): EuclideanDistance; exists(): Exists; // (undocumented) exprType: ExprType; - gt(other: Constant): Gt; + gt(other: Accumulator): Gt; gt(other: any): Gt; - gte(other: Constant): Gte; + gte(other: Accumulator): Gte; gte(other: any): Gte; isNaN(): IsNan; like(pattern: string): Like; // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; + like(pattern: Accumulator): Like; + logicalMaximum(other: Accumulator): LogicalMaximum; logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: Accumulator): LogicalMinimum; logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; + lt(other: Accumulator): Lt; lt(other: any): Lt; - lte(other: Constant): Lte; + lte(other: Accumulator): Lte; lte(other: any): Lte; mapGet(subfield: string): MapGet; maximum(): Maximum; minimum(): Minimum; - mod(other: Constant): Mod; + mod(other: Accumulator): Mod; mod(other: any): Mod; - multiply(other: Constant): Multiply; + multiply(other: Accumulator): Multiply; multiply(other: any): Multiply; - neq(other: Constant): Neq; + neq(other: Accumulator): Neq; neq(other: any): Neq; - notEqAny(...others: Constant[]): FirestoreFunction; + notEqAny(...others: Accumulator[]): FirestoreFunction; // (undocumented) notEqAny(...others: any[]): FirestoreFunction; regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; + regexContains(pattern: Accumulator): RegexContains; regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; + regexMatch(pattern: Accumulator): RegexMatch; replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; reverse(): Reverse; startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; + startsWith(prefix: Accumulator): StartsWith; + strConcat(...elements: Array): StrConcat; strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; + strContains(expr: Accumulator): StrContains; + subtract(other: Accumulator): Subtract; subtract(other: any): Subtract; sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; timestampToUnixMicros(): TimestampToUnixMicros; timestampToUnixMillis(): TimestampToUnixMillis; @@ -993,7 +1190,7 @@ export class FirestoreFunction { } // @beta -export function genericFunction(name: string, params: Constant[]): FirestoreFunction; +export function genericFunction(name: string, params: Accumulator[]): FirestoreFunction; // @beta (undocumented) export class GenericStage implements Stage { @@ -1004,58 +1201,58 @@ export class GenericStage implements Stage { // @beta (undocumented) export class Gt extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); // (undocumented) filterable: true; } // @beta -export function gt(left: Constant, right: Constant): Gt; +export function gt(left: Accumulator, right: Accumulator): Gt; // @beta -export function gt(left: Constant, right: any): Gt; +export function gt(left: Accumulator, right: any): Gt; // @beta -export function gt(left: string, right: Constant): Gt; +export function gt(left: string, right: Accumulator): Gt; // @beta export function gt(left: string, right: any): Gt; // @beta (undocumented) export class Gte extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); // (undocumented) filterable: true; } // @beta -export function gte(left: Constant, right: Constant): Gte; +export function gte(left: Accumulator, right: Accumulator): Gte; // @beta -export function gte(left: Constant, right: any): Gte; +export function gte(left: Accumulator, right: any): Gte; // @beta -export function gte(left: string, right: Constant): Gte; +export function gte(left: string, right: Accumulator): Gte; // @beta export function gte(left: string, right: any): Gte; // @beta (undocumented) export class IsNan extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant); + constructor(expr: Accumulator); // (undocumented) filterable: true; } // @beta -export function isNan(value: Constant): IsNan; +export function isNan(value: Accumulator): IsNan; // @beta export function isNan(value: string): IsNan; // @beta (undocumented) export class Like extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, pattern: Constant); + constructor(expr: Accumulator, pattern: Accumulator); // (undocumented) filterable: true; } @@ -1064,13 +1261,13 @@ export class Like extends FirestoreFunction implements FilterCondition { export function like(left: string, pattern: string): Like; // @beta -export function like(left: string, pattern: Constant): Like; +export function like(left: string, pattern: Accumulator): Like; // @beta -export function like(left: Constant, pattern: string): Like; +export function like(left: Accumulator, pattern: string): Like; // @beta -export function like(left: Constant, pattern: Constant): Like; +export function like(left: Accumulator, pattern: Accumulator): Like; // @beta (undocumented) export class Limit implements Stage { @@ -1081,187 +1278,187 @@ export class Limit implements Stage { // @beta (undocumented) export class LogicalMaximum extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); } // @beta -export function logicalMaximum(left: Constant, right: Constant): LogicalMaximum; +export function logicalMaximum(left: Accumulator, right: Accumulator): LogicalMaximum; // @beta -export function logicalMaximum(left: Constant, right: any): LogicalMaximum; +export function logicalMaximum(left: Accumulator, right: any): LogicalMaximum; // @beta -export function logicalMaximum(left: string, right: Constant): LogicalMaximum; +export function logicalMaximum(left: string, right: Accumulator): LogicalMaximum; // @beta export function logicalMaximum(left: string, right: any): LogicalMaximum; // @beta (undocumented) export class LogicalMinimum extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); } // @beta -export function logicalMinimum(left: Constant, right: Constant): LogicalMinimum; +export function logicalMinimum(left: Accumulator, right: Accumulator): LogicalMinimum; // @beta -export function logicalMinimum(left: Constant, right: any): LogicalMinimum; +export function logicalMinimum(left: Accumulator, right: any): LogicalMinimum; // @beta -export function logicalMinimum(left: string, right: Constant): LogicalMinimum; +export function logicalMinimum(left: string, right: Accumulator): LogicalMinimum; // @beta export function logicalMinimum(left: string, right: any): LogicalMinimum; // @beta (undocumented) export class Lt extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); // (undocumented) filterable: true; } // @beta -export function lt(left: Constant, right: Constant): Lt; +export function lt(left: Accumulator, right: Accumulator): Lt; // @beta -export function lt(left: Constant, right: any): Lt; +export function lt(left: Accumulator, right: any): Lt; // @beta -export function lt(left: string, right: Constant): Lt; +export function lt(left: string, right: Accumulator): Lt; // @beta export function lt(left: string, right: any): Lt; // @beta (undocumented) export class Lte extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); // (undocumented) filterable: true; } // @beta -export function lte(left: Constant, right: Constant): Lte; +export function lte(left: Accumulator, right: Accumulator): Lte; // @beta -export function lte(left: Constant, right: any): Lte; +export function lte(left: Accumulator, right: any): Lte; -// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Constant" which is marked as @beta +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Accumulator" which is marked as @beta // Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Lte" which is marked as @beta // // @public -export function lte(left: string, right: Constant): Lte; +export function lte(left: string, right: Accumulator): Lte; // @beta export function lte(left: string, right: any): Lte; // @beta (undocumented) export class MapGet extends FirestoreFunction { - constructor(map: Constant, name: string); + constructor(map: Accumulator, name: string); } // @beta export function mapGet(mapField: string, subField: string): MapGet; // @beta -export function mapGet(mapExpr: Constant, subField: string): MapGet; +export function mapGet(mapExpr: Accumulator, subField: string): MapGet; // @beta (undocumented) export class Maximum extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); + constructor(value: Accumulator, distinct: boolean); // (undocumented) accumulator: true; } // @beta -export function maximum(value: Constant): Maximum; +export function maximum(value: Accumulator): Maximum; // @beta export function maximum(value: string): Maximum; // @beta (undocumented) export class Minimum extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); + constructor(value: Accumulator, distinct: boolean); // (undocumented) accumulator: true; } // @beta -export function minimum(value: Constant): Minimum; +export function minimum(value: Accumulator): Minimum; // @beta export function minimum(value: string): Minimum; // @beta (undocumented) export class Mod extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); } // @beta -export function mod(left: Constant, right: Constant): Mod; +export function mod(left: Accumulator, right: Accumulator): Mod; // @beta -export function mod(left: Constant, right: any): Mod; +export function mod(left: Accumulator, right: any): Mod; // @beta -export function mod(left: string, right: Constant): Mod; +export function mod(left: string, right: Accumulator): Mod; // @beta export function mod(left: string, right: any): Mod; // @beta (undocumented) export class Multiply extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); } // @beta -export function multiply(left: Constant, right: Constant): Multiply; +export function multiply(left: Accumulator, right: Accumulator): Multiply; // @beta -export function multiply(left: Constant, right: any): Multiply; +export function multiply(left: Accumulator, right: any): Multiply; // @beta -export function multiply(left: string, right: Constant): Multiply; +export function multiply(left: string, right: Accumulator): Multiply; // @beta export function multiply(left: string, right: any): Multiply; // @beta (undocumented) export class Neq extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); // (undocumented) filterable: true; } // @beta -export function neq(left: Constant, right: Constant): Neq; +export function neq(left: Accumulator, right: Accumulator): Neq; // @beta -export function neq(left: Constant, right: any): Neq; +export function neq(left: Accumulator, right: any): Neq; // @beta -export function neq(left: string, right: Constant): Neq; +export function neq(left: string, right: Accumulator): Neq; // @beta export function neq(left: string, right: any): Neq; // @beta (undocumented) export class Not extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant); + constructor(expr: Accumulator); // (undocumented) filterable: true; } // @beta -export function not(filter: FilterExpr): Not; +export function not(filter: FilterCondition): Not; // @beta -export function notEqAny(element: Constant, others: Constant[]): FirestoreFunction; +export function notEqAny(element: Accumulator, others: Accumulator[]): FirestoreFunction; // @beta -export function notEqAny(element: Constant, others: any[]): FirestoreFunction; +export function notEqAny(element: Accumulator, others: any[]): FirestoreFunction; // @beta -export function notEqAny(element: string, others: Constant[]): FirestoreFunction; +export function notEqAny(element: string, others: Accumulator[]): FirestoreFunction; // @beta export function notEqAny(element: string, others: any[]): FirestoreFunction; @@ -1275,88 +1472,79 @@ export class Offset implements Stage { // @beta (undocumented) export class Or extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterExpr[]); + constructor(conditions: (FilterCondition)[]); // (undocumented) filterable: true; } // @beta export class Ordering { - constructor(expr: Constant, direction: 'ascending' | 'descending'); - } + constructor(expr: Accumulator, direction: 'ascending' | 'descending'); + // (undocumented) + readonly direction: 'ascending' | 'descending'; + // (undocumented) + readonly expr: Accumulator; +} -// Warning: (ae-forgotten-export) The symbol "DocumentData" needs to be exported by the entry point pipelines.d.ts -// // @public -export class Pipeline { +export class Pipeline { /* Excluded from this release type: _db */ // Warning: (ae-incompatible-release-tags) The symbol "addFields" is marked as @public, but its signature references "Selectable" which is marked as @beta - addFields(...fields: Selectable[]): Pipeline; + addFields(...fields: Selectable[]): Pipeline; /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta - aggregate(...accumulators: AccumulatorTarget[]): Pipeline; + aggregate(...accumulators: AccumulatorTarget[]): Pipeline; /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ aggregate(options: { accumulators: AccumulatorTarget[]; groups?: Array; - }): Pipeline; + }): Pipeline; /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta - distinct(...groups: Array): Pipeline; + distinct(...groups: Array): Pipeline; /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta - execute(): Promise>>; + execute(): Promise; /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ // Warning: (ae-incompatible-release-tags) The symbol "findNearest" is marked as @public, but its signature references "FindNearestOptions" which is marked as @beta // // (undocumented) - findNearest(options: FindNearestOptions): Pipeline; + findNearest(options: FindNearestOptions): Pipeline; /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - genericStage(name: string, params: any[]): Pipeline; + genericStage(name: string, params: any[]): Pipeline; /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - limit(limit: number): Pipeline; + limit(limit: number): Pipeline; /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ - offset(offset: number): Pipeline; + offset(offset: number): Pipeline; /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ // Warning: (ae-incompatible-release-tags) The symbol "select" is marked as @public, but its signature references "Selectable" which is marked as @beta - select(...selections: Array): Pipeline; + select(...selections: Array): Pipeline; /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ // Warning: (ae-incompatible-release-tags) The symbol "sort" is marked as @public, but its signature references "Ordering" which is marked as @beta - sort(...orderings: Ordering[]): Pipeline; + sort(...orderings: Ordering[]): Pipeline; /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ // (undocumented) sort(options: { orderings: Ordering[]; - }): Pipeline; + }): Pipeline; /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "FilterCondition" which is marked as @beta - // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "Constant" which is marked as @beta - where(condition: FilterCondition & Constant): Pipeline; + where(condition: FilterCondition): Pipeline; } // Warning: (ae-forgotten-export) The symbol "Firestore" needs to be exported by the entry point pipelines.d.ts // Warning: (ae-incompatible-release-tags) The symbol "pipeline" is marked as @public, but its signature references "PipelineSource" which is marked as @beta // // @public -export function pipeline(firestore: Firestore): PipelineSource; +export function pipeline(firestore: Firestore): PipelineSource; // Warning: (ae-forgotten-export) The symbol "Query" needs to be exported by the entry point pipelines.d.ts // // @public export function pipeline(query: Query): Pipeline; +// Warning: (ae-forgotten-export) The symbol "DocumentData" needs to be exported by the entry point pipelines.d.ts +// // @beta export class PipelineResult { /* Excluded from this release type: _ref */ @@ -1372,25 +1560,22 @@ export class PipelineResult { } // @beta -export class PipelineSource { - /* Excluded from this release type: _db */ - /* Excluded from this release type: _userDataReader */ - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ +export class PipelineSource { + /* Excluded from this release type: _createPipeline */ /* Excluded from this release type: __constructor */ // (undocumented) - collection(collectionPath: string): Pipeline; + collection(collectionPath: string): PipelineType; // (undocumented) - collectionGroup(collectionId: string): Pipeline; + collectionGroup(collectionId: string): PipelineType; // (undocumented) - database(): Pipeline; + database(): PipelineType; // (undocumented) - documents(docs: DocumentReference[]): Pipeline; + documents(docs: DocumentReference[]): PipelineType; } // @beta (undocumented) export class RegexContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, pattern: Constant); + constructor(expr: Accumulator, pattern: Accumulator); // (undocumented) filterable: true; } @@ -1399,17 +1584,17 @@ export class RegexContains extends FirestoreFunction implements FilterCondition export function regexContains(left: string, pattern: string): RegexContains; // @beta -export function regexContains(left: string, pattern: Constant): RegexContains; +export function regexContains(left: string, pattern: Accumulator): RegexContains; // @beta -export function regexContains(left: Constant, pattern: string): RegexContains; +export function regexContains(left: Accumulator, pattern: string): RegexContains; // @beta -export function regexContains(left: Constant, pattern: Constant): RegexContains; +export function regexContains(left: Accumulator, pattern: Accumulator): RegexContains; // @beta (undocumented) export class RegexMatch extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, pattern: Constant); + constructor(expr: Accumulator, pattern: Accumulator); // (undocumented) filterable: true; } @@ -1418,69 +1603,166 @@ export class RegexMatch extends FirestoreFunction implements FilterCondition { export function regexMatch(left: string, pattern: string): RegexMatch; // @beta -export function regexMatch(left: string, pattern: Constant): RegexMatch; +export function regexMatch(left: string, pattern: Accumulator): RegexMatch; // @beta -export function regexMatch(left: Constant, pattern: string): RegexMatch; +export function regexMatch(left: Accumulator, pattern: string): RegexMatch; // @beta -export function regexMatch(left: Constant, pattern: Constant): RegexMatch; +export function regexMatch(left: Accumulator, pattern: Accumulator): RegexMatch; // @beta (undocumented) export class ReplaceAll extends FirestoreFunction { - constructor(value: Constant, find: Constant, replace: Constant); + constructor(value: Accumulator, find: Accumulator, replace: Accumulator); } // @beta -export function replaceAll(value: Constant, find: string, replace: string): ReplaceAll; +export function replaceAll(value: Accumulator, find: string, replace: string): ReplaceAll; // @beta -export function replaceAll(value: Constant, find: Constant, replace: Constant): ReplaceAll; +export function replaceAll(value: Accumulator, find: Accumulator, replace: Accumulator): ReplaceAll; // @beta export function replaceAll(field: string, find: string, replace: string): ReplaceAll; // @beta (undocumented) export class ReplaceFirst extends FirestoreFunction { - constructor(value: Constant, find: Constant, replace: Constant); + constructor(value: Accumulator, find: Accumulator, replace: Accumulator); } // @beta -export function replaceFirst(value: Constant, find: string, replace: string): ReplaceFirst; +export function replaceFirst(value: Accumulator, find: string, replace: string): ReplaceFirst; // @beta -export function replaceFirst(value: Constant, find: Constant, replace: Constant): ReplaceFirst; +export function replaceFirst(value: Accumulator, find: Accumulator, replace: Accumulator): ReplaceFirst; // @beta export function replaceFirst(field: string, find: string, replace: string): ReplaceFirst; // @beta (undocumented) export class Reverse extends FirestoreFunction { - constructor(value: Constant); + constructor(value: Accumulator); } // @beta -export function reverse(expr: Constant): Reverse; +export function reverse(expr: Accumulator): Reverse; // @beta export function reverse(field: string): Reverse; // @beta (undocumented) export class Select implements Stage { - constructor(projections: Map); + constructor(projections: Map); // (undocumented) name: string; } // @beta export interface Selectable { + add(other: Accumulator): Add; + add(other: any): Add; + arrayConcat(...arrays: Accumulator[]): ArrayConcat; + arrayConcat(...arrays: any[][]): ArrayConcat; + arrayContains(element: Accumulator): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Accumulator): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Accumulator): Divide; + divide(other: any): Divide; + dotProduct(other: Accumulator): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Accumulator): EndsWith; + eq(other: Accumulator): Eq; + eq(other: any): Eq; + eqAny(...others: Accumulator[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Accumulator): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + gt(other: Accumulator): Gt; + gt(other: any): Gt; + gte(other: Accumulator): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Accumulator): Like; + logicalMaximum(other: Accumulator): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Accumulator): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Accumulator): Lt; + lt(other: any): Lt; + lte(other: Accumulator): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Accumulator): Mod; + mod(other: any): Mod; + multiply(other: Accumulator): Multiply; + multiply(other: any): Multiply; + neq(other: Accumulator): Neq; + neq(other: any): Neq; + notEqAny(...others: Accumulator[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Accumulator): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Accumulator): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; + reverse(): Reverse; // (undocumented) selectable: true; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Accumulator): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Accumulator): StrContains; + subtract(other: Accumulator): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; } -// @beta -export type SelectableExpr = Constant & Selectable; - // @beta (undocumented) export class Sort implements Stage { constructor(orders: Ordering[]); @@ -1496,7 +1778,7 @@ export interface Stage { // @beta (undocumented) export class StartsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, prefix: Constant); + constructor(expr: Accumulator, prefix: Accumulator); // (undocumented) filterable: true; } @@ -1505,28 +1787,28 @@ export class StartsWith extends FirestoreFunction implements FilterCondition { export function startsWith(expr: string, prefix: string): StartsWith; // @beta -export function startsWith(expr: string, prefix: Constant): StartsWith; +export function startsWith(expr: string, prefix: Accumulator): StartsWith; // @beta -export function startsWith(expr: Constant, prefix: string): StartsWith; +export function startsWith(expr: Accumulator, prefix: string): StartsWith; // @beta -export function startsWith(expr: Constant, prefix: Constant): StartsWith; +export function startsWith(expr: Accumulator, prefix: Accumulator): StartsWith; // @beta (undocumented) export class StrConcat extends FirestoreFunction { - constructor(first: Constant, rest: Constant[]); + constructor(first: Accumulator, rest: Accumulator[]); } // @beta -export function strConcat(first: string, ...elements: Array): StrConcat; +export function strConcat(first: string, ...elements: Array): StrConcat; // @beta -export function strConcat(first: Constant, ...elements: Array): StrConcat; +export function strConcat(first: Accumulator, ...elements: Array): StrConcat; // @beta (undocumented) export class StrContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, substring: Constant); + constructor(expr: Accumulator, substring: Accumulator); // (undocumented) filterable: true; } @@ -1535,201 +1817,198 @@ export class StrContains extends FirestoreFunction implements FilterCondition { export function strContains(left: string, substring: string): StrContains; // @beta -export function strContains(left: string, substring: Constant): StrContains; +export function strContains(left: string, substring: Accumulator): StrContains; // @beta -export function strContains(left: Constant, substring: string): StrContains; +export function strContains(left: Accumulator, substring: string): StrContains; // @beta -export function strContains(left: Constant, substring: Constant): StrContains; +export function strContains(left: Accumulator, substring: Accumulator): StrContains; // @beta (undocumented) export class Subtract extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Accumulator, right: Accumulator); } // @beta -export function subtract(left: Constant, right: Constant): Subtract; +export function subtract(left: Accumulator, right: Accumulator): Subtract; // @beta -export function subtract(left: Constant, right: any): Subtract; +export function subtract(left: Accumulator, right: any): Subtract; // @beta -export function subtract(left: string, right: Constant): Subtract; +export function subtract(left: string, right: Accumulator): Subtract; // @beta export function subtract(left: string, right: any): Subtract; // @beta (undocumented) export class Sum extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); + constructor(value: Accumulator, distinct: boolean); // (undocumented) accumulator: true; } // @beta (undocumented) export class TimestampAdd extends FirestoreFunction { - constructor(timestamp: Constant, unit: Constant, amount: Constant); + constructor(timestamp: Accumulator, unit: Accumulator, amount: Accumulator); } // @beta -export function timestampAdd(timestamp: Constant, unit: Constant, amount: Constant): TimestampAdd; +export function timestampAdd(timestamp: Accumulator, unit: Accumulator, amount: Accumulator): TimestampAdd; // @beta -export function timestampAdd(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; +export function timestampAdd(timestamp: Accumulator, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; // @beta export function timestampAdd(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; // @beta (undocumented) export class TimestampSub extends FirestoreFunction { - constructor(timestamp: Constant, unit: Constant, amount: Constant); + constructor(timestamp: Accumulator, unit: Accumulator, amount: Accumulator); } // @beta -export function timestampSub(timestamp: Constant, unit: Constant, amount: Constant): TimestampSub; +export function timestampSub(timestamp: Accumulator, unit: Accumulator, amount: Accumulator): TimestampSub; // @beta -export function timestampSub(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; +export function timestampSub(timestamp: Accumulator, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; // @beta export function timestampSub(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; // @beta (undocumented) export class TimestampToUnixMicros extends FirestoreFunction { - constructor(input: Constant); + constructor(input: Accumulator); } // @beta -export function timestampToUnixMicros(expr: Constant): TimestampToUnixMicros; +export function timestampToUnixMicros(expr: Accumulator): TimestampToUnixMicros; // @beta export function timestampToUnixMicros(field: string): TimestampToUnixMicros; // @beta (undocumented) export class TimestampToUnixMillis extends FirestoreFunction { - constructor(input: Constant); + constructor(input: Accumulator); } // @beta -export function timestampToUnixMillis(expr: Constant): TimestampToUnixMillis; +export function timestampToUnixMillis(expr: Accumulator): TimestampToUnixMillis; // @beta export function timestampToUnixMillis(field: string): TimestampToUnixMillis; // @beta (undocumented) export class TimestampToUnixSeconds extends FirestoreFunction { - constructor(input: Constant); + constructor(input: Accumulator); } // @beta -export function timestampToUnixSeconds(expr: Constant): TimestampToUnixSeconds; +export function timestampToUnixSeconds(expr: Accumulator): TimestampToUnixSeconds; // @beta export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; // @beta (undocumented) export class ToLower extends FirestoreFunction { - constructor(expr: Constant); + constructor(expr: Accumulator); } // @beta export function toLower(expr: string): ToLower; // @beta -export function toLower(expr: Constant): ToLower; +export function toLower(expr: Accumulator): ToLower; // @beta (undocumented) export class ToUpper extends FirestoreFunction { - constructor(expr: Constant); + constructor(expr: Accumulator); } // @beta export function toUpper(expr: string): ToUpper; // @beta -export function toUpper(expr: Constant): ToUpper; +export function toUpper(expr: Accumulator): ToUpper; // @beta (undocumented) export class Trim extends FirestoreFunction { - constructor(expr: Constant); + constructor(expr: Accumulator); } // @beta export function trim(expr: string): Trim; // @beta -export function trim(expr: Constant): Trim; +export function trim(expr: Accumulator): Trim; // @beta (undocumented) export class UnixMicrosToTimestamp extends FirestoreFunction { - constructor(input: Constant); + constructor(input: Accumulator); } // @beta -export function unixMicrosToTimestamp(expr: Constant): UnixMicrosToTimestamp; +export function unixMicrosToTimestamp(expr: Accumulator): UnixMicrosToTimestamp; // @beta export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; // @beta (undocumented) export class UnixMillisToTimestamp extends FirestoreFunction { - constructor(input: Constant); + constructor(input: Accumulator); } // @beta -export function unixMillisToTimestamp(expr: Constant): UnixMillisToTimestamp; +export function unixMillisToTimestamp(expr: Accumulator): UnixMillisToTimestamp; // @beta export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; // @beta (undocumented) export class UnixSecondsToTimestamp extends FirestoreFunction { - constructor(input: Constant); + constructor(input: Accumulator); } // @beta -export function unixSecondsToTimestamp(expr: Constant): UnixSecondsToTimestamp; +export function unixSecondsToTimestamp(expr: Accumulator): UnixSecondsToTimestamp; // @beta export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; -// @public (undocumented) -export function useFluentPipelines(): void; - // @beta (undocumented) export class VectorLength extends FirestoreFunction { - constructor(value: Constant); + constructor(value: Accumulator); } // @beta -export function vectorLength(expr: Constant): VectorLength; +export function vectorLength(expr: Accumulator): VectorLength; // @beta export function vectorLength(field: string): VectorLength; // @beta (undocumented) export class Where implements Stage { - constructor(condition: FilterCondition & Constant); + constructor(condition: FilterCondition); // (undocumented) name: string; } // @beta (undocumented) export class Xor extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterExpr[]); + constructor(conditions: (FilterCondition)[]); // (undocumented) filterable: true; } // @beta -export function xor(left: FilterExpr, ...right: FilterExpr[]): Xor; +export function xor(left: FilterCondition, ...right: (FilterCondition)[]): Xor; // Warnings were encountered during analysis: // -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:8118:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:8119:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:8148:9 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:10252:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:10253:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:10282:9 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta ``` diff --git a/common/api-review/firestore-pipelines.api.md b/common/api-review/firestore-pipelines.api.md index b9023a41300..11bb7780e3a 100644 --- a/common/api-review/firestore-pipelines.api.md +++ b/common/api-review/firestore-pipelines.api.md @@ -7,125 +7,125 @@ import { FirebaseApp } from '@firebase/app'; // @beta -export interface Accumulator { +export interface Accumulator extends Expr { // (undocumented) accumulator: true; } // @beta -export type AccumulatorTarget = ExprWithAlias; +export type AccumulatorTarget = ExprWithAlias; // @beta (undocumented) export class Add extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); } // @beta -export function add(left: Constant, right: Constant): Add; +export function add(left: Expr, right: Expr): Add; // @beta -export function add(left: Constant, right: any): Add; +export function add(left: Expr, right: any): Add; // @beta -export function add(left: string, right: Constant): Add; +export function add(left: string, right: Expr): Add; // @beta export function add(left: string, right: any): Add; // @beta (undocumented) export class AddFields implements Stage { - constructor(fields: Map); + constructor(fields: Map); // (undocumented) name: string; } // @beta (undocumented) export class Aggregate implements Stage { - constructor(accumulators: Map, groups: Map); + constructor(accumulators: Map, groups: Map); // (undocumented) name: string; } // @beta (undocumented) export class And extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterExpr[]); + constructor(conditions: (FilterCondition)[]); // (undocumented) filterable: true; } // @beta -export function andFunction(left: FilterExpr, ...right: FilterExpr[]): And; +export function andFunction(left: FilterCondition, ...right: (FilterCondition)[]): And; // @beta (undocumented) export class ArrayConcat extends FirestoreFunction { - constructor(array: Constant, elements: Constant[]); + constructor(array: Expr, elements: Expr[]); } // @beta -export function arrayConcat(array: Constant, elements: Constant[]): ArrayConcat; +export function arrayConcat(array: Expr, elements: Expr[]): ArrayConcat; // @beta -export function arrayConcat(array: Constant, elements: any[]): ArrayConcat; +export function arrayConcat(array: Expr, elements: any[]): ArrayConcat; // @beta -export function arrayConcat(array: string, elements: Constant[]): ArrayConcat; +export function arrayConcat(array: string, elements: Expr[]): ArrayConcat; // @beta export function arrayConcat(array: string, elements: any[]): ArrayConcat; // @beta (undocumented) export class ArrayContains extends FirestoreFunction implements FilterCondition { - constructor(array: Constant, element: Constant); + constructor(array: Expr, element: Expr); // (undocumented) filterable: true; } // @beta -export function arrayContains(array: Constant, element: Constant): ArrayContains; +export function arrayContains(array: Expr, element: Expr): ArrayContains; // @beta -export function arrayContains(array: Constant, element: any): ArrayContains; +export function arrayContains(array: Expr, element: any): ArrayContains; // @beta -export function arrayContains(array: string, element: Constant): ArrayContains; +export function arrayContains(array: string, element: Expr): ArrayContains; // @beta export function arrayContains(array: string, element: any): ArrayContains; // @beta (undocumented) export class ArrayContainsAll extends FirestoreFunction implements FilterCondition { - constructor(array: Constant, values: Constant[]); + constructor(array: Expr, values: Expr[]); // (undocumented) filterable: true; } // @beta -export function arrayContainsAll(array: Constant, values: Constant[]): ArrayContainsAll; +export function arrayContainsAll(array: Expr, values: Expr[]): ArrayContainsAll; // @beta -export function arrayContainsAll(array: Constant, values: any[]): ArrayContainsAll; +export function arrayContainsAll(array: Expr, values: any[]): ArrayContainsAll; // @beta -export function arrayContainsAll(array: string, values: Constant[]): ArrayContainsAll; +export function arrayContainsAll(array: string, values: Expr[]): ArrayContainsAll; // @beta export function arrayContainsAll(array: string, values: any[]): ArrayContainsAll; // @beta (undocumented) export class ArrayContainsAny extends FirestoreFunction implements FilterCondition { - constructor(array: Constant, values: Constant[]); + constructor(array: Expr, values: Expr[]); // (undocumented) filterable: true; } // @beta -export function arrayContainsAny(array: Constant, values: Constant[]): ArrayContainsAny; +export function arrayContainsAny(array: Expr, values: Expr[]): ArrayContainsAny; // @beta -export function arrayContainsAny(array: Constant, values: any[]): ArrayContainsAny; +export function arrayContainsAny(array: Expr, values: any[]): ArrayContainsAny; // @beta -export function arrayContainsAny(array: string, values: Constant[]): ArrayContainsAny; +export function arrayContainsAny(array: string, values: Expr[]): ArrayContainsAny; // @beta export function arrayContainsAny(array: string, values: any[]): ArrayContainsAny; @@ -137,54 +137,54 @@ export class ArrayElement extends FirestoreFunction { // @beta (undocumented) export class ArrayLength extends FirestoreFunction { - constructor(array: Constant); + constructor(array: Expr); } // @beta -export function arrayLength(array: Constant): ArrayLength; +export function arrayLength(array: Expr): ArrayLength; // @beta (undocumented) export class ArrayReverse extends FirestoreFunction { - constructor(array: Constant); + constructor(array: Expr); } // @beta -export function ascending(expr: Constant): Ordering; +export function ascending(expr: Expr): Ordering; // @beta (undocumented) export class Avg extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); + constructor(value: Expr, distinct: boolean); // (undocumented) accumulator: true; } // @beta -export function avgFunction(value: Constant): Avg; +export function avgFunction(value: Expr): Avg; // @beta export function avgFunction(value: string): Avg; // @beta (undocumented) export class ByteLength extends FirestoreFunction { - constructor(value: Constant); + constructor(value: Expr); } // @beta -export function byteLength(expr: Constant): ByteLength; +export function byteLength(expr: Expr): ByteLength; // @beta export function byteLength(field: string): ByteLength; // @beta (undocumented) export class CharLength extends FirestoreFunction { - constructor(value: Constant); + constructor(value: Expr); } // @beta export function charLength(field: string): CharLength; // @beta -export function charLength(expr: Constant): CharLength; +export function charLength(expr: Expr): CharLength; // @beta (undocumented) export class CollectionGroupSource implements Stage { @@ -201,86 +201,19 @@ export class CollectionSource implements Stage { } // @beta (undocumented) -export class Cond extends FirestoreFunction implements FilterCondition { - constructor(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant); +export class Cond extends FirestoreFunction { + constructor(condition: FilterCondition, thenExpr: Expr, elseExpr: Expr); // (undocumented) filterable: true; } // @beta -export function cond(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant): Cond; +export function cond(condition: FilterCondition, thenExpr: Expr, elseExpr: Expr): Cond; // @beta -export class Constant { - add(other: Constant): Add; - add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; +export class Constant extends Expr { // (undocumented) exprType: ExprType; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): NotEqAny; - // (undocumented) - notEqAny(...others: any[]): NotEqAny; static of(value: number): Constant; static of(value: string): Constant; static of(value: boolean): Constant; @@ -298,43 +231,12 @@ export class Constant { static of(value: Map): Constant; // Warning: (ae-forgotten-export) The symbol "VectorValue" needs to be exported by the entry point pipelines.d.ts static of(value: VectorValue): Constant; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; static vector(value: number[] | VectorValue): Constant; - vectorLength(): VectorLength; } // @beta (undocumented) export class CosineDistance extends FirestoreFunction { - constructor(vector1: Constant, vector2: Constant); + constructor(vector1: Expr, vector2: Expr); } // @beta @@ -344,20 +246,20 @@ export function cosineDistance(expr: string, other: number[]): CosineDistance; export function cosineDistance(expr: string, other: VectorValue): CosineDistance; // @beta -export function cosineDistance(expr: string, other: Constant): CosineDistance; +export function cosineDistance(expr: string, other: Expr): CosineDistance; // @beta -export function cosineDistance(expr: Constant, other: number[]): CosineDistance; +export function cosineDistance(expr: Expr, other: number[]): CosineDistance; // @beta -export function cosineDistance(expr: Constant, other: VectorValue): CosineDistance; +export function cosineDistance(expr: Expr, other: VectorValue): CosineDistance; // @beta -export function cosineDistance(expr: Constant, other: Constant): CosineDistance; +export function cosineDistance(expr: Expr, other: Expr): CosineDistance; // @beta (undocumented) export class Count extends FirestoreFunction implements Accumulator { - constructor(value: Constant | undefined, distinct: boolean); + constructor(value: Expr | undefined, distinct: boolean); // (undocumented) accumulator: true; } @@ -366,7 +268,7 @@ export class Count extends FirestoreFunction implements Accumulator { export function countAll(): Count; // @beta -export function countFunction(value: Constant): Count; +export function countFunction(value: Expr): Count; // Warning: (ae-incompatible-release-tags) The symbol "countFunction" is marked as @public, but its signature references "Count" which is marked as @beta // @@ -380,28 +282,28 @@ export class DatabaseSource implements Stage { } // @beta -export function descending(expr: Constant): Ordering; +export function descending(expr: Expr): Ordering; // @beta (undocumented) export class Distinct implements Stage { - constructor(groups: Map); + constructor(groups: Map); // (undocumented) name: string; } // @beta (undocumented) export class Divide extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); } // @beta -export function divide(left: Constant, right: Constant): Divide; +export function divide(left: Expr, right: Expr): Divide; // @beta -export function divide(left: Constant, right: any): Divide; +export function divide(left: Expr, right: any): Divide; // @beta -export function divide(left: string, right: Constant): Divide; +export function divide(left: string, right: Expr): Divide; // @beta export function divide(left: string, right: any): Divide; @@ -417,7 +319,7 @@ export class DocumentsSource implements Stage { // @beta (undocumented) export class DotProduct extends FirestoreFunction { - constructor(vector1: Constant, vector2: Constant); + constructor(vector1: Expr, vector2: Expr); } // @beta @@ -427,20 +329,20 @@ export function dotProduct(expr: string, other: number[]): DotProduct; export function dotProduct(expr: string, other: VectorValue): DotProduct; // @beta -export function dotProduct(expr: string, other: Constant): DotProduct; +export function dotProduct(expr: string, other: Expr): DotProduct; // @beta -export function dotProduct(expr: Constant, other: number[]): DotProduct; +export function dotProduct(expr: Expr, other: number[]): DotProduct; // @beta -export function dotProduct(expr: Constant, other: VectorValue): DotProduct; +export function dotProduct(expr: Expr, other: VectorValue): DotProduct; // @beta -export function dotProduct(expr: Constant, other: Constant): DotProduct; +export function dotProduct(expr: Expr, other: Expr): DotProduct; // @beta (undocumented) export class EndsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, suffix: Constant); + constructor(expr: Expr, suffix: Expr); // (undocumented) filterable: true; } @@ -449,55 +351,55 @@ export class EndsWith extends FirestoreFunction implements FilterCondition { export function endsWith(expr: string, suffix: string): EndsWith; // @beta -export function endsWith(expr: string, suffix: Constant): EndsWith; +export function endsWith(expr: string, suffix: Expr): EndsWith; // @beta -export function endsWith(expr: Constant, suffix: string): EndsWith; +export function endsWith(expr: Expr, suffix: string): EndsWith; // @beta -export function endsWith(expr: Constant, suffix: Constant): EndsWith; +export function endsWith(expr: Expr, suffix: Expr): EndsWith; // @beta (undocumented) export class Eq extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); // (undocumented) filterable: true; } // @beta -export function eq(left: Constant, right: Constant): Eq; +export function eq(left: Expr, right: Expr): Eq; // @beta -export function eq(left: Constant, right: any): Eq; +export function eq(left: Expr, right: any): Eq; // @beta -export function eq(left: string, right: Constant): Eq; +export function eq(left: string, right: Expr): Eq; // @beta export function eq(left: string, right: any): Eq; // @beta (undocumented) export class EqAny extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, others: Constant[]); + constructor(left: Expr, others: Expr[]); // (undocumented) filterable: true; } // @beta -export function eqAny(element: Constant, others: Constant[]): EqAny; +export function eqAny(element: Expr, others: Expr[]): EqAny; // @beta -export function eqAny(element: Constant, others: any[]): EqAny; +export function eqAny(element: Expr, others: any[]): EqAny; // @beta -export function eqAny(element: string, others: Constant[]): EqAny; +export function eqAny(element: string, others: Expr[]): EqAny; // @beta export function eqAny(element: string, others: any[]): EqAny; // @beta (undocumented) export class EuclideanDistance extends FirestoreFunction { - constructor(vector1: Constant, vector2: Constant); + constructor(vector1: Expr, vector2: Expr); } // @beta @@ -507,52 +409,46 @@ export function euclideanDistance(expr: string, other: number[]): EuclideanDista export function euclideanDistance(expr: string, other: VectorValue): EuclideanDistance; // @beta -export function euclideanDistance(expr: string, other: Constant): EuclideanDistance; +export function euclideanDistance(expr: string, other: Expr): EuclideanDistance; // @beta -export function euclideanDistance(expr: Constant, other: number[]): EuclideanDistance; +export function euclideanDistance(expr: Expr, other: number[]): EuclideanDistance; // @beta -export function euclideanDistance(expr: Constant, other: VectorValue): EuclideanDistance; +export function euclideanDistance(expr: Expr, other: VectorValue): EuclideanDistance; // @beta -export function euclideanDistance(expr: Constant, other: Constant): EuclideanDistance; +export function euclideanDistance(expr: Expr, other: Expr): EuclideanDistance; // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta // // @public (undocumented) -export function execute(pipeline: Pipeline): Promise>>; +export function execute(pipeline: Pipeline): Promise; // @beta (undocumented) export class Exists extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant); + constructor(expr: Expr); // (undocumented) filterable: true; } // @beta -export function exists(value: Constant): Exists; +export function exists(value: Expr): Exists; // @beta export function exists(field: string): Exists; // @beta -export type ExprType = 'Field' | 'Constant' | 'Function' | 'ListOfExprs' | 'ExprWithAlias'; - -// @beta (undocumented) -export class ExprWithAlias implements Selectable { - constructor(expr: T, alias: string); - add(other: Constant): Add; +export abstract class Expr { + add(other: Expr): Add; add(other: any): Add; - // (undocumented) - alias: string; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; + arrayConcat(...arrays: Expr[]): ArrayConcat; + arrayConcat(...arrays: any[][]): ArrayConcat; + arrayContains(element: Expr): ArrayContains; arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: Expr[]): ArrayContainsAll; arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: Expr[]): ArrayContainsAny; arrayContainsAny(...values: any[]): ArrayContainsAny; arrayLength(): ArrayLength; as(name: string): ExprWithAlias; @@ -560,83 +456,74 @@ export class ExprWithAlias implements Selectable { avg(): Avg; byteLength(): ByteLength; charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: Expr): CosineDistance; cosineDistance(other: VectorValue): CosineDistance; cosineDistance(other: number[]): CosineDistance; count(): Count; descending(): Ordering; - divide(other: Constant): Divide; + divide(other: Expr): Divide; divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; + dotProduct(other: Expr): DotProduct; dotProduct(other: VectorValue): DotProduct; - // (undocumented) dotProduct(other: number[]): DotProduct; endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; + endsWith(suffix: Expr): EndsWith; + eq(other: Expr): Eq; eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) + eqAny(...others: Expr[]): EqAny; eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: Expr): EuclideanDistance; euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) euclideanDistance(other: number[]): EuclideanDistance; exists(): Exists; // (undocumented) - expr: T; - // (undocumented) - exprType: ExprType; - gt(other: Constant): Gt; + abstract exprType: ExprType; + gt(other: Expr): Gt; gt(other: any): Gt; - gte(other: Constant): Gte; + gte(other: Expr): Gte; gte(other: any): Gte; isNaN(): IsNan; like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; + like(pattern: Expr): Like; + logicalMaximum(other: Expr): LogicalMaximum; logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: Expr): LogicalMinimum; logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; + lt(other: Expr): Lt; lt(other: any): Lt; - lte(other: Constant): Lte; + lte(other: Expr): Lte; lte(other: any): Lte; mapGet(subfield: string): MapGet; maximum(): Maximum; minimum(): Minimum; - mod(other: Constant): Mod; + mod(other: Expr): Mod; mod(other: any): Mod; - multiply(other: Constant): Multiply; + multiply(other: Expr): Multiply; multiply(other: any): Multiply; - neq(other: Constant): Neq; + neq(other: Expr): Neq; neq(other: any): Neq; - notEqAny(...others: Constant[]): NotEqAny; - // (undocumented) + notEqAny(...others: Expr[]): NotEqAny; notEqAny(...others: any[]): NotEqAny; regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; + regexContains(pattern: Expr): RegexContains; regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; + regexMatch(pattern: Expr): RegexMatch; replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceAll(find: Expr, replace: Expr): ReplaceAll; replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + replaceFirst(find: Expr, replace: Expr): ReplaceFirst; reverse(): Reverse; - // (undocumented) - selectable: true; startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; + startsWith(prefix: Expr): StartsWith; + strConcat(...elements: Array): StrConcat; strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; + strContains(expr: Expr): StrContains; + subtract(other: Expr): Subtract; subtract(other: any): Subtract; sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: Expr, amount: Expr): TimestampAdd; timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: Expr, amount: Expr): TimestampSub; timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; timestampToUnixMicros(): TimestampToUnixMicros; timestampToUnixMillis(): TimestampToUnixMillis; @@ -651,78 +538,27 @@ export class ExprWithAlias implements Selectable { } // @beta -export class Field implements Selectable { - add(other: Constant): Add; - add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; +export type ExprType = 'Field' | 'Constant' | 'Function' | 'ListOfExprs' | 'ExprWithAlias'; + +// @beta (undocumented) +export class ExprWithAlias extends Expr implements Selectable { + constructor(expr: T, alias: string); // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; + readonly alias: string; // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; + readonly expr: T; // (undocumented) exprType: ExprType; // (undocumented) - fieldName(): string; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; + selectable: true; +} + +// @beta +export class Field extends Expr implements Selectable { // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): NotEqAny; + exprType: ExprType; // (undocumented) - notEqAny(...others: any[]): NotEqAny; + fieldName(): string; static of(name: string): Field; // Warning: (ae-forgotten-export) The symbol "FieldPath" needs to be exported by the entry point pipelines.d.ts // @@ -730,162 +566,30 @@ export class Field implements Selectable { static of(path: FieldPath): Field; // (undocumented) static of(pipeline: Pipeline, name: string): Field; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; // (undocumented) selectable: true; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; } // @beta (undocumented) -export class Fields implements Selectable { - add(other: Constant): Add; - add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; +export class Fields extends Expr implements Selectable { // (undocumented) exprType: ExprType; // (undocumented) fieldList(): Field[]; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): NotEqAny; - // (undocumented) - notEqAny(...others: any[]): NotEqAny; // (undocumented) static of(name: string, ...others: string[]): Fields; // (undocumented) static ofAll(): Fields; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; // (undocumented) selectable: true; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; } // @beta -export interface FilterCondition { +export interface FilterCondition extends Expr { // (undocumented) filterable: true; } -// @beta -export type FilterExpr = Constant & FilterCondition; - // @beta (undocumented) export class FindNearest implements Stage { // (undocumented) @@ -907,112 +611,14 @@ export interface FindNearestOptions { } // @beta -export class FirestoreFunction { - constructor(name: string, params: Constant[]); - add(other: Constant): Add; - add(other: any): Add; - arrayConcat(arrays: Constant[]): ArrayConcat; - arrayConcat(arrays: any[]): ArrayConcat; - arrayContains(element: Constant): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Constant[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Constant[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Constant): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Constant): Divide; - divide(other: any): Divide; - dotProduct(other: Constant): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Constant): EndsWith; - eq(other: Constant): Eq; - eq(other: any): Eq; - eqAny(...others: Constant[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Constant): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; +export class FirestoreFunction extends Expr { + constructor(name: string, params: Expr[]); // (undocumented) exprType: ExprType; - gt(other: Constant): Gt; - gt(other: any): Gt; - gte(other: Constant): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Constant): Like; - logicalMaximum(other: Constant): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Constant): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Constant): Lt; - lt(other: any): Lt; - lte(other: Constant): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Constant): Mod; - mod(other: any): Mod; - multiply(other: Constant): Multiply; - multiply(other: any): Multiply; - neq(other: Constant): Neq; - neq(other: any): Neq; - notEqAny(...others: Constant[]): NotEqAny; - // (undocumented) - notEqAny(...others: any[]): NotEqAny; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Constant): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Constant): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Constant, replace: Constant): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Constant, replace: Constant): ReplaceFirst; - reverse(): Reverse; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Constant): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Constant): StrContains; - subtract(other: Constant): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Constant, amount: Constant): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Constant, amount: Constant): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} + } // @beta -export function genericFunction(name: string, params: Constant[]): FirestoreFunction; +export function genericFunction(name: string, params: Expr[]): FirestoreFunction; // @beta (undocumented) export class GenericStage implements Stage { @@ -1023,58 +629,58 @@ export class GenericStage implements Stage { // @beta (undocumented) export class Gt extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); // (undocumented) filterable: true; } // @beta -export function gt(left: Constant, right: Constant): Gt; +export function gt(left: Expr, right: Expr): Gt; // @beta -export function gt(left: Constant, right: any): Gt; +export function gt(left: Expr, right: any): Gt; // @beta -export function gt(left: string, right: Constant): Gt; +export function gt(left: string, right: Expr): Gt; // @beta export function gt(left: string, right: any): Gt; // @beta (undocumented) export class Gte extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); // (undocumented) filterable: true; } // @beta -export function gte(left: Constant, right: Constant): Gte; +export function gte(left: Expr, right: Expr): Gte; // @beta -export function gte(left: Constant, right: any): Gte; +export function gte(left: Expr, right: any): Gte; // @beta -export function gte(left: string, right: Constant): Gte; +export function gte(left: string, right: Expr): Gte; // @beta export function gte(left: string, right: any): Gte; // @beta (undocumented) export class IsNan extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant); + constructor(expr: Expr); // (undocumented) filterable: true; } // @beta -export function isNan(value: Constant): IsNan; +export function isNan(value: Expr): IsNan; // @beta export function isNan(value: string): IsNan; // @beta (undocumented) export class Like extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, pattern: Constant); + constructor(expr: Expr, pattern: Expr); // (undocumented) filterable: true; } @@ -1083,13 +689,13 @@ export class Like extends FirestoreFunction implements FilterCondition { export function like(left: string, pattern: string): Like; // @beta -export function like(left: string, pattern: Constant): Like; +export function like(left: string, pattern: Expr): Like; // @beta -export function like(left: Constant, pattern: string): Like; +export function like(left: Expr, pattern: string): Like; // @beta -export function like(left: Constant, pattern: Constant): Like; +export function like(left: Expr, pattern: Expr): Like; // @beta (undocumented) export class Limit implements Stage { @@ -1100,194 +706,194 @@ export class Limit implements Stage { // @beta (undocumented) export class LogicalMaximum extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); } // @beta -export function logicalMaximum(left: Constant, right: Constant): LogicalMaximum; +export function logicalMaximum(left: Expr, right: Expr): LogicalMaximum; // @beta -export function logicalMaximum(left: Constant, right: any): LogicalMaximum; +export function logicalMaximum(left: Expr, right: any): LogicalMaximum; // @beta -export function logicalMaximum(left: string, right: Constant): LogicalMaximum; +export function logicalMaximum(left: string, right: Expr): LogicalMaximum; // @beta export function logicalMaximum(left: string, right: any): LogicalMaximum; // @beta (undocumented) export class LogicalMinimum extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); } // @beta -export function logicalMinimum(left: Constant, right: Constant): LogicalMinimum; +export function logicalMinimum(left: Expr, right: Expr): LogicalMinimum; // @beta -export function logicalMinimum(left: Constant, right: any): LogicalMinimum; +export function logicalMinimum(left: Expr, right: any): LogicalMinimum; // @beta -export function logicalMinimum(left: string, right: Constant): LogicalMinimum; +export function logicalMinimum(left: string, right: Expr): LogicalMinimum; // @beta export function logicalMinimum(left: string, right: any): LogicalMinimum; // @beta (undocumented) export class Lt extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); // (undocumented) filterable: true; } // @beta -export function lt(left: Constant, right: Constant): Lt; +export function lt(left: Expr, right: Expr): Lt; // @beta -export function lt(left: Constant, right: any): Lt; +export function lt(left: Expr, right: any): Lt; // @beta -export function lt(left: string, right: Constant): Lt; +export function lt(left: string, right: Expr): Lt; // @beta export function lt(left: string, right: any): Lt; // @beta (undocumented) export class Lte extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); // (undocumented) filterable: true; } // @beta -export function lte(left: Constant, right: Constant): Lte; +export function lte(left: Expr, right: Expr): Lte; // @beta -export function lte(left: Constant, right: any): Lte; +export function lte(left: Expr, right: any): Lte; -// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Constant" which is marked as @beta +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Expr" which is marked as @beta // Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Lte" which is marked as @beta // // @public -export function lte(left: string, right: Constant): Lte; +export function lte(left: string, right: Expr): Lte; // @beta export function lte(left: string, right: any): Lte; // @beta (undocumented) export class MapGet extends FirestoreFunction { - constructor(map: Constant, name: string); + constructor(map: Expr, name: string); } // @beta export function mapGet(mapField: string, subField: string): MapGet; // @beta -export function mapGet(mapExpr: Constant, subField: string): MapGet; +export function mapGet(mapExpr: Expr, subField: string): MapGet; // @beta (undocumented) export class Maximum extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); + constructor(value: Expr, distinct: boolean); // (undocumented) accumulator: true; } // @beta -export function maximum(value: Constant): Maximum; +export function maximum(value: Expr): Maximum; // @beta export function maximum(value: string): Maximum; // @beta (undocumented) export class Minimum extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); + constructor(value: Expr, distinct: boolean); // (undocumented) accumulator: true; } // @beta -export function minimum(value: Constant): Minimum; +export function minimum(value: Expr): Minimum; // @beta export function minimum(value: string): Minimum; // @beta (undocumented) export class Mod extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); } // @beta -export function mod(left: Constant, right: Constant): Mod; +export function mod(left: Expr, right: Expr): Mod; // @beta -export function mod(left: Constant, right: any): Mod; +export function mod(left: Expr, right: any): Mod; // @beta -export function mod(left: string, right: Constant): Mod; +export function mod(left: string, right: Expr): Mod; // @beta export function mod(left: string, right: any): Mod; // @beta (undocumented) export class Multiply extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); } // @beta -export function multiply(left: Constant, right: Constant): Multiply; +export function multiply(left: Expr, right: Expr): Multiply; // @beta -export function multiply(left: Constant, right: any): Multiply; +export function multiply(left: Expr, right: any): Multiply; // @beta -export function multiply(left: string, right: Constant): Multiply; +export function multiply(left: string, right: Expr): Multiply; // @beta export function multiply(left: string, right: any): Multiply; // @beta (undocumented) export class Neq extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); // (undocumented) filterable: true; } // @beta -export function neq(left: Constant, right: Constant): Neq; +export function neq(left: Expr, right: Expr): Neq; // @beta -export function neq(left: Constant, right: any): Neq; +export function neq(left: Expr, right: any): Neq; // @beta -export function neq(left: string, right: Constant): Neq; +export function neq(left: string, right: Expr): Neq; // @beta export function neq(left: string, right: any): Neq; // @beta (undocumented) export class Not extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant); + constructor(expr: Expr); // (undocumented) filterable: true; } // @beta -export function not(filter: FilterExpr): Not; +export function not(filter: FilterCondition): Not; // @beta (undocumented) export class NotEqAny extends FirestoreFunction implements FilterCondition { - constructor(left: Constant, others: Constant[]); + constructor(left: Expr, others: Expr[]); // (undocumented) filterable: true; } // @beta -export function notEqAny(element: Constant, others: Constant[]): NotEqAny; +export function notEqAny(element: Expr, others: Expr[]): NotEqAny; // @beta -export function notEqAny(element: Constant, others: any[]): NotEqAny; +export function notEqAny(element: Expr, others: any[]): NotEqAny; // @beta -export function notEqAny(element: string, others: Constant[]): NotEqAny; +export function notEqAny(element: string, others: Expr[]): NotEqAny; // @beta export function notEqAny(element: string, others: any[]): NotEqAny; @@ -1301,72 +907,72 @@ export class Offset implements Stage { // @beta (undocumented) export class Or extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterExpr[]); + constructor(conditions: (FilterCondition)[]); // (undocumented) filterable: true; } // @beta export class Ordering { - constructor(expr: Constant, direction: 'ascending' | 'descending'); - } + constructor(expr: Expr, direction: 'ascending' | 'descending'); + // (undocumented) + readonly direction: 'ascending' | 'descending'; + // (undocumented) + readonly expr: Expr; +} // @beta -export function orFunction(left: FilterExpr, ...right: FilterExpr[]): Or; +export function orFunction(left: FilterCondition, ...right: (FilterCondition)[]): Or; -// Warning: (ae-forgotten-export) The symbol "DocumentData" needs to be exported by the entry point pipelines.d.ts -// // @public (undocumented) -export class Pipeline { - /* Excluded from this release type: __constructor */ +export class Pipeline { /* Excluded from this release type: newPipeline */ // Warning: (ae-incompatible-release-tags) The symbol "addFields" is marked as @public, but its signature references "Selectable" which is marked as @beta - addFields(...fields: Selectable[]): Pipeline; + addFields(...fields: Selectable[]): Pipeline; // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta - aggregate(...accumulators: AccumulatorTarget[]): Pipeline; - aggregate(options: { accumulators: AccumulatorTarget[]; groups?: Array; }): Pipeline; - // (undocumented) - converter: any; + aggregate(...accumulators: AccumulatorTarget[]): Pipeline; + aggregate(options: { accumulators: AccumulatorTarget[]; groups?: Array; }): Pipeline; // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta - distinct(...groups: Array): Pipeline; + distinct(...groups: Array): Pipeline; // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta - execute(): Promise>>; + execute(): Promise; // Warning: (ae-incompatible-release-tags) The symbol "findNearest" is marked as @public, but its signature references "FindNearestOptions" which is marked as @beta // // (undocumented) - findNearest(options: FindNearestOptions): Pipeline; - genericStage(name: string, params: any[]): Pipeline; - limit(limit: number): Pipeline; - offset(offset: number): Pipeline; + findNearest(options: FindNearestOptions): Pipeline; + genericStage(name: string, params: any[]): Pipeline; + limit(limit: number): Pipeline; + offset(offset: number): Pipeline; readUserData: any; // Warning: (ae-incompatible-release-tags) The symbol "select" is marked as @public, but its signature references "Selectable" which is marked as @beta - select(...selections: Array): Pipeline; + select(...selections: Array): Pipeline; // (undocumented) selectablesToMap: any; // Warning: (ae-incompatible-release-tags) The symbol "sort" is marked as @public, but its signature references "Ordering" which is marked as @beta - sort(...orderings: Ordering[]): Pipeline; + sort(...orderings: Ordering[]): Pipeline; // (undocumented) - sort(options: { orderings: Ordering[]; }): Pipeline; + sort(options: { orderings: Ordering[]; }): Pipeline; // (undocumented) stages: any; // (undocumented) userDataReader: any; // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "FilterCondition" which is marked as @beta - // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "Constant" which is marked as @beta - where(condition: FilterCondition & Constant): Pipeline; + where(condition: FilterCondition): Pipeline; } // Warning: (ae-forgotten-export) The symbol "Firestore" needs to be exported by the entry point pipelines.d.ts // Warning: (ae-incompatible-release-tags) The symbol "pipeline" is marked as @public, but its signature references "PipelineSource" which is marked as @beta // // @public -export function pipeline(firestore: Firestore): PipelineSource; +export function pipeline(firestore: Firestore): PipelineSource; // Warning: (ae-forgotten-export) The symbol "Query" needs to be exported by the entry point pipelines.d.ts // // @public export function pipeline(query: Query): Pipeline; +// Warning: (ae-forgotten-export) The symbol "DocumentData" needs to be exported by the entry point pipelines.d.ts +// // @beta export class PipelineResult { /* Excluded from this release type: _ref */ @@ -1382,25 +988,22 @@ export class PipelineResult { } // @beta -export class PipelineSource { - /* Excluded from this release type: _db */ - /* Excluded from this release type: _userDataReader */ - /* Excluded from this release type: _userDataWriter */ - /* Excluded from this release type: _documentReferenceFactory */ +export class PipelineSource { + /* Excluded from this release type: _createPipeline */ /* Excluded from this release type: __constructor */ // (undocumented) - collection(collectionPath: string): Pipeline; + collection(collectionPath: string): PipelineType; // (undocumented) - collectionGroup(collectionId: string): Pipeline; + collectionGroup(collectionId: string): PipelineType; // (undocumented) - database(): Pipeline; + database(): PipelineType; // (undocumented) - documents(docs: DocumentReference[]): Pipeline; + documents(docs: DocumentReference[]): PipelineType; } // @beta (undocumented) export class RegexContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, pattern: Constant); + constructor(expr: Expr, pattern: Expr); // (undocumented) filterable: true; } @@ -1409,17 +1012,17 @@ export class RegexContains extends FirestoreFunction implements FilterCondition export function regexContains(left: string, pattern: string): RegexContains; // @beta -export function regexContains(left: string, pattern: Constant): RegexContains; +export function regexContains(left: string, pattern: Expr): RegexContains; // @beta -export function regexContains(left: Constant, pattern: string): RegexContains; +export function regexContains(left: Expr, pattern: string): RegexContains; // @beta -export function regexContains(left: Constant, pattern: Constant): RegexContains; +export function regexContains(left: Expr, pattern: Expr): RegexContains; // @beta (undocumented) export class RegexMatch extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, pattern: Constant); + constructor(expr: Expr, pattern: Expr); // (undocumented) filterable: true; } @@ -1428,69 +1031,66 @@ export class RegexMatch extends FirestoreFunction implements FilterCondition { export function regexMatch(left: string, pattern: string): RegexMatch; // @beta -export function regexMatch(left: string, pattern: Constant): RegexMatch; +export function regexMatch(left: string, pattern: Expr): RegexMatch; // @beta -export function regexMatch(left: Constant, pattern: string): RegexMatch; +export function regexMatch(left: Expr, pattern: string): RegexMatch; // @beta -export function regexMatch(left: Constant, pattern: Constant): RegexMatch; +export function regexMatch(left: Expr, pattern: Expr): RegexMatch; // @beta (undocumented) export class ReplaceAll extends FirestoreFunction { - constructor(value: Constant, find: Constant, replace: Constant); + constructor(value: Expr, find: Expr, replace: Expr); } // @beta -export function replaceAll(value: Constant, find: string, replace: string): ReplaceAll; +export function replaceAll(value: Expr, find: string, replace: string): ReplaceAll; // @beta -export function replaceAll(value: Constant, find: Constant, replace: Constant): ReplaceAll; +export function replaceAll(value: Expr, find: Expr, replace: Expr): ReplaceAll; // @beta export function replaceAll(field: string, find: string, replace: string): ReplaceAll; // @beta (undocumented) export class ReplaceFirst extends FirestoreFunction { - constructor(value: Constant, find: Constant, replace: Constant); + constructor(value: Expr, find: Expr, replace: Expr); } // @beta -export function replaceFirst(value: Constant, find: string, replace: string): ReplaceFirst; +export function replaceFirst(value: Expr, find: string, replace: string): ReplaceFirst; // @beta -export function replaceFirst(value: Constant, find: Constant, replace: Constant): ReplaceFirst; +export function replaceFirst(value: Expr, find: Expr, replace: Expr): ReplaceFirst; // @beta export function replaceFirst(field: string, find: string, replace: string): ReplaceFirst; // @beta (undocumented) export class Reverse extends FirestoreFunction { - constructor(value: Constant); + constructor(value: Expr); } // @beta -export function reverse(expr: Constant): Reverse; +export function reverse(expr: Expr): Reverse; // @beta export function reverse(field: string): Reverse; // @beta (undocumented) export class Select implements Stage { - constructor(projections: Map); + constructor(projections: Map); // (undocumented) name: string; } // @beta -export interface Selectable { +export interface Selectable extends Expr { // (undocumented) selectable: true; } -// @beta -export type SelectableExpr = Constant & Selectable; - // @beta (undocumented) export class Sort implements Stage { constructor(orders: Ordering[]); @@ -1506,7 +1106,7 @@ export interface Stage { // @beta (undocumented) export class StartsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, prefix: Constant); + constructor(expr: Expr, prefix: Expr); // (undocumented) filterable: true; } @@ -1515,28 +1115,28 @@ export class StartsWith extends FirestoreFunction implements FilterCondition { export function startsWith(expr: string, prefix: string): StartsWith; // @beta -export function startsWith(expr: string, prefix: Constant): StartsWith; +export function startsWith(expr: string, prefix: Expr): StartsWith; // @beta -export function startsWith(expr: Constant, prefix: string): StartsWith; +export function startsWith(expr: Expr, prefix: string): StartsWith; // @beta -export function startsWith(expr: Constant, prefix: Constant): StartsWith; +export function startsWith(expr: Expr, prefix: Expr): StartsWith; // @beta (undocumented) export class StrConcat extends FirestoreFunction { - constructor(first: Constant, rest: Constant[]); + constructor(first: Expr, rest: Expr[]); } // @beta -export function strConcat(first: string, ...elements: Array): StrConcat; +export function strConcat(first: string, ...elements: Array): StrConcat; // @beta -export function strConcat(first: Constant, ...elements: Array): StrConcat; +export function strConcat(first: Expr, ...elements: Array): StrConcat; // @beta (undocumented) export class StrContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Constant, substring: Constant); + constructor(expr: Expr, substring: Expr); // (undocumented) filterable: true; } @@ -1545,207 +1145,204 @@ export class StrContains extends FirestoreFunction implements FilterCondition { export function strContains(left: string, substring: string): StrContains; // @beta -export function strContains(left: string, substring: Constant): StrContains; +export function strContains(left: string, substring: Expr): StrContains; // @beta -export function strContains(left: Constant, substring: string): StrContains; +export function strContains(left: Expr, substring: string): StrContains; // @beta -export function strContains(left: Constant, substring: Constant): StrContains; +export function strContains(left: Expr, substring: Expr): StrContains; // @beta (undocumented) export class Subtract extends FirestoreFunction { - constructor(left: Constant, right: Constant); + constructor(left: Expr, right: Expr); } // @beta -export function subtract(left: Constant, right: Constant): Subtract; +export function subtract(left: Expr, right: Expr): Subtract; // @beta -export function subtract(left: Constant, right: any): Subtract; +export function subtract(left: Expr, right: any): Subtract; // @beta -export function subtract(left: string, right: Constant): Subtract; +export function subtract(left: string, right: Expr): Subtract; // @beta export function subtract(left: string, right: any): Subtract; // @beta (undocumented) export class Sum extends FirestoreFunction implements Accumulator { - constructor(value: Constant, distinct: boolean); + constructor(value: Expr, distinct: boolean); // (undocumented) accumulator: true; } // @beta -export function sumFunction(value: Constant): Sum; +export function sumFunction(value: Expr): Sum; // @beta export function sumFunction(value: string): Sum; // @beta (undocumented) export class TimestampAdd extends FirestoreFunction { - constructor(timestamp: Constant, unit: Constant, amount: Constant); + constructor(timestamp: Expr, unit: Expr, amount: Expr); } // @beta -export function timestampAdd(timestamp: Constant, unit: Constant, amount: Constant): TimestampAdd; +export function timestampAdd(timestamp: Expr, unit: Expr, amount: Expr): TimestampAdd; // @beta -export function timestampAdd(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; +export function timestampAdd(timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; // @beta export function timestampAdd(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; // @beta (undocumented) export class TimestampSub extends FirestoreFunction { - constructor(timestamp: Constant, unit: Constant, amount: Constant); + constructor(timestamp: Expr, unit: Expr, amount: Expr); } // @beta -export function timestampSub(timestamp: Constant, unit: Constant, amount: Constant): TimestampSub; +export function timestampSub(timestamp: Expr, unit: Expr, amount: Expr): TimestampSub; // @beta -export function timestampSub(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; +export function timestampSub(timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; // @beta export function timestampSub(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; // @beta (undocumented) export class TimestampToUnixMicros extends FirestoreFunction { - constructor(input: Constant); + constructor(input: Expr); } // @beta -export function timestampToUnixMicros(expr: Constant): TimestampToUnixMicros; +export function timestampToUnixMicros(expr: Expr): TimestampToUnixMicros; // @beta export function timestampToUnixMicros(field: string): TimestampToUnixMicros; // @beta (undocumented) export class TimestampToUnixMillis extends FirestoreFunction { - constructor(input: Constant); + constructor(input: Expr); } // @beta -export function timestampToUnixMillis(expr: Constant): TimestampToUnixMillis; +export function timestampToUnixMillis(expr: Expr): TimestampToUnixMillis; // @beta export function timestampToUnixMillis(field: string): TimestampToUnixMillis; // @beta (undocumented) export class TimestampToUnixSeconds extends FirestoreFunction { - constructor(input: Constant); + constructor(input: Expr); } // @beta -export function timestampToUnixSeconds(expr: Constant): TimestampToUnixSeconds; +export function timestampToUnixSeconds(expr: Expr): TimestampToUnixSeconds; // @beta export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; // @beta (undocumented) export class ToLower extends FirestoreFunction { - constructor(expr: Constant); + constructor(expr: Expr); } // @beta export function toLower(expr: string): ToLower; // @beta -export function toLower(expr: Constant): ToLower; +export function toLower(expr: Expr): ToLower; // @beta (undocumented) export class ToUpper extends FirestoreFunction { - constructor(expr: Constant); + constructor(expr: Expr); } // @beta export function toUpper(expr: string): ToUpper; // @beta -export function toUpper(expr: Constant): ToUpper; +export function toUpper(expr: Expr): ToUpper; // @beta (undocumented) export class Trim extends FirestoreFunction { - constructor(expr: Constant); + constructor(expr: Expr); } // @beta export function trim(expr: string): Trim; // @beta -export function trim(expr: Constant): Trim; +export function trim(expr: Expr): Trim; // @beta (undocumented) export class UnixMicrosToTimestamp extends FirestoreFunction { - constructor(input: Constant); + constructor(input: Expr); } // @beta -export function unixMicrosToTimestamp(expr: Constant): UnixMicrosToTimestamp; +export function unixMicrosToTimestamp(expr: Expr): UnixMicrosToTimestamp; // @beta export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; // @beta (undocumented) export class UnixMillisToTimestamp extends FirestoreFunction { - constructor(input: Constant); + constructor(input: Expr); } // @beta -export function unixMillisToTimestamp(expr: Constant): UnixMillisToTimestamp; +export function unixMillisToTimestamp(expr: Expr): UnixMillisToTimestamp; // @beta export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; // @beta (undocumented) export class UnixSecondsToTimestamp extends FirestoreFunction { - constructor(input: Constant); + constructor(input: Expr); } // @beta -export function unixSecondsToTimestamp(expr: Constant): UnixSecondsToTimestamp; +export function unixSecondsToTimestamp(expr: Expr): UnixSecondsToTimestamp; // @beta export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; -// @public (undocumented) -export function useFluentPipelines(): void; - // @beta (undocumented) export class VectorLength extends FirestoreFunction { - constructor(value: Constant); + constructor(value: Expr); } // @beta -export function vectorLength(expr: Constant): VectorLength; +export function vectorLength(expr: Expr): VectorLength; // @beta export function vectorLength(field: string): VectorLength; // @beta (undocumented) export class Where implements Stage { - constructor(condition: FilterCondition & Constant); + constructor(condition: FilterCondition); // (undocumented) name: string; } // @beta (undocumented) export class Xor extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterExpr[]); + constructor(conditions: (FilterCondition)[]); // (undocumented) filterable: true; } // @beta -export function xor(left: FilterExpr, ...right: FilterExpr[]): Xor; +export function xor(left: FilterCondition, ...right: (FilterCondition)[]): Xor; // Warnings were encountered during analysis: // -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:8193:26 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:8193:61 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:8220:21 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:3982:26 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:3982:61 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:4009:21 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta ``` diff --git a/common/api-review/firestore.api.md b/common/api-review/firestore.api.md index 34b56b97f21..6f0e14206c2 100644 --- a/common/api-review/firestore.api.md +++ b/common/api-review/firestore.api.md @@ -9,14 +9,54 @@ import { FirebaseApp } from '@firebase/app'; import { FirebaseError } from '@firebase/util'; import { LogLevelString as LogLevel } from '@firebase/logger'; +// @beta +export interface Accumulator extends Expr { + // (undocumented) + accumulator: true; +} + +// @beta +export type AccumulatorTarget = ExprWithAlias; + +// @beta (undocumented) +export class Add extends FirestoreFunction { + constructor(left: Expr, right: Expr); + } + +// @beta +export function add(left: Expr, right: Expr): Add; + +// @beta +export function add(left: Expr, right: any): Add; + +// @beta +export function add(left: string, right: Expr): Add; + +// @beta +export function add(left: string, right: any): Add; + // @public export function addDoc(reference: CollectionReference, data: WithFieldValue): Promise>; +// @beta (undocumented) +export class AddFields implements Stage { + constructor(fields: Map); + // (undocumented) + name: string; +} + // @public export type AddPrefixToKeys> = { [K in keyof T & string as `${Prefix}.${K}`]+?: string extends K ? any : T[K]; }; +// @beta (undocumented) +export class Aggregate implements Stage { + constructor(accumulators: Map, groups: Map); + // (undocumented) + name: string; +} + // @public export class AggregateField { readonly aggregateType: AggregateType; @@ -53,18 +93,147 @@ export type AggregateSpecData = { // @public export type AggregateType = 'count' | 'avg' | 'sum'; +// @beta (undocumented) +export class And extends FirestoreFunction implements FilterCondition { + constructor(conditions: (FilterCondition)[]); + // (undocumented) + filterable: true; +} + // @public export function and(...queryConstraints: QueryFilterConstraint[]): QueryCompositeFilterConstraint; +// @beta +export function andFunction(left: FilterCondition, ...right: (FilterCondition)[]): And; + +// @beta (undocumented) +export class ArrayConcat extends FirestoreFunction { + constructor(array: Expr, elements: Expr[]); + } + +// @beta +export function arrayConcat(array: Expr, elements: Expr[]): ArrayConcat; + +// @beta +export function arrayConcat(array: Expr, elements: any[]): ArrayConcat; + +// @beta +export function arrayConcat(array: string, elements: Expr[]): ArrayConcat; + +// @beta +export function arrayConcat(array: string, elements: any[]): ArrayConcat; + +// @beta (undocumented) +export class ArrayContains extends FirestoreFunction implements FilterCondition { + constructor(array: Expr, element: Expr); + // (undocumented) + filterable: true; +} + +// @beta +export function arrayContains(array: Expr, element: Expr): ArrayContains; + +// @beta +export function arrayContains(array: Expr, element: any): ArrayContains; + +// @beta +export function arrayContains(array: string, element: Expr): ArrayContains; + +// @beta +export function arrayContains(array: string, element: any): ArrayContains; + +// @beta (undocumented) +export class ArrayContainsAll extends FirestoreFunction implements FilterCondition { + constructor(array: Expr, values: Expr[]); + // (undocumented) + filterable: true; + } + +// @beta +export function arrayContainsAll(array: Expr, values: Expr[]): ArrayContainsAll; + +// @beta +export function arrayContainsAll(array: Expr, values: any[]): ArrayContainsAll; + +// @beta +export function arrayContainsAll(array: string, values: Expr[]): ArrayContainsAll; + +// @beta +export function arrayContainsAll(array: string, values: any[]): ArrayContainsAll; + +// @beta (undocumented) +export class ArrayContainsAny extends FirestoreFunction implements FilterCondition { + constructor(array: Expr, values: Expr[]); + // (undocumented) + filterable: true; + } + +// @beta +export function arrayContainsAny(array: Expr, values: Expr[]): ArrayContainsAny; + +// @beta +export function arrayContainsAny(array: Expr, values: any[]): ArrayContainsAny; + +// @beta +export function arrayContainsAny(array: string, values: Expr[]): ArrayContainsAny; + +// @beta +export function arrayContainsAny(array: string, values: any[]): ArrayContainsAny; + +// @beta (undocumented) +export class ArrayElement extends FirestoreFunction { + constructor(); +} + +// @beta (undocumented) +export class ArrayLength extends FirestoreFunction { + constructor(array: Expr); + } + +// @beta +export function arrayLength(array: Expr): ArrayLength; + // @public export function arrayRemove(...elements: unknown[]): FieldValue; +// @beta (undocumented) +export class ArrayReverse extends FirestoreFunction { + constructor(array: Expr); + } + // @public export function arrayUnion(...elements: unknown[]): FieldValue; +// @beta +export function ascending(expr: Expr): Ordering; + // @public export function average(field: string | FieldPath): AggregateField; +// @beta (undocumented) +export class Avg extends FirestoreFunction implements Accumulator { + constructor(value: Expr, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function avgFunction(value: Expr): Avg; + +// @beta +export function avgFunction(value: string): Avg; + +// @beta (undocumented) +export class ByteLength extends FirestoreFunction { + constructor(value: Expr); + } + +// @beta +export function byteLength(expr: Expr): ByteLength; + +// @beta +export function byteLength(field: string): ByteLength; + // @public export class Bytes { static fromBase64String(base64: string): Bytes; @@ -78,6 +247,17 @@ export class Bytes { // @public export const CACHE_SIZE_UNLIMITED = -1; +// @beta (undocumented) +export class CharLength extends FirestoreFunction { + constructor(value: Expr); + } + +// @beta +export function charLength(field: string): CharLength; + +// @beta +export function charLength(expr: Expr): CharLength; + // @public export type ChildUpdateFields = V extends Record ? AddPrefixToKeys> : never; @@ -96,6 +276,13 @@ export function collection(refer // @public export function collectionGroup(firestore: Firestore, collectionId: string): Query; +// @beta (undocumented) +export class CollectionGroupSource implements Stage { + constructor(collectionId: string); + // (undocumented) + name: string; +} + // @public export class CollectionReference extends Query { get id(): string; @@ -106,14 +293,98 @@ export class CollectionReference; } +// @beta (undocumented) +export class CollectionSource implements Stage { + constructor(collectionPath: string); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class Cond extends FirestoreFunction { + constructor(condition: FilterCondition, thenExpr: Expr, elseExpr: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function cond(condition: FilterCondition, thenExpr: Expr, elseExpr: Expr): Cond; + // @public export function connectFirestoreEmulator(firestore: Firestore, host: string, port: number, options?: { mockUserToken?: EmulatorMockTokenOptions | string; }): void; +// @beta +export class Constant extends Expr { + // (undocumented) + exprType: ExprType; + static of(value: number): Constant; + static of(value: string): Constant; + static of(value: boolean): Constant; + static of(value: null): Constant; + static of(value: undefined): Constant; + static of(value: GeoPoint): Constant; + static of(value: Timestamp): Constant; + static of(value: Date): Constant; + static of(value: Uint8Array): Constant; + static of(value: DocumentReference): Constant; + static of(value: any[]): Constant; + static of(value: Map): Constant; + static of(value: VectorValue): Constant; + static vector(value: number[] | VectorValue): Constant; +} + +// @beta (undocumented) +export class CosineDistance extends FirestoreFunction { + constructor(vector1: Expr, vector2: Expr); + } + +// @beta +export function cosineDistance(expr: string, other: number[]): CosineDistance; + +// @beta +export function cosineDistance(expr: string, other: VectorValue): CosineDistance; + +// @beta +export function cosineDistance(expr: string, other: Expr): CosineDistance; + +// @beta +export function cosineDistance(expr: Expr, other: number[]): CosineDistance; + +// @beta +export function cosineDistance(expr: Expr, other: VectorValue): CosineDistance; + +// @beta +export function cosineDistance(expr: Expr, other: Expr): CosineDistance; + +// @beta (undocumented) +export class Count extends FirestoreFunction implements Accumulator { + constructor(value: Expr | undefined, distinct: boolean); + // (undocumented) + accumulator: true; + } + // @public export function count(): AggregateField; +// @beta +export function countAll(): Count; + +// @beta +export function countFunction(value: Expr): Count; + +// Warning: (ae-incompatible-release-tags) The symbol "countFunction" is marked as @public, but its signature references "Count" which is marked as @beta +// +// @public +export function countFunction(value: string): Count; + +// @beta (undocumented) +export class DatabaseSource implements Stage { + // (undocumented) + name: string; +} + // @public export function deleteAllPersistentCacheIndexes(indexManager: PersistentCacheIndexManager): void; @@ -123,12 +394,39 @@ export function deleteDoc(refere // @public export function deleteField(): FieldValue; +// @beta +export function descending(expr: Expr): Ordering; + // @public export function disableNetwork(firestore: Firestore): Promise; // @public export function disablePersistentCacheIndexAutoCreation(indexManager: PersistentCacheIndexManager): void; +// @beta (undocumented) +export class Distinct implements Stage { + constructor(groups: Map); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class Divide extends FirestoreFunction { + constructor(left: Expr, right: Expr); + } + +// @beta +export function divide(left: Expr, right: Expr): Divide; + +// @beta +export function divide(left: Expr, right: any): Divide; + +// @beta +export function divide(left: string, right: Expr): Divide; + +// @beta +export function divide(left: string, right: any): Divide; + // @public export function doc(firestore: Firestore, path: string, ...pathSegments: string[]): DocumentReference; @@ -180,6 +478,38 @@ export class DocumentSnapshot; } +// @beta (undocumented) +export class DocumentsSource implements Stage { + constructor(docPaths: string[]); + // (undocumented) + name: string; + // (undocumented) + static of(refs: DocumentReference[]): DocumentsSource; +} + +// @beta (undocumented) +export class DotProduct extends FirestoreFunction { + constructor(vector1: Expr, vector2: Expr); + } + +// @beta +export function dotProduct(expr: string, other: number[]): DotProduct; + +// @beta +export function dotProduct(expr: string, other: VectorValue): DotProduct; + +// @beta +export function dotProduct(expr: string, other: Expr): DotProduct; + +// @beta +export function dotProduct(expr: Expr, other: number[]): DotProduct; + +// @beta +export function dotProduct(expr: Expr, other: VectorValue): DotProduct; + +// @beta +export function dotProduct(expr: Expr, other: Expr): DotProduct; + export { EmulatorMockTokenOptions } // @public @deprecated @@ -206,22 +536,290 @@ export function endBefore(snapsh // @public export function endBefore(...fieldValues: unknown[]): QueryEndAtConstraint; +// @beta (undocumented) +export class EndsWith extends FirestoreFunction implements FilterCondition { + constructor(expr: Expr, suffix: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function endsWith(expr: string, suffix: string): EndsWith; + +// @beta +export function endsWith(expr: string, suffix: Expr): EndsWith; + +// @beta +export function endsWith(expr: Expr, suffix: string): EndsWith; + +// @beta +export function endsWith(expr: Expr, suffix: Expr): EndsWith; + +// @beta (undocumented) +export class Eq extends FirestoreFunction implements FilterCondition { + constructor(left: Expr, right: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function eq(left: Expr, right: Expr): Eq; + +// @beta +export function eq(left: Expr, right: any): Eq; + +// @beta +export function eq(left: string, right: Expr): Eq; + +// @beta +export function eq(left: string, right: any): Eq; + +// @beta (undocumented) +export class EqAny extends FirestoreFunction implements FilterCondition { + constructor(left: Expr, others: Expr[]); + // (undocumented) + filterable: true; + } + +// @beta +export function eqAny(element: Expr, others: Expr[]): EqAny; + +// @beta +export function eqAny(element: Expr, others: any[]): EqAny; + +// @beta +export function eqAny(element: string, others: Expr[]): EqAny; + +// @beta +export function eqAny(element: string, others: any[]): EqAny; + +// @beta (undocumented) +export class EuclideanDistance extends FirestoreFunction { + constructor(vector1: Expr, vector2: Expr); + } + +// @beta +export function euclideanDistance(expr: string, other: number[]): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: string, other: VectorValue): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: string, other: Expr): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: Expr, other: number[]): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: Expr, other: VectorValue): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: Expr, other: Expr): EuclideanDistance; + +// Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta +// +// @public (undocumented) +export function execute(pipeline: Pipeline): Promise; + +// @beta (undocumented) +export class Exists extends FirestoreFunction implements FilterCondition { + constructor(expr: Expr); + // (undocumented) + filterable: true; +} + +// @beta +export function exists(value: Expr): Exists; + +// @beta +export function exists(field: string): Exists; + // @public export interface ExperimentalLongPollingOptions { timeoutSeconds?: number; } +// @beta +export abstract class Expr { + add(other: Expr): Add; + add(other: any): Add; + arrayConcat(...arrays: Expr[]): ArrayConcat; + arrayConcat(...arrays: any[][]): ArrayConcat; + arrayContains(element: Expr): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Expr[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Expr[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Expr): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Expr): Divide; + divide(other: any): Divide; + dotProduct(other: Expr): DotProduct; + dotProduct(other: VectorValue): DotProduct; + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Expr): EndsWith; + eq(other: Expr): Eq; + eq(other: any): Eq; + eqAny(...others: Expr[]): EqAny; + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Expr): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + abstract exprType: ExprType; + gt(other: Expr): Gt; + gt(other: any): Gt; + gte(other: Expr): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + like(pattern: Expr): Like; + logicalMaximum(other: Expr): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Expr): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Expr): Lt; + lt(other: any): Lt; + lte(other: Expr): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Expr): Mod; + mod(other: any): Mod; + multiply(other: Expr): Multiply; + multiply(other: any): Multiply; + neq(other: Expr): Neq; + neq(other: any): Neq; + notEqAny(...others: Expr[]): NotEqAny; + notEqAny(...others: any[]): NotEqAny; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Expr): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Expr): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Expr, replace: Expr): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Expr, replace: Expr): ReplaceFirst; + reverse(): Reverse; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Expr): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Expr): StrContains; + subtract(other: Expr): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Expr, amount: Expr): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Expr, amount: Expr): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + +// @beta +export type ExprType = 'Field' | 'Constant' | 'Function' | 'ListOfExprs' | 'ExprWithAlias'; + +// @beta (undocumented) +export class ExprWithAlias extends Expr implements Selectable { + constructor(expr: T, alias: string); + // (undocumented) + readonly alias: string; + // (undocumented) + readonly expr: T; + // (undocumented) + exprType: ExprType; + // (undocumented) + selectable: true; +} + +// @beta +export class Field extends Expr implements Selectable { + // (undocumented) + exprType: ExprType; + // (undocumented) + fieldName(): string; + static of(name: string): Field; + // (undocumented) + static of(path: FieldPath): Field; + // (undocumented) + static of(pipeline: Pipeline, name: string): Field; + // (undocumented) + selectable: true; +} + // @public export class FieldPath { constructor(...fieldNames: string[]); isEqual(other: FieldPath): boolean; } +// @beta (undocumented) +export class Fields extends Expr implements Selectable { + // (undocumented) + exprType: ExprType; + // (undocumented) + fieldList(): Field[]; + // (undocumented) + static of(name: string, ...others: string[]): Fields; + // (undocumented) + static ofAll(): Fields; + // (undocumented) + selectable: true; +} + // @public export abstract class FieldValue { abstract isEqual(other: FieldValue): boolean; } +// @beta +export interface FilterCondition extends Expr { + // (undocumented) + filterable: true; +} + +// @beta (undocumented) +export class FindNearest implements Stage { + // (undocumented) + name: string; +} + +// @beta (undocumented) +export interface FindNearestOptions { + // (undocumented) + distanceField?: string; + // (undocumented) + distanceMeasure: 'euclidean' | 'cosine' | 'dot_product'; + // (undocumented) + field: Field; + // (undocumented) + limit?: number; + // (undocumented) + vectorValue: VectorValue | number[]; +} + // @public export class Firestore { get app(): FirebaseApp; @@ -246,6 +844,13 @@ export class FirestoreError extends FirebaseError { // @public export type FirestoreErrorCode = 'cancelled' | 'unknown' | 'invalid-argument' | 'deadline-exceeded' | 'not-found' | 'already-exists' | 'permission-denied' | 'resource-exhausted' | 'failed-precondition' | 'aborted' | 'out-of-range' | 'unimplemented' | 'internal' | 'unavailable' | 'data-loss' | 'unauthenticated'; +// @beta +export class FirestoreFunction extends Expr { + constructor(name: string, params: Expr[]); + // (undocumented) + exprType: ExprType; + } + // @public export type FirestoreLocalCache = MemoryLocalCache | PersistentLocalCache; @@ -261,6 +866,16 @@ export interface FirestoreSettings { ssl?: boolean; } +// @beta +export function genericFunction(name: string, params: Expr[]): FirestoreFunction; + +// @beta (undocumented) +export class GenericStage implements Stage { + constructor(name: string, params: unknown[]); + // (undocumented) + name: string; +} + // @public export class GeoPoint { constructor(latitude: number, longitude: number); @@ -314,6 +929,44 @@ export function getFirestore(app: FirebaseApp, databaseId: string): Firestore; // @public export function getPersistentCacheIndexManager(firestore: Firestore): PersistentCacheIndexManager | null; +// @beta (undocumented) +export class Gt extends FirestoreFunction implements FilterCondition { + constructor(left: Expr, right: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function gt(left: Expr, right: Expr): Gt; + +// @beta +export function gt(left: Expr, right: any): Gt; + +// @beta +export function gt(left: string, right: Expr): Gt; + +// @beta +export function gt(left: string, right: any): Gt; + +// @beta (undocumented) +export class Gte extends FirestoreFunction implements FilterCondition { + constructor(left: Expr, right: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function gte(left: Expr, right: Expr): Gte; + +// @beta +export function gte(left: Expr, right: any): Gte; + +// @beta +export function gte(left: string, right: Expr): Gte; + +// @beta +export function gte(left: string, right: any): Gte; + // @public export function increment(n: number): FieldValue; @@ -344,6 +997,45 @@ export interface IndexField { // @public export function initializeFirestore(app: FirebaseApp, settings: FirestoreSettings, databaseId?: string): Firestore; +// @beta (undocumented) +export class IsNan extends FirestoreFunction implements FilterCondition { + constructor(expr: Expr); + // (undocumented) + filterable: true; +} + +// @beta +export function isNan(value: Expr): IsNan; + +// @beta +export function isNan(value: string): IsNan; + +// @beta (undocumented) +export class Like extends FirestoreFunction implements FilterCondition { + constructor(expr: Expr, pattern: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function like(left: string, pattern: string): Like; + +// @beta +export function like(left: string, pattern: Expr): Like; + +// @beta +export function like(left: Expr, pattern: string): Like; + +// @beta +export function like(left: Expr, pattern: Expr): Like; + +// @beta (undocumented) +export class Limit implements Stage { + constructor(limit: number); + // (undocumented) + name: string; +} + // @public export function limit(limit: number): QueryLimitConstraint; @@ -372,7 +1064,106 @@ export interface LoadBundleTaskProgress { totalDocuments: number; } -export { LogLevel } +// @beta (undocumented) +export class LogicalMaximum extends FirestoreFunction { + constructor(left: Expr, right: Expr); + } + +// @beta +export function logicalMaximum(left: Expr, right: Expr): LogicalMaximum; + +// @beta +export function logicalMaximum(left: Expr, right: any): LogicalMaximum; + +// @beta +export function logicalMaximum(left: string, right: Expr): LogicalMaximum; + +// @beta +export function logicalMaximum(left: string, right: any): LogicalMaximum; + +// @beta (undocumented) +export class LogicalMinimum extends FirestoreFunction { + constructor(left: Expr, right: Expr); + } + +// @beta +export function logicalMinimum(left: Expr, right: Expr): LogicalMinimum; + +// @beta +export function logicalMinimum(left: Expr, right: any): LogicalMinimum; + +// @beta +export function logicalMinimum(left: string, right: Expr): LogicalMinimum; + +// @beta +export function logicalMinimum(left: string, right: any): LogicalMinimum; + +export { LogLevel } + +// @beta (undocumented) +export class Lt extends FirestoreFunction implements FilterCondition { + constructor(left: Expr, right: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function lt(left: Expr, right: Expr): Lt; + +// @beta +export function lt(left: Expr, right: any): Lt; + +// @beta +export function lt(left: string, right: Expr): Lt; + +// @beta +export function lt(left: string, right: any): Lt; + +// @beta (undocumented) +export class Lte extends FirestoreFunction implements FilterCondition { + constructor(left: Expr, right: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function lte(left: Expr, right: Expr): Lte; + +// @beta +export function lte(left: Expr, right: any): Lte; + +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Expr" which is marked as @beta +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Lte" which is marked as @beta +// +// @public +export function lte(left: string, right: Expr): Lte; + +// @beta +export function lte(left: string, right: any): Lte; + +// @beta (undocumented) +export class MapGet extends FirestoreFunction { + constructor(map: Expr, name: string); +} + +// @beta +export function mapGet(mapField: string, subField: string): MapGet; + +// @beta +export function mapGet(mapExpr: Expr, subField: string): MapGet; + +// @beta (undocumented) +export class Maximum extends FirestoreFunction implements Accumulator { + constructor(value: Expr, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function maximum(value: Expr): Maximum; + +// @beta +export function maximum(value: string): Maximum; // @public export interface MemoryCacheSettings { @@ -411,14 +1202,116 @@ export function memoryLruGarbageCollector(settings?: { cacheSizeBytes?: number; }): MemoryLruGarbageCollector; +// @beta (undocumented) +export class Minimum extends FirestoreFunction implements Accumulator { + constructor(value: Expr, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function minimum(value: Expr): Minimum; + +// @beta +export function minimum(value: string): Minimum; + +// @beta (undocumented) +export class Mod extends FirestoreFunction { + constructor(left: Expr, right: Expr); + } + +// @beta +export function mod(left: Expr, right: Expr): Mod; + +// @beta +export function mod(left: Expr, right: any): Mod; + +// @beta +export function mod(left: string, right: Expr): Mod; + +// @beta +export function mod(left: string, right: any): Mod; + +// @beta (undocumented) +export class Multiply extends FirestoreFunction { + constructor(left: Expr, right: Expr); + } + +// @beta +export function multiply(left: Expr, right: Expr): Multiply; + +// @beta +export function multiply(left: Expr, right: any): Multiply; + +// @beta +export function multiply(left: string, right: Expr): Multiply; + +// @beta +export function multiply(left: string, right: any): Multiply; + // @public export function namedQuery(firestore: Firestore, name: string): Promise; +// @beta (undocumented) +export class Neq extends FirestoreFunction implements FilterCondition { + constructor(left: Expr, right: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function neq(left: Expr, right: Expr): Neq; + +// @beta +export function neq(left: Expr, right: any): Neq; + +// @beta +export function neq(left: string, right: Expr): Neq; + +// @beta +export function neq(left: string, right: any): Neq; + // @public export type NestedUpdateFields> = UnionToIntersection<{ [K in keyof T & string]: ChildUpdateFields; }[keyof T & string]>; +// @beta (undocumented) +export class Not extends FirestoreFunction implements FilterCondition { + constructor(expr: Expr); + // (undocumented) + filterable: true; +} + +// @beta +export function not(filter: FilterCondition): Not; + +// @beta (undocumented) +export class NotEqAny extends FirestoreFunction implements FilterCondition { + constructor(left: Expr, others: Expr[]); + // (undocumented) + filterable: true; + } + +// @beta +export function notEqAny(element: Expr, others: Expr[]): NotEqAny; + +// @beta +export function notEqAny(element: Expr, others: any[]): NotEqAny; + +// @beta +export function notEqAny(element: string, others: Expr[]): NotEqAny; + +// @beta +export function notEqAny(element: string, others: any[]): NotEqAny; + +// @beta (undocumented) +export class Offset implements Stage { + constructor(offset: number); + // (undocumented) + name: string; + } + // @public export function onSnapshot(reference: DocumentReference, observer: { next?: (snapshot: DocumentSnapshot) => void; @@ -469,6 +1362,13 @@ export function onSnapshotsInSync(firestore: Firestore, observer: { // @public export function onSnapshotsInSync(firestore: Firestore, onSync: () => void): Unsubscribe; +// @beta (undocumented) +export class Or extends FirestoreFunction implements FilterCondition { + constructor(conditions: (FilterCondition)[]); + // (undocumented) + filterable: true; +} + // @public export function or(...queryConstraints: QueryFilterConstraint[]): QueryCompositeFilterConstraint; @@ -478,6 +1378,18 @@ export function orderBy(fieldPath: string | FieldPath, directionStr?: OrderByDir // @public export type OrderByDirection = 'desc' | 'asc'; +// @beta +export class Ordering { + constructor(expr: Expr, direction: 'ascending' | 'descending'); + // (undocumented) + readonly direction: 'ascending' | 'descending'; + // (undocumented) + readonly expr: Expr; +} + +// @beta +export function orFunction(left: FilterCondition, ...right: (FilterCondition)[]): Or; + // @public export type PartialWithFieldValue = Partial | (T extends Primitive ? T : T extends {} ? { [K in keyof T]?: PartialWithFieldValue | FieldValue; @@ -534,6 +1446,78 @@ export interface PersistentSingleTabManagerSettings { // @public export type PersistentTabManager = PersistentSingleTabManager | PersistentMultipleTabManager; +// @public (undocumented) +export class Pipeline { + /* Excluded from this release type: newPipeline */ + // Warning: (ae-incompatible-release-tags) The symbol "addFields" is marked as @public, but its signature references "Selectable" which is marked as @beta + addFields(...fields: Selectable[]): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta + aggregate(...accumulators: AccumulatorTarget[]): Pipeline; + aggregate(options: { accumulators: AccumulatorTarget[]; groups?: Array; }): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta + distinct(...groups: Array): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta + execute(): Promise; + // Warning: (ae-incompatible-release-tags) The symbol "findNearest" is marked as @public, but its signature references "FindNearestOptions" which is marked as @beta + // + // (undocumented) + findNearest(options: FindNearestOptions): Pipeline; + genericStage(name: string, params: any[]): Pipeline; + limit(limit: number): Pipeline; + offset(offset: number): Pipeline; + readUserData: any; + // Warning: (ae-incompatible-release-tags) The symbol "select" is marked as @public, but its signature references "Selectable" which is marked as @beta + select(...selections: Array): Pipeline; + // (undocumented) + selectablesToMap: any; + // Warning: (ae-incompatible-release-tags) The symbol "sort" is marked as @public, but its signature references "Ordering" which is marked as @beta + sort(...orderings: Ordering[]): Pipeline; + // (undocumented) + sort(options: { orderings: Ordering[]; }): Pipeline; + // (undocumented) + stages: any; + // (undocumented) + userDataReader: any; + // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "FilterCondition" which is marked as @beta + where(condition: FilterCondition): Pipeline; +} + +// Warning: (ae-incompatible-release-tags) The symbol "pipeline" is marked as @public, but its signature references "PipelineSource" which is marked as @beta +// +// @public +export function pipeline(firestore: Firestore): PipelineSource; + +// @public +export function pipeline(query: Query): Pipeline; + +// @beta +export class PipelineResult { + /* Excluded from this release type: _ref */ + /* Excluded from this release type: _fields */ + /* Excluded from this release type: __constructor */ + get createTime(): Timestamp | undefined; + data(): AppModelType | undefined; + get executionTime(): Timestamp; + get(fieldPath: string | FieldPath): any; + get id(): string | undefined; + get ref(): DocumentReference | undefined; + get updateTime(): Timestamp | undefined; +} + +// @beta +export class PipelineSource { + /* Excluded from this release type: _createPipeline */ + /* Excluded from this release type: __constructor */ + // (undocumented) + collection(collectionPath: string): PipelineType; + // (undocumented) + collectionGroup(collectionId: string): PipelineType; + // (undocumented) + database(): PipelineType; + // (undocumented) + documents(docs: DocumentReference[]): PipelineType; +} + // @public export type Primitive = string | number | boolean | undefined | null; @@ -620,9 +1604,99 @@ export class QueryStartAtConstraint extends QueryConstraint { // @public export function refEqual(left: DocumentReference | CollectionReference, right: DocumentReference | CollectionReference): boolean; +// @beta (undocumented) +export class RegexContains extends FirestoreFunction implements FilterCondition { + constructor(expr: Expr, pattern: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function regexContains(left: string, pattern: string): RegexContains; + +// @beta +export function regexContains(left: string, pattern: Expr): RegexContains; + +// @beta +export function regexContains(left: Expr, pattern: string): RegexContains; + +// @beta +export function regexContains(left: Expr, pattern: Expr): RegexContains; + +// @beta (undocumented) +export class RegexMatch extends FirestoreFunction implements FilterCondition { + constructor(expr: Expr, pattern: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function regexMatch(left: string, pattern: string): RegexMatch; + +// @beta +export function regexMatch(left: string, pattern: Expr): RegexMatch; + +// @beta +export function regexMatch(left: Expr, pattern: string): RegexMatch; + +// @beta +export function regexMatch(left: Expr, pattern: Expr): RegexMatch; + +// @beta (undocumented) +export class ReplaceAll extends FirestoreFunction { + constructor(value: Expr, find: Expr, replace: Expr); + } + +// @beta +export function replaceAll(value: Expr, find: string, replace: string): ReplaceAll; + +// @beta +export function replaceAll(value: Expr, find: Expr, replace: Expr): ReplaceAll; + +// @beta +export function replaceAll(field: string, find: string, replace: string): ReplaceAll; + +// @beta (undocumented) +export class ReplaceFirst extends FirestoreFunction { + constructor(value: Expr, find: Expr, replace: Expr); + } + +// @beta +export function replaceFirst(value: Expr, find: string, replace: string): ReplaceFirst; + +// @beta +export function replaceFirst(value: Expr, find: Expr, replace: Expr): ReplaceFirst; + +// @beta +export function replaceFirst(field: string, find: string, replace: string): ReplaceFirst; + +// @beta (undocumented) +export class Reverse extends FirestoreFunction { + constructor(value: Expr); + } + +// @beta +export function reverse(expr: Expr): Reverse; + +// @beta +export function reverse(field: string): Reverse; + // @public export function runTransaction(firestore: Firestore, updateFunction: (transaction: Transaction) => Promise, options?: TransactionOptions): Promise; +// @beta (undocumented) +export class Select implements Stage { + constructor(projections: Map); + // (undocumented) + name: string; + } + +// @beta +export interface Selectable extends Expr { + // (undocumented) + selectable: true; +} + // @public export function serverTimestamp(): FieldValue; @@ -669,6 +1743,19 @@ export interface SnapshotOptions { readonly serverTimestamps?: 'estimate' | 'previous' | 'none'; } +// @beta (undocumented) +export class Sort implements Stage { + constructor(orders: Ordering[]); + // (undocumented) + name: string; + } + +// @beta (undocumented) +export interface Stage { + // (undocumented) + name: string; +} + // @public export function startAfter(snapshot: DocumentSnapshot): QueryStartAtConstraint; @@ -681,9 +1768,88 @@ export function startAt(snapshot // @public export function startAt(...fieldValues: unknown[]): QueryStartAtConstraint; +// @beta (undocumented) +export class StartsWith extends FirestoreFunction implements FilterCondition { + constructor(expr: Expr, prefix: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function startsWith(expr: string, prefix: string): StartsWith; + +// @beta +export function startsWith(expr: string, prefix: Expr): StartsWith; + +// @beta +export function startsWith(expr: Expr, prefix: string): StartsWith; + +// @beta +export function startsWith(expr: Expr, prefix: Expr): StartsWith; + +// @beta (undocumented) +export class StrConcat extends FirestoreFunction { + constructor(first: Expr, rest: Expr[]); + } + +// @beta +export function strConcat(first: string, ...elements: Array): StrConcat; + +// @beta +export function strConcat(first: Expr, ...elements: Array): StrConcat; + +// @beta (undocumented) +export class StrContains extends FirestoreFunction implements FilterCondition { + constructor(expr: Expr, substring: Expr); + // (undocumented) + filterable: true; + } + +// @beta +export function strContains(left: string, substring: string): StrContains; + +// @beta +export function strContains(left: string, substring: Expr): StrContains; + +// @beta +export function strContains(left: Expr, substring: string): StrContains; + +// @beta +export function strContains(left: Expr, substring: Expr): StrContains; + +// @beta (undocumented) +export class Subtract extends FirestoreFunction { + constructor(left: Expr, right: Expr); + } + +// @beta +export function subtract(left: Expr, right: Expr): Subtract; + +// @beta +export function subtract(left: Expr, right: any): Subtract; + +// @beta +export function subtract(left: string, right: Expr): Subtract; + +// @beta +export function subtract(left: string, right: any): Subtract; + +// @beta (undocumented) +export class Sum extends FirestoreFunction implements Accumulator { + constructor(value: Expr, distinct: boolean); + // (undocumented) + accumulator: true; + } + // @public export function sum(field: string | FieldPath): AggregateField; +// @beta +export function sumFunction(value: Expr): Sum; + +// @beta +export function sumFunction(value: string): Sum; + // @public export type TaskState = 'Error' | 'Running' | 'Success'; @@ -711,6 +1877,89 @@ export class Timestamp { valueOf(): string; } +// @beta (undocumented) +export class TimestampAdd extends FirestoreFunction { + constructor(timestamp: Expr, unit: Expr, amount: Expr); + } + +// @beta +export function timestampAdd(timestamp: Expr, unit: Expr, amount: Expr): TimestampAdd; + +// @beta +export function timestampAdd(timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + +// @beta +export function timestampAdd(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + +// @beta (undocumented) +export class TimestampSub extends FirestoreFunction { + constructor(timestamp: Expr, unit: Expr, amount: Expr); + } + +// @beta +export function timestampSub(timestamp: Expr, unit: Expr, amount: Expr): TimestampSub; + +// @beta +export function timestampSub(timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + +// @beta +export function timestampSub(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + +// @beta (undocumented) +export class TimestampToUnixMicros extends FirestoreFunction { + constructor(input: Expr); + } + +// @beta +export function timestampToUnixMicros(expr: Expr): TimestampToUnixMicros; + +// @beta +export function timestampToUnixMicros(field: string): TimestampToUnixMicros; + +// @beta (undocumented) +export class TimestampToUnixMillis extends FirestoreFunction { + constructor(input: Expr); + } + +// @beta +export function timestampToUnixMillis(expr: Expr): TimestampToUnixMillis; + +// @beta +export function timestampToUnixMillis(field: string): TimestampToUnixMillis; + +// @beta (undocumented) +export class TimestampToUnixSeconds extends FirestoreFunction { + constructor(input: Expr); + } + +// @beta +export function timestampToUnixSeconds(expr: Expr): TimestampToUnixSeconds; + +// @beta +export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; + +// @beta (undocumented) +export class ToLower extends FirestoreFunction { + constructor(expr: Expr); + } + +// @beta +export function toLower(expr: string): ToLower; + +// @beta +export function toLower(expr: Expr): ToLower; + +// @beta (undocumented) +export class ToUpper extends FirestoreFunction { + constructor(expr: Expr); + } + +// @beta +export function toUpper(expr: string): ToUpper; + +// @beta +export function toUpper(expr: Expr): ToUpper; + // @public export class Transaction { delete(documentRef: DocumentReference): this; @@ -726,9 +1975,53 @@ export interface TransactionOptions { readonly maxAttempts?: number; } +// @beta (undocumented) +export class Trim extends FirestoreFunction { + constructor(expr: Expr); + } + +// @beta +export function trim(expr: string): Trim; + +// @beta +export function trim(expr: Expr): Trim; + // @public export type UnionToIntersection = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never; +// @beta (undocumented) +export class UnixMicrosToTimestamp extends FirestoreFunction { + constructor(input: Expr); + } + +// @beta +export function unixMicrosToTimestamp(expr: Expr): UnixMicrosToTimestamp; + +// @beta +export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; + +// @beta (undocumented) +export class UnixMillisToTimestamp extends FirestoreFunction { + constructor(input: Expr); + } + +// @beta +export function unixMillisToTimestamp(expr: Expr): UnixMillisToTimestamp; + +// @beta +export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; + +// @beta (undocumented) +export class UnixSecondsToTimestamp extends FirestoreFunction { + constructor(input: Expr); + } + +// @beta +export function unixSecondsToTimestamp(expr: Expr): UnixSecondsToTimestamp; + +// @beta +export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; + // @public export interface Unsubscribe { (): void; @@ -748,6 +2041,17 @@ export function updateDoc(refere // @public export function vector(values?: number[]): VectorValue; +// @beta (undocumented) +export class VectorLength extends FirestoreFunction { + constructor(value: Expr); + } + +// @beta +export function vectorLength(expr: Expr): VectorLength; + +// @beta +export function vectorLength(field: string): VectorLength; + // @public export class VectorValue { /* Excluded from this release type: __constructor */ @@ -758,6 +2062,13 @@ export class VectorValue { // @public export function waitForPendingWrites(firestore: Firestore): Promise; +// @beta (undocumented) +export class Where implements Stage { + constructor(condition: FilterCondition); + // (undocumented) + name: string; +} + // @public export function where(fieldPath: string | FieldPath, opStr: WhereFilterOp, value: unknown): QueryFieldFilterConstraint; @@ -782,5 +2093,21 @@ export class WriteBatch { // @public export function writeBatch(firestore: Firestore): WriteBatch; +// @beta (undocumented) +export class Xor extends FirestoreFunction implements FilterCondition { + constructor(conditions: (FilterCondition)[]); + // (undocumented) + filterable: true; +} + +// @beta +export function xor(left: FilterCondition, ...right: (FilterCondition)[]): Xor; + + +// Warnings were encountered during analysis: +// +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/all_packages.d.ts:5962:26 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/all_packages.d.ts:5962:61 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/all_packages.d.ts:5989:21 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta ``` From 0522ea7804a61cf8124d5c093c3fdc96b72834e0 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:14:03 -0700 Subject: [PATCH 15/75] Query to Proto with integration tests --- .../firestore-lite-pipelines.api.md | 24 +- common/api-review/firestore-lite.api.md | 1795 ++++++++++++- common/api-review/firestore-pipelines.api.md | 28 +- packages/firestore/src/api/pipeline_impl.ts | 19 +- packages/firestore/src/core/pipeline-util.ts | 142 +- .../firestore/src/lite-api/expressions.ts | 20 +- packages/firestore/src/lite-api/pipeline.ts | 11 + packages/firestore/src/lite-api/stage.ts | 11 +- .../test/integration/api/pipeline.test.ts | 2234 +++++++++++------ 9 files changed, 3425 insertions(+), 859 deletions(-) diff --git a/common/api-review/firestore-lite-pipelines.api.md b/common/api-review/firestore-lite-pipelines.api.md index aa7e062f068..d1536c8a626 100644 --- a/common/api-review/firestore-lite-pipelines.api.md +++ b/common/api-review/firestore-lite-pipelines.api.md @@ -149,7 +149,7 @@ export class Aggregate implements Stage { // @beta (undocumented) export class And extends FirestoreFunction implements FilterCondition { - constructor(conditions: (FilterCondition)[]); + constructor(conditions: FilterCondition[]); // (undocumented) filterable: true; } @@ -1271,7 +1271,11 @@ export function like(left: Accumulator, pattern: Accumulator): Like; // @beta (undocumented) export class Limit implements Stage { - constructor(limit: number); + constructor(limit: number, convertedFromLimitTolast?: boolean); + // (undocumented) + readonly convertedFromLimitTolast: boolean; + // (undocumented) + readonly limit: number; // (undocumented) name: string; } @@ -1472,7 +1476,7 @@ export class Offset implements Stage { // @beta (undocumented) export class Or extends FirestoreFunction implements FilterCondition { - constructor(conditions: (FilterCondition)[]); + constructor(conditions: FilterCondition[]); // (undocumented) filterable: true; } @@ -1501,7 +1505,7 @@ export class Pipeline { }): Pipeline; /* Excluded from this release type: _userDataWriter */ // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta - distinct(...groups: Array): Pipeline; + distinct(...groups: Array): Pipeline; /* Excluded from this release type: _userDataWriter */ // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta execute(): Promise; @@ -1996,19 +2000,21 @@ export class Where implements Stage { // @beta (undocumented) export class Xor extends FirestoreFunction implements FilterCondition { - constructor(conditions: (FilterCondition)[]); + constructor(conditions: FilterCondition[]); // (undocumented) filterable: true; } // @beta -export function xor(left: FilterCondition, ...right: (FilterCondition)[]): Xor; +export function xor(left: FilterCondition, ...right: FilterCondition[]): Xor; // Warnings were encountered during analysis: // -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:10252:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:10253:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:10282:9 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:10253:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:10254:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:10283:9 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta + +// (No @packageDocumentation comment for this package) ``` diff --git a/common/api-review/firestore-lite.api.md b/common/api-review/firestore-lite.api.md index 4a9ef4c0171..29c373ff3c1 100644 --- a/common/api-review/firestore-lite.api.md +++ b/common/api-review/firestore-lite.api.md @@ -9,14 +9,54 @@ import { FirebaseApp } from '@firebase/app'; import { FirebaseError } from '@firebase/util'; import { LogLevelString as LogLevel } from '@firebase/logger'; +// @beta +export interface Accumulator { + // (undocumented) + accumulator: true; +} + +// @beta +export type AccumulatorTarget = ExprWithAlias; + +// @beta (undocumented) +export class Add extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function add(left: Constant, right: Constant): Add; + +// @beta +export function add(left: Constant, right: any): Add; + +// @beta +export function add(left: string, right: Constant): Add; + +// @beta +export function add(left: string, right: any): Add; + // @public export function addDoc(reference: CollectionReference, data: WithFieldValue): Promise>; +// @beta (undocumented) +export class AddFields implements Stage { + constructor(fields: Map); + // (undocumented) + name: string; +} + // @public export type AddPrefixToKeys> = { [K in keyof T & string as `${Prefix}.${K}`]+?: string extends K ? any : T[K]; }; +// @beta (undocumented) +export class Aggregate implements Stage { + constructor(accumulators: Map, groups: Map); + // (undocumented) + name: string; +} + // @public export class AggregateField { readonly aggregateType: AggregateType; @@ -53,18 +93,138 @@ export type AggregateSpecData = { // @public export type AggregateType = 'count' | 'avg' | 'sum'; +// @beta (undocumented) +export class And extends FirestoreFunction implements FilterCondition { + constructor(conditions: FilterExpr[]); + // (undocumented) + filterable: true; +} + // @public export function and(...queryConstraints: QueryFilterConstraint[]): QueryCompositeFilterConstraint; +// @beta (undocumented) +export class ArrayConcat extends FirestoreFunction { + constructor(array: Constant, elements: Constant[]); + } + +// @beta +export function arrayConcat(array: Constant, elements: Constant[]): ArrayConcat; + +// @beta +export function arrayConcat(array: Constant, elements: any[]): ArrayConcat; + +// @beta +export function arrayConcat(array: string, elements: Constant[]): ArrayConcat; + +// @beta +export function arrayConcat(array: string, elements: any[]): ArrayConcat; + +// @beta (undocumented) +export class ArrayContains extends FirestoreFunction implements FilterCondition { + constructor(array: Constant, element: Constant); + // (undocumented) + filterable: true; +} + +// @beta +export function arrayContains(array: Constant, element: Constant): ArrayContains; + +// @beta +export function arrayContains(array: Constant, element: any): ArrayContains; + +// @beta +export function arrayContains(array: string, element: Constant): ArrayContains; + +// @beta +export function arrayContains(array: string, element: any): ArrayContains; + +// @beta (undocumented) +export class ArrayContainsAll extends FirestoreFunction implements FilterCondition { + constructor(array: Constant, values: Constant[]); + // (undocumented) + filterable: true; + } + +// @beta +export function arrayContainsAll(array: Constant, values: Constant[]): ArrayContainsAll; + +// @beta +export function arrayContainsAll(array: Constant, values: any[]): ArrayContainsAll; + +// @beta +export function arrayContainsAll(array: string, values: Constant[]): ArrayContainsAll; + +// @beta +export function arrayContainsAll(array: string, values: any[]): ArrayContainsAll; + +// @beta (undocumented) +export class ArrayContainsAny extends FirestoreFunction implements FilterCondition { + constructor(array: Constant, values: Constant[]); + // (undocumented) + filterable: true; + } + +// @beta +export function arrayContainsAny(array: Constant, values: Constant[]): ArrayContainsAny; + +// @beta +export function arrayContainsAny(array: Constant, values: any[]): ArrayContainsAny; + +// @beta +export function arrayContainsAny(array: string, values: Constant[]): ArrayContainsAny; + +// @beta +export function arrayContainsAny(array: string, values: any[]): ArrayContainsAny; + +// @beta (undocumented) +export class ArrayElement extends FirestoreFunction { + constructor(); +} + +// @beta (undocumented) +export class ArrayLength extends FirestoreFunction { + constructor(array: Constant); + } + +// @beta +export function arrayLength(array: Constant): ArrayLength; + // @public export function arrayRemove(...elements: unknown[]): FieldValue; +// @beta (undocumented) +export class ArrayReverse extends FirestoreFunction { + constructor(array: Constant); + } + // @public export function arrayUnion(...elements: unknown[]): FieldValue; +// @beta +export function ascending(expr: Constant): Ordering; + // @public export function average(field: string | FieldPath): AggregateField; +// @beta (undocumented) +export class Avg extends FirestoreFunction implements Accumulator { + constructor(value: Constant, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta (undocumented) +export class ByteLength extends FirestoreFunction { + constructor(value: Constant); + } + +// @beta +export function byteLength(expr: Constant): ByteLength; + +// @beta +export function byteLength(field: string): ByteLength; + // @public export class Bytes { static fromBase64String(base64: string): Bytes; @@ -75,6 +235,17 @@ export class Bytes { toUint8Array(): Uint8Array; } +// @beta (undocumented) +export class CharLength extends FirestoreFunction { + constructor(value: Constant); + } + +// @beta +export function charLength(field: string): CharLength; + +// @beta +export function charLength(expr: Constant): CharLength; + // @public export type ChildUpdateFields = V extends Record ? AddPrefixToKeys> : never; @@ -90,6 +261,13 @@ export function collection(refer // @public export function collectionGroup(firestore: Firestore, collectionId: string): Query; +// @beta (undocumented) +export class CollectionGroupSource implements Stage { + constructor(collectionId: string); + // (undocumented) + name: string; +} + // @public export class CollectionReference extends Query { get id(): string; @@ -100,20 +278,220 @@ export class CollectionReference; } +// @beta (undocumented) +export class CollectionSource implements Stage { + constructor(collectionPath: string); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class Cond extends FirestoreFunction implements FilterCondition { + constructor(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function cond(condition: FilterExpr, thenExpr: Constant, elseExpr: Constant): Cond; + // @public export function connectFirestoreEmulator(firestore: Firestore, host: string, port: number, options?: { mockUserToken?: EmulatorMockTokenOptions | string; }): void; +// @beta +export class Constant { + add(other: Constant): Add; + add(other: any): Add; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + static of(value: number): Constant; + static of(value: string): Constant; + static of(value: boolean): Constant; + static of(value: null): Constant; + static of(value: GeoPoint): Constant; + static of(value: Timestamp): Constant; + static of(value: Date): Constant; + static of(value: Bytes): Constant; + static of(value: DocumentReference): Constant; + static of(value: any[]): Constant; + static of(value: Record): Constant; + static of(value: VectorValue): Constant; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + static vector(value: number[] | VectorValue): Constant; + vectorLength(): VectorLength; +} + +// @beta (undocumented) +export class CosineDistance extends FirestoreFunction { + constructor(vector1: Constant, vector2: Constant); + } + +// @beta +export function cosineDistance(expr: string, other: number[]): CosineDistance; + +// @beta +export function cosineDistance(expr: string, other: VectorValue): CosineDistance; + +// @beta +export function cosineDistance(expr: string, other: Constant): CosineDistance; + +// @beta +export function cosineDistance(expr: Constant, other: number[]): CosineDistance; + +// @beta +export function cosineDistance(expr: Constant, other: VectorValue): CosineDistance; + +// @beta +export function cosineDistance(expr: Constant, other: Constant): CosineDistance; + +// @beta (undocumented) +export class Count extends FirestoreFunction implements Accumulator { + constructor(value: Constant | undefined, distinct: boolean); + // (undocumented) + accumulator: true; + } + // @public export function count(): AggregateField; +// @beta +export function countAll(): Count; + +// @beta (undocumented) +export class DatabaseSource implements Stage { + // (undocumented) + name: string; +} + // @public export function deleteDoc(reference: DocumentReference): Promise; // @public export function deleteField(): FieldValue; +// @beta +export function descending(expr: Constant): Ordering; + +// @beta (undocumented) +export class Distinct implements Stage { + constructor(groups: Map); + // (undocumented) + name: string; +} + +// @beta (undocumented) +export class Divide extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function divide(left: Constant, right: Constant): Divide; + +// @beta +export function divide(left: Constant, right: any): Divide; + +// @beta +export function divide(left: string, right: Constant): Divide; + +// @beta +export function divide(left: string, right: any): Divide; + // @public export function doc(firestore: Firestore, path: string, ...pathSegments: string[]): DocumentReference; @@ -153,6 +531,38 @@ export class DocumentSnapshot; } +// @beta (undocumented) +export class DocumentsSource implements Stage { + constructor(docPaths: string[]); + // (undocumented) + name: string; + // (undocumented) + static of(refs: DocumentReference[]): DocumentsSource; +} + +// @beta (undocumented) +export class DotProduct extends FirestoreFunction { + constructor(vector1: Constant, vector2: Constant); + } + +// @beta +export function dotProduct(expr: string, other: number[]): DotProduct; + +// @beta +export function dotProduct(expr: string, other: VectorValue): DotProduct; + +// @beta +export function dotProduct(expr: string, other: Constant): DotProduct; + +// @beta +export function dotProduct(expr: Constant, other: number[]): DotProduct; + +// @beta +export function dotProduct(expr: Constant, other: VectorValue): DotProduct; + +// @beta +export function dotProduct(expr: Constant, other: Constant): DotProduct; + export { EmulatorMockTokenOptions } // @public @@ -167,17 +577,481 @@ export function endBefore(snapsh // @public export function endBefore(...fieldValues: unknown[]): QueryEndAtConstraint; +// @beta (undocumented) +export class EndsWith extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, suffix: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function endsWith(expr: string, suffix: string): EndsWith; + +// @beta +export function endsWith(expr: string, suffix: Constant): EndsWith; + +// @beta +export function endsWith(expr: Constant, suffix: string): EndsWith; + +// @beta +export function endsWith(expr: Constant, suffix: Constant): EndsWith; + +// @beta (undocumented) +export class Eq extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function eq(left: Constant, right: Constant): Eq; + +// @beta +export function eq(left: Constant, right: any): Eq; + +// @beta +export function eq(left: string, right: Constant): Eq; + +// @beta +export function eq(left: string, right: any): Eq; + +// @beta (undocumented) +export class EqAny extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, others: Constant[]); + // (undocumented) + filterable: true; + } + +// @beta +export function eqAny(element: Constant, others: Constant[]): EqAny; + +// @beta +export function eqAny(element: Constant, others: any[]): EqAny; + +// @beta +export function eqAny(element: string, others: Constant[]): EqAny; + +// @beta +export function eqAny(element: string, others: any[]): EqAny; + +// @beta (undocumented) +export class EuclideanDistance extends FirestoreFunction { + constructor(vector1: Constant, vector2: Constant); + } + +// @beta +export function euclideanDistance(expr: string, other: number[]): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: string, other: VectorValue): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: string, other: Constant): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: Constant, other: number[]): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: Constant, other: VectorValue): EuclideanDistance; + +// @beta +export function euclideanDistance(expr: Constant, other: Constant): EuclideanDistance; + +// @beta +export function execute(pipeline: Pipeline): Promise>>; + +// @beta (undocumented) +export class Exists extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant); + // (undocumented) + filterable: true; +} + +// @beta +export function exists(value: Constant): Exists; + +// @beta +export function exists(field: string): Exists; + +// @beta +export type ExprType = 'Field' | 'Constant' | 'Function' | 'ListOfExprs' | 'ExprWithAlias'; + +// @beta (undocumented) +export class ExprWithAlias implements Selectable { + constructor(expr: T, alias: string); + add(other: Constant): Add; + add(other: any): Add; + // (undocumented) + alias: string; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + expr: T; + // (undocumented) + exprType: ExprType; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + // (undocumented) + selectable: true; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + +// @beta +export class Field implements Selectable { + add(other: Constant): Add; + add(other: any): Add; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + // (undocumented) + fieldName(): string; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + static of(name: string): Field; + // (undocumented) + static of(path: FieldPath): Field; + // (undocumented) + static of(pipeline: Pipeline, name: string): Field; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + // (undocumented) + selectable: true; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + // @public export class FieldPath { constructor(...fieldNames: string[]); isEqual(other: FieldPath): boolean; } +// @beta (undocumented) +export class Fields implements Selectable { + add(other: Constant): Add; + add(other: any): Add; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + // (undocumented) + fieldList(): Field[]; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + // (undocumented) + static of(name: string, ...others: string[]): Fields; + // (undocumented) + static ofAll(): Fields; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + // (undocumented) + selectable: true; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + // @public export abstract class FieldValue { abstract isEqual(other: FieldValue): boolean; } +// @beta +export interface FilterCondition { + // (undocumented) + filterable: true; +} + +// @beta +export type FilterExpr = Constant & FilterCondition; + +// @beta (undocumented) +export class FindNearest implements Stage { + // (undocumented) + name: string; +} + +// @beta (undocumented) +export interface FindNearestOptions { + // (undocumented) + distanceField?: string; + // (undocumented) + distanceMeasure: 'euclidean' | 'cosine' | 'dot_product'; + // (undocumented) + field: Field; + // (undocumented) + limit?: number; + // (undocumented) + vectorValue: VectorValue | number[]; +} + // @public export class Firestore { get app(): FirebaseApp; @@ -199,69 +1073,466 @@ export class FirestoreError extends FirebaseError { readonly stack?: string; } -// @public -export type FirestoreErrorCode = 'cancelled' | 'unknown' | 'invalid-argument' | 'deadline-exceeded' | 'not-found' | 'already-exists' | 'permission-denied' | 'resource-exhausted' | 'failed-precondition' | 'aborted' | 'out-of-range' | 'unimplemented' | 'internal' | 'unavailable' | 'data-loss' | 'unauthenticated'; +// @public +export type FirestoreErrorCode = 'cancelled' | 'unknown' | 'invalid-argument' | 'deadline-exceeded' | 'not-found' | 'already-exists' | 'permission-denied' | 'resource-exhausted' | 'failed-precondition' | 'aborted' | 'out-of-range' | 'unimplemented' | 'internal' | 'unavailable' | 'data-loss' | 'unauthenticated'; + +// @beta +export class FirestoreFunction { + constructor(name: string, params: Constant[]); + add(other: Constant): Add; + add(other: any): Add; + arrayConcat(arrays: Constant[]): ArrayConcat; + arrayConcat(arrays: any[]): ArrayConcat; + arrayContains(element: Constant): ArrayContains; + arrayContains(element: any): ArrayContains; + arrayContainsAll(...values: Constant[]): ArrayContainsAll; + arrayContainsAll(...values: any[]): ArrayContainsAll; + arrayContainsAny(...values: Constant[]): ArrayContainsAny; + arrayContainsAny(...values: any[]): ArrayContainsAny; + arrayLength(): ArrayLength; + as(name: string): ExprWithAlias; + ascending(): Ordering; + avg(): Avg; + byteLength(): ByteLength; + charLength(): CharLength; + cosineDistance(other: Constant): CosineDistance; + cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: number[]): CosineDistance; + count(): Count; + descending(): Ordering; + divide(other: Constant): Divide; + divide(other: any): Divide; + dotProduct(other: Constant): DotProduct; + dotProduct(other: VectorValue): DotProduct; + // (undocumented) + dotProduct(other: number[]): DotProduct; + endsWith(suffix: string): EndsWith; + endsWith(suffix: Constant): EndsWith; + eq(other: Constant): Eq; + eq(other: any): Eq; + eqAny(...others: Constant[]): EqAny; + // (undocumented) + eqAny(...others: any[]): EqAny; + euclideanDistance(other: Constant): EuclideanDistance; + euclideanDistance(other: VectorValue): EuclideanDistance; + // (undocumented) + euclideanDistance(other: number[]): EuclideanDistance; + exists(): Exists; + // (undocumented) + exprType: ExprType; + gt(other: Constant): Gt; + gt(other: any): Gt; + gte(other: Constant): Gte; + gte(other: any): Gte; + isNaN(): IsNan; + like(pattern: string): Like; + // (undocumented) + like(pattern: Constant): Like; + logicalMaximum(other: Constant): LogicalMaximum; + logicalMaximum(other: any): LogicalMaximum; + logicalMinimum(other: Constant): LogicalMinimum; + logicalMinimum(other: any): LogicalMinimum; + lt(other: Constant): Lt; + lt(other: any): Lt; + lte(other: Constant): Lte; + lte(other: any): Lte; + mapGet(subfield: string): MapGet; + maximum(): Maximum; + minimum(): Minimum; + mod(other: Constant): Mod; + mod(other: any): Mod; + multiply(other: Constant): Multiply; + multiply(other: any): Multiply; + neq(other: Constant): Neq; + neq(other: any): Neq; + notEqAny(...others: Constant[]): FirestoreFunction; + // (undocumented) + notEqAny(...others: any[]): FirestoreFunction; + regexContains(pattern: string): RegexContains; + regexContains(pattern: Constant): RegexContains; + regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: Constant): RegexMatch; + replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: Constant, replace: Constant): ReplaceAll; + replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: Constant, replace: Constant): ReplaceFirst; + reverse(): Reverse; + startsWith(prefix: string): StartsWith; + startsWith(prefix: Constant): StartsWith; + strConcat(...elements: Array): StrConcat; + strContains(substring: string): StrContains; + strContains(expr: Constant): StrContains; + subtract(other: Constant): Subtract; + subtract(other: any): Subtract; + sum(): Sum; + timestampAdd(unit: Constant, amount: Constant): TimestampAdd; + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + timestampSub(unit: Constant, amount: Constant): TimestampSub; + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + timestampToUnixMicros(): TimestampToUnixMicros; + timestampToUnixMillis(): TimestampToUnixMillis; + timestampToUnixSeconds(): TimestampToUnixSeconds; + toLower(): ToLower; + toUpper(): ToUpper; + trim(): Trim; + unixMicrosToTimestamp(): UnixMicrosToTimestamp; + unixMillisToTimestamp(): UnixMillisToTimestamp; + unixSecondsToTimestamp(): UnixSecondsToTimestamp; + vectorLength(): VectorLength; +} + +// @beta +export function genericFunction(name: string, params: Constant[]): FirestoreFunction; + +// @beta (undocumented) +export class GenericStage implements Stage { + constructor(name: string, params: unknown[]); + // (undocumented) + name: string; +} + +// @public +export class GeoPoint { + constructor(latitude: number, longitude: number); + isEqual(other: GeoPoint): boolean; + get latitude(): number; + get longitude(): number; + toJSON(): { + latitude: number; + longitude: number; + }; +} + +// @public +export function getAggregate(query: Query, aggregateSpec: AggregateSpecType): Promise>; + +// @public +export function getCount(query: Query): Promise; +}, AppModelType, DbModelType>>; + +// @public +export function getDoc(reference: DocumentReference): Promise>; + +// @public +export function getDocs(query: Query): Promise>; + +// @public +export function getFirestore(): Firestore; + +// @public +export function getFirestore(app: FirebaseApp): Firestore; + +// @beta +export function getFirestore(databaseId: string): Firestore; + +// @beta +export function getFirestore(app: FirebaseApp, databaseId: string): Firestore; + +// @beta (undocumented) +export class Gt extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function gt(left: Constant, right: Constant): Gt; + +// @beta +export function gt(left: Constant, right: any): Gt; + +// @beta +export function gt(left: string, right: Constant): Gt; + +// @beta +export function gt(left: string, right: any): Gt; + +// @beta (undocumented) +export class Gte extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function gte(left: Constant, right: Constant): Gte; + +// @beta +export function gte(left: Constant, right: any): Gte; + +// @beta +export function gte(left: string, right: Constant): Gte; + +// @beta +export function gte(left: string, right: any): Gte; + +// @public +export function increment(n: number): FieldValue; + +// @public +export function initializeFirestore(app: FirebaseApp, settings: Settings): Firestore; + +// @beta +export function initializeFirestore(app: FirebaseApp, settings: Settings, databaseId?: string): Firestore; + +// @beta (undocumented) +export class IsNan extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant); + // (undocumented) + filterable: true; +} + +// @beta +export function isNan(value: Constant): IsNan; + +// @beta +export function isNan(value: string): IsNan; + +// @beta (undocumented) +export class Like extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, pattern: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function like(left: string, pattern: string): Like; + +// @beta +export function like(left: string, pattern: Constant): Like; + +// @beta +export function like(left: Constant, pattern: string): Like; + +// @beta +export function like(left: Constant, pattern: Constant): Like; + +// @beta (undocumented) +export class Limit implements Stage { + constructor(limit: number, convertedFromLimitTolast?: boolean); + // (undocumented) + readonly convertedFromLimitTolast: boolean; + // (undocumented) + readonly limit: number; + // (undocumented) + name: string; +} + +// @public +export function limit(limit: number): QueryLimitConstraint; + +// @public +export function limitToLast(limit: number): QueryLimitConstraint; + +// @beta (undocumented) +export class LogicalMaximum extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function logicalMaximum(left: Constant, right: Constant): LogicalMaximum; + +// @beta +export function logicalMaximum(left: Constant, right: any): LogicalMaximum; + +// @beta +export function logicalMaximum(left: string, right: Constant): LogicalMaximum; + +// @beta +export function logicalMaximum(left: string, right: any): LogicalMaximum; + +// @beta (undocumented) +export class LogicalMinimum extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function logicalMinimum(left: Constant, right: Constant): LogicalMinimum; + +// @beta +export function logicalMinimum(left: Constant, right: any): LogicalMinimum; + +// @beta +export function logicalMinimum(left: string, right: Constant): LogicalMinimum; + +// @beta +export function logicalMinimum(left: string, right: any): LogicalMinimum; + +export { LogLevel } + +// @beta (undocumented) +export class Lt extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function lt(left: Constant, right: Constant): Lt; + +// @beta +export function lt(left: Constant, right: any): Lt; + +// @beta +export function lt(left: string, right: Constant): Lt; + +// @beta +export function lt(left: string, right: any): Lt; + +// @beta (undocumented) +export class Lte extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function lte(left: Constant, right: Constant): Lte; + +// @beta +export function lte(left: Constant, right: any): Lte; + +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Constant" which is marked as @beta +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Lte" which is marked as @beta +// +// @public +export function lte(left: string, right: Constant): Lte; + +// @beta +export function lte(left: string, right: any): Lte; + +// @beta (undocumented) +export class MapGet extends FirestoreFunction { + constructor(map: Constant, name: string); +} + +// @beta +export function mapGet(mapField: string, subField: string): MapGet; + +// @beta +export function mapGet(mapExpr: Constant, subField: string): MapGet; + +// @beta (undocumented) +export class Maximum extends FirestoreFunction implements Accumulator { + constructor(value: Constant, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function maximum(value: Constant): Maximum; + +// @beta +export function maximum(value: string): Maximum; + +// @beta (undocumented) +export class Minimum extends FirestoreFunction implements Accumulator { + constructor(value: Constant, distinct: boolean); + // (undocumented) + accumulator: true; + } + +// @beta +export function minimum(value: Constant): Minimum; + +// @beta +export function minimum(value: string): Minimum; -// @public -export class GeoPoint { - constructor(latitude: number, longitude: number); - isEqual(other: GeoPoint): boolean; - get latitude(): number; - get longitude(): number; - toJSON(): { - latitude: number; - longitude: number; - }; -} +// @beta (undocumented) +export class Mod extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } -// @public -export function getAggregate(query: Query, aggregateSpec: AggregateSpecType): Promise>; +// @beta +export function mod(left: Constant, right: Constant): Mod; -// @public -export function getCount(query: Query): Promise; -}, AppModelType, DbModelType>>; +// @beta +export function mod(left: Constant, right: any): Mod; -// @public -export function getDoc(reference: DocumentReference): Promise>; +// @beta +export function mod(left: string, right: Constant): Mod; -// @public -export function getDocs(query: Query): Promise>; +// @beta +export function mod(left: string, right: any): Mod; -// @public -export function getFirestore(): Firestore; +// @beta (undocumented) +export class Multiply extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } -// @public -export function getFirestore(app: FirebaseApp): Firestore; +// @beta +export function multiply(left: Constant, right: Constant): Multiply; // @beta -export function getFirestore(databaseId: string): Firestore; +export function multiply(left: Constant, right: any): Multiply; // @beta -export function getFirestore(app: FirebaseApp, databaseId: string): Firestore; +export function multiply(left: string, right: Constant): Multiply; -// @public -export function increment(n: number): FieldValue; +// @beta +export function multiply(left: string, right: any): Multiply; -// @public -export function initializeFirestore(app: FirebaseApp, settings: Settings): Firestore; +// @beta (undocumented) +export class Neq extends FirestoreFunction implements FilterCondition { + constructor(left: Constant, right: Constant); + // (undocumented) + filterable: true; + } // @beta -export function initializeFirestore(app: FirebaseApp, settings: Settings, databaseId?: string): Firestore; +export function neq(left: Constant, right: Constant): Neq; -// @public -export function limit(limit: number): QueryLimitConstraint; +// @beta +export function neq(left: Constant, right: any): Neq; -// @public -export function limitToLast(limit: number): QueryLimitConstraint; +// @beta +export function neq(left: string, right: Constant): Neq; -export { LogLevel } +// @beta +export function neq(left: string, right: any): Neq; // @public export type NestedUpdateFields> = UnionToIntersection<{ [K in keyof T & string]: ChildUpdateFields; }[keyof T & string]>; +// @beta (undocumented) +export class Not extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant); + // (undocumented) + filterable: true; +} + +// @beta +export function not(filter: FilterExpr): Not; + +// @beta +export function notEqAny(element: Constant, others: Constant[]): FirestoreFunction; + +// @beta +export function notEqAny(element: Constant, others: any[]): FirestoreFunction; + +// @beta +export function notEqAny(element: string, others: Constant[]): FirestoreFunction; + +// @beta +export function notEqAny(element: string, others: any[]): FirestoreFunction; + +// @beta (undocumented) +export class Offset implements Stage { + constructor(offset: number); + // (undocumented) + name: string; + } + +// @beta (undocumented) +export class Or extends FirestoreFunction implements FilterCondition { + constructor(conditions: FilterExpr[]); + // (undocumented) + filterable: true; +} + // @public export function or(...queryConstraints: QueryFilterConstraint[]): QueryCompositeFilterConstraint; @@ -271,11 +1542,114 @@ export function orderBy(fieldPath: string | FieldPath, directionStr?: OrderByDir // @public export type OrderByDirection = 'desc' | 'asc'; +// @beta +export class Ordering { + constructor(expr: Constant, direction: 'ascending' | 'descending'); + } + // @public export type PartialWithFieldValue = Partial | (T extends Primitive ? T : T extends {} ? { [K in keyof T]?: PartialWithFieldValue | FieldValue; } : never); +// @public +export class Pipeline { + /* Excluded from this release type: _db */ + // Warning: (ae-incompatible-release-tags) The symbol "addFields" is marked as @public, but its signature references "Selectable" which is marked as @beta + addFields(...fields: Selectable[]): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta + aggregate(...accumulators: AccumulatorTarget[]): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + aggregate(options: { + accumulators: AccumulatorTarget[]; + groups?: Array; + }): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta + distinct(...groups: Array): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta + execute(): Promise>>; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "findNearest" is marked as @public, but its signature references "FindNearestOptions" which is marked as @beta + // + // (undocumented) + findNearest(options: FindNearestOptions): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + genericStage(name: string, params: any[]): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + limit(limit: number): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + offset(offset: number): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "select" is marked as @public, but its signature references "Selectable" which is marked as @beta + select(...selections: Array): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "sort" is marked as @public, but its signature references "Ordering" which is marked as @beta + sort(...orderings: Ordering[]): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // (undocumented) + sort(options: { + orderings: Ordering[]; + }): Pipeline; + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "FilterCondition" which is marked as @beta + // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "Constant" which is marked as @beta + where(condition: FilterCondition & Constant): Pipeline; +} + +// Warning: (ae-incompatible-release-tags) The symbol "pipeline" is marked as @public, but its signature references "PipelineSource" which is marked as @beta +// +// @public +export function pipeline(firestore: Firestore): PipelineSource; + +// @public +export function pipeline(query: Query): Pipeline; + +// @beta +export class PipelineResult { + /* Excluded from this release type: _ref */ + /* Excluded from this release type: _fields */ + /* Excluded from this release type: __constructor */ + get createTime(): Timestamp | undefined; + data(): AppModelType | undefined; + get executionTime(): Timestamp; + get(fieldPath: string | FieldPath): any; + get id(): string | undefined; + get ref(): DocumentReference | undefined; + get updateTime(): Timestamp | undefined; +} + +// @beta +export class PipelineSource { + /* Excluded from this release type: _db */ + /* Excluded from this release type: _userDataReader */ + /* Excluded from this release type: _userDataWriter */ + /* Excluded from this release type: _documentReferenceFactory */ + /* Excluded from this release type: __constructor */ + // (undocumented) + collection(collectionPath: string): Pipeline; + // (undocumented) + collectionGroup(collectionId: string): Pipeline; + // (undocumented) + database(): Pipeline; + // (undocumented) + documents(docs: DocumentReference[]): Pipeline; +} + // @public export type Primitive = string | number | boolean | undefined | null; @@ -360,9 +1734,102 @@ export class QueryStartAtConstraint extends QueryConstraint { // @public export function refEqual(left: DocumentReference | CollectionReference, right: DocumentReference | CollectionReference): boolean; +// @beta (undocumented) +export class RegexContains extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, pattern: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function regexContains(left: string, pattern: string): RegexContains; + +// @beta +export function regexContains(left: string, pattern: Constant): RegexContains; + +// @beta +export function regexContains(left: Constant, pattern: string): RegexContains; + +// @beta +export function regexContains(left: Constant, pattern: Constant): RegexContains; + +// @beta (undocumented) +export class RegexMatch extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, pattern: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function regexMatch(left: string, pattern: string): RegexMatch; + +// @beta +export function regexMatch(left: string, pattern: Constant): RegexMatch; + +// @beta +export function regexMatch(left: Constant, pattern: string): RegexMatch; + +// @beta +export function regexMatch(left: Constant, pattern: Constant): RegexMatch; + +// @beta (undocumented) +export class ReplaceAll extends FirestoreFunction { + constructor(value: Constant, find: Constant, replace: Constant); + } + +// @beta +export function replaceAll(value: Constant, find: string, replace: string): ReplaceAll; + +// @beta +export function replaceAll(value: Constant, find: Constant, replace: Constant): ReplaceAll; + +// @beta +export function replaceAll(field: string, find: string, replace: string): ReplaceAll; + +// @beta (undocumented) +export class ReplaceFirst extends FirestoreFunction { + constructor(value: Constant, find: Constant, replace: Constant); + } + +// @beta +export function replaceFirst(value: Constant, find: string, replace: string): ReplaceFirst; + +// @beta +export function replaceFirst(value: Constant, find: Constant, replace: Constant): ReplaceFirst; + +// @beta +export function replaceFirst(field: string, find: string, replace: string): ReplaceFirst; + +// @beta (undocumented) +export class Reverse extends FirestoreFunction { + constructor(value: Constant); + } + +// @beta +export function reverse(expr: Constant): Reverse; + +// @beta +export function reverse(field: string): Reverse; + // @public export function runTransaction(firestore: Firestore, updateFunction: (transaction: Transaction) => Promise, options?: TransactionOptions): Promise; +// @beta (undocumented) +export class Select implements Stage { + constructor(projections: Map); + // (undocumented) + name: string; + } + +// @beta +export interface Selectable { + // (undocumented) + selectable: true; +} + +// @beta +export type SelectableExpr = Constant & Selectable; + // @public export function serverTimestamp(): FieldValue; @@ -392,6 +1859,19 @@ export interface Settings { // @public export function snapshotEqual(left: DocumentSnapshot | QuerySnapshot, right: DocumentSnapshot | QuerySnapshot): boolean; +// @beta (undocumented) +export class Sort implements Stage { + constructor(orders: Ordering[]); + // (undocumented) + name: string; + } + +// @beta (undocumented) +export interface Stage { + // (undocumented) + name: string; +} + // @public export function startAfter(snapshot: DocumentSnapshot): QueryStartAtConstraint; @@ -404,6 +1884,79 @@ export function startAt(snapshot // @public export function startAt(...fieldValues: unknown[]): QueryStartAtConstraint; +// @beta (undocumented) +export class StartsWith extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, prefix: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function startsWith(expr: string, prefix: string): StartsWith; + +// @beta +export function startsWith(expr: string, prefix: Constant): StartsWith; + +// @beta +export function startsWith(expr: Constant, prefix: string): StartsWith; + +// @beta +export function startsWith(expr: Constant, prefix: Constant): StartsWith; + +// @beta (undocumented) +export class StrConcat extends FirestoreFunction { + constructor(first: Constant, rest: Constant[]); + } + +// @beta +export function strConcat(first: string, ...elements: Array): StrConcat; + +// @beta +export function strConcat(first: Constant, ...elements: Array): StrConcat; + +// @beta (undocumented) +export class StrContains extends FirestoreFunction implements FilterCondition { + constructor(expr: Constant, substring: Constant); + // (undocumented) + filterable: true; + } + +// @beta +export function strContains(left: string, substring: string): StrContains; + +// @beta +export function strContains(left: string, substring: Constant): StrContains; + +// @beta +export function strContains(left: Constant, substring: string): StrContains; + +// @beta +export function strContains(left: Constant, substring: Constant): StrContains; + +// @beta (undocumented) +export class Subtract extends FirestoreFunction { + constructor(left: Constant, right: Constant); + } + +// @beta +export function subtract(left: Constant, right: Constant): Subtract; + +// @beta +export function subtract(left: Constant, right: any): Subtract; + +// @beta +export function subtract(left: string, right: Constant): Subtract; + +// @beta +export function subtract(left: string, right: any): Subtract; + +// @beta (undocumented) +export class Sum extends FirestoreFunction implements Accumulator { + constructor(value: Constant, distinct: boolean); + // (undocumented) + accumulator: true; + } + // @public export function sum(field: string | FieldPath): AggregateField; @@ -431,6 +1984,89 @@ export class Timestamp { valueOf(): string; } +// @beta (undocumented) +export class TimestampAdd extends FirestoreFunction { + constructor(timestamp: Constant, unit: Constant, amount: Constant); + } + +// @beta +export function timestampAdd(timestamp: Constant, unit: Constant, amount: Constant): TimestampAdd; + +// @beta +export function timestampAdd(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + +// @beta +export function timestampAdd(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; + +// @beta (undocumented) +export class TimestampSub extends FirestoreFunction { + constructor(timestamp: Constant, unit: Constant, amount: Constant); + } + +// @beta +export function timestampSub(timestamp: Constant, unit: Constant, amount: Constant): TimestampSub; + +// @beta +export function timestampSub(timestamp: Constant, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + +// @beta +export function timestampSub(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; + +// @beta (undocumented) +export class TimestampToUnixMicros extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function timestampToUnixMicros(expr: Constant): TimestampToUnixMicros; + +// @beta +export function timestampToUnixMicros(field: string): TimestampToUnixMicros; + +// @beta (undocumented) +export class TimestampToUnixMillis extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function timestampToUnixMillis(expr: Constant): TimestampToUnixMillis; + +// @beta +export function timestampToUnixMillis(field: string): TimestampToUnixMillis; + +// @beta (undocumented) +export class TimestampToUnixSeconds extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function timestampToUnixSeconds(expr: Constant): TimestampToUnixSeconds; + +// @beta +export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; + +// @beta (undocumented) +export class ToLower extends FirestoreFunction { + constructor(expr: Constant); + } + +// @beta +export function toLower(expr: string): ToLower; + +// @beta +export function toLower(expr: Constant): ToLower; + +// @beta (undocumented) +export class ToUpper extends FirestoreFunction { + constructor(expr: Constant); + } + +// @beta +export function toUpper(expr: string): ToUpper; + +// @beta +export function toUpper(expr: Constant): ToUpper; + // @public export class Transaction { delete(documentRef: DocumentReference): this; @@ -446,9 +2082,53 @@ export interface TransactionOptions { readonly maxAttempts?: number; } +// @beta (undocumented) +export class Trim extends FirestoreFunction { + constructor(expr: Constant); + } + +// @beta +export function trim(expr: string): Trim; + +// @beta +export function trim(expr: Constant): Trim; + // @public export type UnionToIntersection = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never; +// @beta (undocumented) +export class UnixMicrosToTimestamp extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function unixMicrosToTimestamp(expr: Constant): UnixMicrosToTimestamp; + +// @beta +export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; + +// @beta (undocumented) +export class UnixMillisToTimestamp extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function unixMillisToTimestamp(expr: Constant): UnixMillisToTimestamp; + +// @beta +export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; + +// @beta (undocumented) +export class UnixSecondsToTimestamp extends FirestoreFunction { + constructor(input: Constant); + } + +// @beta +export function unixSecondsToTimestamp(expr: Constant): UnixSecondsToTimestamp; + +// @beta +export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; + // @public export type UpdateData = T extends Primitive ? T : T extends {} ? { [K in keyof T]?: UpdateData | FieldValue; @@ -460,9 +2140,23 @@ export function updateDoc(refere // @public export function updateDoc(reference: DocumentReference, field: string | FieldPath, value: unknown, ...moreFieldsAndValues: unknown[]): Promise; +// @public (undocumented) +export function useFluentPipelines(): void; + // @public export function vector(values?: number[]): VectorValue; +// @beta (undocumented) +export class VectorLength extends FirestoreFunction { + constructor(value: Constant); + } + +// @beta +export function vectorLength(expr: Constant): VectorLength; + +// @beta +export function vectorLength(field: string): VectorLength; + // @public export class VectorValue { /* Excluded from this release type: __constructor */ @@ -470,6 +2164,13 @@ export class VectorValue { toArray(): number[]; } +// @beta (undocumented) +export class Where implements Stage { + constructor(condition: FilterCondition & Constant); + // (undocumented) + name: string; +} + // @public export function where(fieldPath: string | FieldPath, opStr: WhereFilterOp, value: unknown): QueryFieldFilterConstraint; @@ -494,5 +2195,21 @@ export class WriteBatch { // @public export function writeBatch(firestore: Firestore): WriteBatch; +// @beta (undocumented) +export class Xor extends FirestoreFunction implements FilterCondition { + constructor(conditions: FilterExpr[]); + // (undocumented) + filterable: true; +} + +// @beta +export function xor(left: FilterExpr, ...right: FilterExpr[]): Xor; + + +// Warnings were encountered during analysis: +// +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/index.d.ts:9239:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/index.d.ts:9240:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/index.d.ts:9269:9 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta ``` diff --git a/common/api-review/firestore-pipelines.api.md b/common/api-review/firestore-pipelines.api.md index 11bb7780e3a..375f5dfd976 100644 --- a/common/api-review/firestore-pipelines.api.md +++ b/common/api-review/firestore-pipelines.api.md @@ -48,13 +48,13 @@ export class Aggregate implements Stage { // @beta (undocumented) export class And extends FirestoreFunction implements FilterCondition { - constructor(conditions: (FilterCondition)[]); + constructor(conditions: FilterCondition[]); // (undocumented) filterable: true; } // @beta -export function andFunction(left: FilterCondition, ...right: (FilterCondition)[]): And; +export function andFunction(left: FilterCondition, ...right: FilterCondition[]): And; // @beta (undocumented) export class ArrayConcat extends FirestoreFunction { @@ -699,7 +699,11 @@ export function like(left: Expr, pattern: Expr): Like; // @beta (undocumented) export class Limit implements Stage { - constructor(limit: number); + constructor(limit: number, convertedFromLimitTolast?: boolean); + // (undocumented) + readonly convertedFromLimitTolast: boolean; + // (undocumented) + readonly limit: number; // (undocumented) name: string; } @@ -907,7 +911,7 @@ export class Offset implements Stage { // @beta (undocumented) export class Or extends FirestoreFunction implements FilterCondition { - constructor(conditions: (FilterCondition)[]); + constructor(conditions: FilterCondition[]); // (undocumented) filterable: true; } @@ -922,7 +926,7 @@ export class Ordering { } // @beta -export function orFunction(left: FilterCondition, ...right: (FilterCondition)[]): Or; +export function orFunction(left: FilterCondition, ...right: FilterCondition[]): Or; // @public (undocumented) export class Pipeline { @@ -933,7 +937,7 @@ export class Pipeline { aggregate(...accumulators: AccumulatorTarget[]): Pipeline; aggregate(options: { accumulators: AccumulatorTarget[]; groups?: Array; }): Pipeline; // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta - distinct(...groups: Array): Pipeline; + distinct(...groups: Array): Pipeline; // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta execute(): Promise; // Warning: (ae-incompatible-release-tags) The symbol "findNearest" is marked as @public, but its signature references "FindNearestOptions" which is marked as @beta @@ -1330,19 +1334,21 @@ export class Where implements Stage { // @beta (undocumented) export class Xor extends FirestoreFunction implements FilterCondition { - constructor(conditions: (FilterCondition)[]); + constructor(conditions: FilterCondition[]); // (undocumented) filterable: true; } // @beta -export function xor(left: FilterCondition, ...right: (FilterCondition)[]): Xor; +export function xor(left: FilterCondition, ...right: FilterCondition[]): Xor; // Warnings were encountered during analysis: // -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:3982:26 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:3982:61 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:4009:21 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:3983:26 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:3983:61 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:4010:21 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta + +// (No @packageDocumentation comment for this package) ``` diff --git a/packages/firestore/src/api/pipeline_impl.ts b/packages/firestore/src/api/pipeline_impl.ts index a8cdf38cf0d..9e7c25e69ab 100644 --- a/packages/firestore/src/api/pipeline_impl.ts +++ b/packages/firestore/src/api/pipeline_impl.ts @@ -16,6 +16,7 @@ */ import { Pipeline } from '../api/pipeline'; +import { toPipeline } from '../core/pipeline-util'; import { Pipeline as LitePipeline } from '../lite-api/pipeline'; import { PipelineResult } from '../lite-api/pipeline-result'; import { PipelineSource } from '../lite-api/pipeline-source'; @@ -27,6 +28,12 @@ import { Firestore } from './database'; import { Query } from './reference'; import { ExpUserDataWriter } from './user_data_writer'; +declare module './database' { + interface Firestore { + pipeline(): PipelineSource; + } +} + /** * Experimental Modular API for console testing. * @param firestore @@ -53,19 +60,11 @@ export function pipeline( ); }); } else { - let result; const query = firestoreOrQuery; const db = cast(query.firestore, Firestore); - if (query._query.collectionGroup) { - result = pipeline(db).collectionGroup(query._query.collectionGroup); - } else { - result = pipeline(db).collection(query._query.path.canonicalString()); - } - - // TODO(pipeline) convert existing query filters, limits, etc into - // pipeline stages - return result; + const litePipeline: LitePipeline = toPipeline(query._query, db); + return cast(litePipeline, Pipeline); } } diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index 0c0c34ecc67..7f1e0dfde64 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -15,14 +15,26 @@ * limitations under the License. */ +import { Firestore } from '../api/database'; import { Constant, Field, FilterCondition, not, andFunction, - orFunction + orFunction, + Ordering, + And, + lt, + gt, + lte, + gte, + Expr, + eq, + Or } from '../lite-api/expressions'; +import { Pipeline } from '../lite-api/pipeline'; +import { doc } from '../lite-api/reference'; import { isNanValue, isNullValue } from '../model/values'; import { ArrayValue as ProtoArrayValue, @@ -36,6 +48,7 @@ import { import { fail } from '../util/assert'; import { isPlainObject } from '../util/input_validation'; +import { Bound } from './bound'; import { CompositeFilter as CompositeFilterInternal, CompositeOperator, @@ -43,6 +56,14 @@ import { Filter as FilterInternal, Operator } from './filter'; +import { Direction } from './order_by'; +import { + isCollectionGroupQuery, + isDocumentQuery, + LimitType, + Query, + queryNormalizedOrderBy +} from './query'; /* eslint @typescript-eslint/no-explicit-any: 0 */ @@ -247,3 +268,122 @@ export function toPipelineFilterCondition(f: FilterInternal): FilterCondition { throw new Error(`Failed to convert filter to pipeline conditions: ${f}`); } + +function reverseOrderings(orderings: Ordering[]): Ordering[] { + return orderings.map( + o => + new Ordering( + o.expr, + o.direction === 'ascending' ? 'descending' : 'ascending' + ) + ); +} + +export function toPipeline(query: Query, db: Firestore): Pipeline { + let pipeline: Pipeline; + if (isCollectionGroupQuery(query)) { + pipeline = db.pipeline().collectionGroup(query.collectionGroup!); + } else if (isDocumentQuery(query)) { + pipeline = db.pipeline().documents([doc(db, query.path.canonicalString())]); + } else { + pipeline = db.pipeline().collection(query.path.canonicalString()); + } + + // filters + for (const filter of query.filters) { + pipeline = pipeline.where(toPipelineFilterCondition(filter)); + } + + // orders + const orders = queryNormalizedOrderBy(query); + const existsConditions = orders.map(order => + Field.of(order.field.canonicalString()).exists() + ); + if (existsConditions.length > 1) { + pipeline = pipeline.where( + andFunction(existsConditions[0], ...existsConditions.slice(1)) + ); + } else { + pipeline = pipeline.where(existsConditions[0]); + } + + const orderings = orders.map(order => + order.dir === Direction.ASCENDING + ? Field.of(order.field.canonicalString()).ascending() + : Field.of(order.field.canonicalString()).descending() + ); + + if (query.limitType === LimitType.Last) { + pipeline = pipeline.sort(...reverseOrderings(orderings)); + // cursors + if (query.startAt !== null) { + pipeline = pipeline.where( + whereConditionsFromCursor(query.startAt, orderings, 'before') + ); + } + + if (query.endAt !== null) { + pipeline = pipeline.where( + whereConditionsFromCursor(query.endAt, orderings, 'after') + ); + } + + pipeline = pipeline._limit(query.limit!, true); + pipeline = pipeline.sort(...orderings); + } else { + pipeline = pipeline.sort(...orderings); + if (query.startAt !== null) { + pipeline = pipeline.where( + whereConditionsFromCursor(query.startAt, orderings, 'after') + ); + } + if (query.endAt !== null) { + pipeline = pipeline.where( + whereConditionsFromCursor(query.endAt, orderings, 'before') + ); + } + + if (query.limit !== null) { + pipeline = pipeline.limit(query.limit); + } + } + + return pipeline; +} + +function whereConditionsFromCursor( + bound: Bound, + orderings: Ordering[], + position: 'before' | 'after' +): Expr { + const cursors = bound.position.map(value => Constant._fromProto(value)); + const filterFunc = position === 'before' ? lt : gt; + const filterInclusiveFunc = position === 'before' ? lte : gte; + + const orConditions = []; + for (let i = 1; i <= orderings.length; i++) { + const cursorSubset = cursors.slice(0, i); + + const conditions = cursorSubset.map((cursor, index) => { + if (index < cursorSubset.length - 1) { + return eq(orderings[index].expr as Field, cursor); + } else if (!!bound.inclusive && i === orderings.length) { + return filterInclusiveFunc(orderings[index].expr as Field, cursor); + } else { + return filterFunc(orderings[index].expr as Field, cursor); + } + }); + + if (conditions.length === 1) { + orConditions.push(conditions[0]); + } else { + orConditions.push(new And(conditions)); + } + } + + if (orConditions.length === 1) { + return orConditions[0]; + } else { + return new Or(orConditions); + } +} diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 65434c2f287..4caee458bb3 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -17,6 +17,7 @@ /* eslint @typescript-eslint/no-explicit-any: 0 */ +import { isFirestoreValue } from '../core/pipeline-util'; import { DOCUMENT_KEY_NAME, FieldPath as InternalFieldPath @@ -2174,6 +2175,16 @@ export class Constant extends Expr { } } + /** + * @private + * @internal + */ + static _fromProto(value: ProtoValue): Constant { + const result = new Constant(value); + result._protoValue = value; + return result; + } + /** * @private * @internal @@ -2195,8 +2206,13 @@ export class Constant extends Expr { UserDataSource.Argument, 'Constant.of' ); - if (this.value === undefined) { - // TODO how should we treat the value of `undefined`? + + if (isFirestoreValue(this.value)) { + // Special case where value is a proto value. + // This can occur when converting a Query to Pipeline. + this._protoValue = this.value; + } else if (this.value === undefined) { + // TODO(pipeline) how should we treat the value of `undefined`? this._protoValue = parseData(null, context)!; } else { this._protoValue = parseData(this.value, context)!; diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index b6cfcb0aa99..2e4a2f03dc3 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -405,6 +405,17 @@ export class Pipeline implements ProtoSerializable { ); } + _limit(limit: number, convertedFromLimitTolast: boolean): Pipeline { + const copy = this.stages.map(s => s); + copy.push(new Limit(limit, convertedFromLimitTolast)); + return this.newPipeline( + this._db, + this.userDataReader, + this._userDataWriter, + copy + ); + } + /** * Returns a set of distinct {@link Expr} values from the inputs to this stage. * diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index 4d43abdb486..46f8fe60654 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -27,6 +27,7 @@ import { toMapValue, toStringValue } from '../remote/serializer'; +import { hardAssert } from '../util/assert'; import { Accumulator, @@ -289,7 +290,15 @@ export class FindNearest implements Stage { export class Limit implements Stage { name = 'limit'; - constructor(private limit: number) {} + constructor( + readonly limit: number, + readonly convertedFromLimitTolast: boolean = false + ) { + hardAssert( + !isNaN(limit) && limit !== Infinity && limit !== -Infinity, + 'Invalid limit value' + ); + } /** * @internal diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 07da8990d94..362a9c2ac80 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -60,894 +60,1556 @@ import { eqAny, logicalMaximum, logicalMinimum, - notEqAny + notEqAny, + query, + where, + FieldPath, + orderBy, + limit, + limitToLast, + startAt, + startAfter, + endAt, + endBefore, + collectionGroup, + collection, + and, + documentId, + addDoc, + getDoc } from '../util/firebase_export'; -import { apiDescribe, withTestCollection } from '../util/helpers'; +import { + apiDescribe, + PERSISTENCE_MODE_UNSPECIFIED, + withTestCollection +} from '../util/helpers'; use(chaiAsPromised); setLogLevel('debug'); -apiDescribe('Pipelines', persistence => { +apiDescribe.only('Pipelines', persistence => { addEqualityMatcher(); - let firestore: Firestore; - let randomCol: CollectionReference; - - // async function addDocs( - // ...docs: DocumentData[] - // ): Promise { - // let id = 0; // Guarantees consistent ordering for the first documents - // const refs: DocumentReference[] = []; - // for (const data of docs) { - // const ref = doc(randomCol, 'doc' + id++); - // await setDoc(ref, data); - // refs.push(ref); - // } - // return refs; - // } - - async function testCollectionWithDocs(docs: { - [id: string]: DocumentData; - }): Promise> { - for (const id in docs) { - if (docs.hasOwnProperty(id)) { - const ref = doc(randomCol, id); - await setDoc(ref, docs[id]); + + describe('books tests', () => { + let firestore: Firestore; + let randomCol: CollectionReference; + + async function testCollectionWithDocs(docs: { + [id: string]: DocumentData; + }): Promise> { + for (const id in docs) { + if (docs.hasOwnProperty(id)) { + const ref = doc(randomCol, id); + await setDoc(ref, docs[id]); + } } + return randomCol; } - return randomCol; - } - - function expectResults( - result: Array>, - ...docs: string[] - ): void; - function expectResults( - result: Array>, - ...data: DocumentData[] - ): void; - - function expectResults( - result: Array>, - ...data: DocumentData[] | string[] - ): void { - expect(result.length).to.equal(data.length); - - if (data.length > 0) { - if (typeof data[0] === 'string') { - const actualIds = result.map(result => result.ref?.id); - expect(actualIds).to.deep.equal(data); - } else { - result.forEach(r => { - expect(r.data()).to.deep.equal(data.shift()); - }); + + function expectResults( + result: Array>, + ...docs: string[] + ): void; + function expectResults( + result: Array>, + ...data: DocumentData[] + ): void; + + function expectResults( + result: Array>, + ...data: DocumentData[] | string[] + ): void { + expect(result.length).to.equal(data.length); + + if (data.length > 0) { + if (typeof data[0] === 'string') { + const actualIds = result.map(result => result.ref?.id); + expect(actualIds).to.deep.equal(data); + } else { + result.forEach(r => { + expect(r.data()).to.deep.equal(data.shift()); + }); + } } } - } - - // async function compareQueryAndPipeline(query: Query): Promise { - // const queryResults = await getDocs(query); - // const pipeline = query.pipeline(); - // const pipelineResults = await pipeline.execute(); - // - // expect(queryResults.docs.map(s => s._fieldsProto)).to.deep.equal( - // pipelineResults.map(r => r._fieldsProto) - // ); - // return queryResults; - // } - - async function setupBookDocs(): Promise> { - const bookDocs: { [id: string]: DocumentData } = { - book1: { - title: "The Hitchhiker's Guide to the Galaxy", - author: 'Douglas Adams', - genre: 'Science Fiction', - published: 1979, - rating: 4.2, - tags: ['comedy', 'space', 'adventure'], - awards: { - hugo: true, - nebula: false, - others: { unknown: { year: 1980 } } - }, - nestedField: { 'level.1': { 'level.2': true } } - }, - book2: { - title: 'Pride and Prejudice', - author: 'Jane Austen', - genre: 'Romance', - published: 1813, - rating: 4.5, - tags: ['classic', 'social commentary', 'love'], - awards: { none: true } - }, - book3: { - title: 'One Hundred Years of Solitude', - author: 'Gabriel García Márquez', - genre: 'Magical Realism', - published: 1967, - rating: 4.3, - tags: ['family', 'history', 'fantasy'], - awards: { nobel: true, nebula: false } - }, - book4: { - title: 'The Lord of the Rings', - author: 'J.R.R. Tolkien', - genre: 'Fantasy', - published: 1954, - rating: 4.7, - tags: ['adventure', 'magic', 'epic'], - awards: { hugo: false, nebula: false } - }, - book5: { - title: "The Handmaid's Tale", - author: 'Margaret Atwood', - genre: 'Dystopian', - published: 1985, - rating: 4.1, - tags: ['feminism', 'totalitarianism', 'resistance'], - awards: { 'arthur c. clarke': true, 'booker prize': false } - }, - book6: { - title: 'Crime and Punishment', - author: 'Fyodor Dostoevsky', - genre: 'Psychological Thriller', - published: 1866, - rating: 4.3, - tags: ['philosophy', 'crime', 'redemption'], - awards: { none: true } - }, - book7: { - title: 'To Kill a Mockingbird', - author: 'Harper Lee', - genre: 'Southern Gothic', - published: 1960, - rating: 4.2, - tags: ['racism', 'injustice', 'coming-of-age'], - awards: { pulitzer: true } - }, - book8: { - title: '1984', - author: 'George Orwell', - genre: 'Dystopian', - published: 1949, - rating: 4.2, - tags: ['surveillance', 'totalitarianism', 'propaganda'], - awards: { prometheus: true } - }, - book9: { - title: 'The Great Gatsby', - author: 'F. Scott Fitzgerald', - genre: 'Modernist', - published: 1925, - rating: 4.0, - tags: ['wealth', 'american dream', 'love'], - awards: { none: true } - }, - book10: { - title: 'Dune', - author: 'Frank Herbert', - genre: 'Science Fiction', - published: 1965, - rating: 4.6, - tags: ['politics', 'desert', 'ecology'], - awards: { hugo: true, nebula: true } - } - }; - return testCollectionWithDocs(bookDocs); - } - - let testDeferred: Deferred | undefined; - let withTestCollectionPromise: Promise | undefined; - - beforeEach(async () => { - const setupDeferred = new Deferred(); - testDeferred = new Deferred(); - withTestCollectionPromise = withTestCollection( - persistence, - {}, - async (collectionRef, firestoreInstance) => { - randomCol = collectionRef; - firestore = firestoreInstance; - await setupBookDocs(); - setupDeferred.resolve(); - - return testDeferred?.promise; - } - ); - await setupDeferred.promise; - }); + async function setupBookDocs(): Promise> { + const bookDocs: { [id: string]: DocumentData } = { + book1: { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + }, + book2: { + title: 'Pride and Prejudice', + author: 'Jane Austen', + genre: 'Romance', + published: 1813, + rating: 4.5, + tags: ['classic', 'social commentary', 'love'], + awards: { none: true } + }, + book3: { + title: 'One Hundred Years of Solitude', + author: 'Gabriel García Márquez', + genre: 'Magical Realism', + published: 1967, + rating: 4.3, + tags: ['family', 'history', 'fantasy'], + awards: { nobel: true, nebula: false } + }, + book4: { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + genre: 'Fantasy', + published: 1954, + rating: 4.7, + tags: ['adventure', 'magic', 'epic'], + awards: { hugo: false, nebula: false } + }, + book5: { + title: "The Handmaid's Tale", + author: 'Margaret Atwood', + genre: 'Dystopian', + published: 1985, + rating: 4.1, + tags: ['feminism', 'totalitarianism', 'resistance'], + awards: { 'arthur c. clarke': true, 'booker prize': false } + }, + book6: { + title: 'Crime and Punishment', + author: 'Fyodor Dostoevsky', + genre: 'Psychological Thriller', + published: 1866, + rating: 4.3, + tags: ['philosophy', 'crime', 'redemption'], + awards: { none: true } + }, + book7: { + title: 'To Kill a Mockingbird', + author: 'Harper Lee', + genre: 'Southern Gothic', + published: 1960, + rating: 4.2, + tags: ['racism', 'injustice', 'coming-of-age'], + awards: { pulitzer: true } + }, + book8: { + title: '1984', + author: 'George Orwell', + genre: 'Dystopian', + published: 1949, + rating: 4.2, + tags: ['surveillance', 'totalitarianism', 'propaganda'], + awards: { prometheus: true } + }, + book9: { + title: 'The Great Gatsby', + author: 'F. Scott Fitzgerald', + genre: 'Modernist', + published: 1925, + rating: 4.0, + tags: ['wealth', 'american dream', 'love'], + awards: { none: true } + }, + book10: { + title: 'Dune', + author: 'Frank Herbert', + genre: 'Science Fiction', + published: 1965, + rating: 4.6, + tags: ['politics', 'desert', 'ecology'], + awards: { hugo: true, nebula: true } + } + }; + return testCollectionWithDocs(bookDocs); + } - afterEach(async () => { - testDeferred?.resolve(); - await withTestCollectionPromise; - }); + let testDeferred: Deferred | undefined; + let withTestCollectionPromise: Promise | undefined; + + beforeEach(async () => { + const setupDeferred = new Deferred(); + testDeferred = new Deferred(); + withTestCollectionPromise = withTestCollection( + persistence, + {}, + async (collectionRef, firestoreInstance) => { + randomCol = collectionRef; + firestore = firestoreInstance; + await setupBookDocs(); + setupDeferred.resolve(); + + return testDeferred?.promise; + } + ); - describe('fluent API', () => { - it('empty results as expected', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .limit(0) - .execute(); - expect(result.length).to.equal(0); + await setupDeferred.promise; }); - it('full results as expected', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .execute(); - expect(result.length).to.equal(10); + afterEach(async () => { + testDeferred?.resolve(); + await withTestCollectionPromise; }); - it('returns aggregate results as expected', async () => { - let result = await firestore - .pipeline() - .collection(randomCol.path) - .aggregate(countAll().as('count')) - .execute(); - expectResults(result, { count: 10 }); - - result = await randomCol - .pipeline() - .where(eq('genre', 'Science Fiction')) - .aggregate( - countAll().as('count'), - avgFunction('rating').as('avgRating'), - Field.of('rating').maximum().as('maxRating') - ) - .execute(); - expectResults(result, { count: 2, avgRating: 4.4, maxRating: 4.6 }); - }); + describe('fluent API', () => { + it('empty results as expected', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .limit(0) + .execute(); + expect(result.length).to.equal(0); + }); + + it('full results as expected', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .execute(); + expect(result.length).to.equal(10); + }); + + it('returns aggregate results as expected', async () => { + let result = await firestore + .pipeline() + .collection(randomCol.path) + .aggregate(countAll().as('count')) + .execute(); + expectResults(result, { count: 10 }); - it('rejects groups without accumulators', async () => { - await expect( - randomCol + result = await randomCol .pipeline() - .where(lt('published', 1900)) + .where(eq('genre', 'Science Fiction')) + .aggregate( + countAll().as('count'), + avgFunction('rating').as('avgRating'), + Field.of('rating').maximum().as('maxRating') + ) + .execute(); + expectResults(result, { count: 2, avgRating: 4.4, maxRating: 4.6 }); + }); + + it('rejects groups without accumulators', async () => { + await expect( + randomCol + .pipeline() + .where(lt('published', 1900)) + .aggregate({ + accumulators: [], + groups: ['genre'] + }) + .execute() + ).to.be.rejected; + }); + + it('returns distinct values as expected', async () => { + const results = await randomCol + .pipeline() + .distinct('genre', 'author') + .sort(Field.of('genre').ascending(), Field.of('author').ascending()) + .execute(); + expectResults( + results, + { genre: 'Dystopian', author: 'George Orwell' }, + { genre: 'Dystopian', author: 'Margaret Atwood' }, + { genre: 'Fantasy', author: 'J.R.R. Tolkien' }, + { genre: 'Magical Realism', author: 'Gabriel García Márquez' }, + { genre: 'Modernist', author: 'F. Scott Fitzgerald' }, + { genre: 'Psychological Thriller', author: 'Fyodor Dostoevsky' }, + { genre: 'Romance', author: 'Jane Austen' }, + { genre: 'Science Fiction', author: 'Douglas Adams' }, + { genre: 'Science Fiction', author: 'Frank Herbert' }, + { genre: 'Southern Gothic', author: 'Harper Lee' } + ); + }); + + it('returns group and accumulate results', async () => { + const results = await randomCol + .pipeline() + .where(lt(Field.of('published'), 1984)) .aggregate({ - accumulators: [], + accumulators: [avgFunction('rating').as('avgRating')], groups: ['genre'] }) - .execute() - ).to.be.rejected; - }); + .where(gt('avgRating', 4.3)) + .sort(Field.of('avgRating').descending()) + .execute(); + expectResults( + results, + { avgRating: 4.7, genre: 'Fantasy' }, + { avgRating: 4.5, genre: 'Romance' }, + { avgRating: 4.4, genre: 'Science Fiction' } + ); + }); - // skip: toLower not supported - // it.skip('returns distinct values as expected', async () => { - // const results = await randomCol - // .pipeline() - // .where(lt('published', 1900)) - // .distinct(Field.of('genre').toLower().as('lowerGenre')) - // .execute(); - // expectResults( - // results, - // { lowerGenre: 'romance' }, - // { lowerGenre: 'psychological thriller' } - // ); - // }); - - it('returns group and accumulate results', async () => { - const results = await randomCol - .pipeline() - .where(lt(Field.of('published'), 1984)) - .aggregate({ - accumulators: [avgFunction('rating').as('avgRating')], - groups: ['genre'] - }) - .where(gt('avgRating', 4.3)) - .sort(Field.of('avgRating').descending()) - .execute(); - expectResults( - results, - { avgRating: 4.7, genre: 'Fantasy' }, - { avgRating: 4.5, genre: 'Romance' }, - { avgRating: 4.4, genre: 'Science Fiction' } - ); - }); + it('returns min and max accumulations', async () => { + const results = await randomCol + .pipeline() + .aggregate( + countAll().as('count'), + Field.of('rating').maximum().as('maxRating'), + Field.of('published').minimum().as('minPublished') + ) + .execute(); + expectResults(results, { + count: 10, + maxRating: 4.7, + minPublished: 1813 + }); + }); - it('returns min and max accumulations', async () => { - const results = await randomCol - .pipeline() - .aggregate( - countAll().as('count'), - Field.of('rating').maximum().as('maxRating'), - Field.of('published').minimum().as('minPublished') - ) - .execute(); - expectResults(results, { - count: 10, - maxRating: 4.7, - minPublished: 1813 + it('can select fields', async () => { + const results = await firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .sort(Field.of('author').ascending()) + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams' + }, + { title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' }, + { title: 'Dune', author: 'Frank Herbert' }, + { title: 'Crime and Punishment', author: 'Fyodor Dostoevsky' }, + { + title: 'One Hundred Years of Solitude', + author: 'Gabriel García Márquez' + }, + { title: '1984', author: 'George Orwell' }, + { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, + { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' }, + { title: 'Pride and Prejudice', author: 'Jane Austen' }, + { title: "The Handmaid's Tale", author: 'Margaret Atwood' } + ); }); - }); - it('can select fields', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author') - .sort(Field.of('author').ascending()) - .execute(); - expectResults( - results, - { - title: "The Hitchhiker's Guide to the Galaxy", - author: 'Douglas Adams' - }, - { title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' }, - { title: 'Dune', author: 'Frank Herbert' }, - { title: 'Crime and Punishment', author: 'Fyodor Dostoevsky' }, - { - title: 'One Hundred Years of Solitude', - author: 'Gabriel García Márquez' - }, - { title: '1984', author: 'George Orwell' }, - { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, - { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' }, - { title: 'Pride and Prejudice', author: 'Jane Austen' }, - { title: "The Handmaid's Tale", author: 'Margaret Atwood' } - ); - }); + it('where with and', async () => { + const results = await randomCol + .pipeline() + .where(andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction'))) + .execute(); + expectResults(results, 'book10'); + }); - it('where with and', async () => { - const results = await randomCol - .pipeline() - .where(andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction'))) - .execute(); - expectResults(results, 'book10'); - }); + it('where with or', async () => { + const results = await randomCol + .pipeline() + .where(orFunction(eq('genre', 'Romance'), eq('genre', 'Dystopian'))) + .select('title') + .execute(); + expectResults( + results, + { title: 'Pride and Prejudice' }, + { title: "The Handmaid's Tale" }, + { title: '1984' } + ); + }); - it('where with or', async () => { - const results = await randomCol - .pipeline() - .where(orFunction(eq('genre', 'Romance'), eq('genre', 'Dystopian'))) - .select('title') - .execute(); - expectResults( - results, - { title: 'Pride and Prejudice' }, - { title: "The Handmaid's Tale" }, - { title: '1984' } - ); - }); + it('offset and limits', async () => { + const results = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('author').ascending()) + .offset(5) + .limit(3) + .select('title', 'author') + .execute(); + expectResults( + results, + { title: '1984', author: 'George Orwell' }, + { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, + { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' } + ); + }); - it('offset and limits', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('author').ascending()) - .offset(5) - .limit(3) - .select('title', 'author') - .execute(); - expectResults( - results, - { title: '1984', author: 'George Orwell' }, - { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, - { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' } - ); - }); + it('logical min works', async () => { + const results = await randomCol + .pipeline() + .select( + 'title', + logicalMinimum(Constant.of(1960), Field.of('published')).as( + 'published-safe' + ) + ) + .sort(Field.of('title').ascending()) + .limit(3) + .execute(); + expectResults( + results, + { title: '1984', 'published-safe': 1949 }, + { title: 'Crime and Punishment', 'published-safe': 1866 }, + { title: 'Dune', 'published-safe': 1960 } + ); + }); - it('logical min works', async () => { - const results = await randomCol - .pipeline() - .select( - 'title', - logicalMinimum(Constant.of(1960), Field.of('published')).as( - 'published-safe' + it('logical max works', async () => { + const results = await randomCol + .pipeline() + .select( + 'title', + logicalMaximum(Constant.of(1960), Field.of('published')).as( + 'published-safe' + ) ) - ) - .sort(Field.of('title').ascending()) - .limit(3) - .execute(); - expectResults( - results, - { title: '1984', 'published-safe': 1949 }, - { title: 'Crime and Punishment', 'published-safe': 1866 }, - { title: 'Dune', 'published-safe': 1960 } - ); - }); + .sort(Field.of('title').ascending()) + .limit(3) + .execute(); + expectResults( + results, + { title: '1984', 'published-safe': 1960 }, + { title: 'Crime and Punishment', 'published-safe': 1960 }, + { title: 'Dune', 'published-safe': 1965 } + ); + }); - it('logical max works', async () => { - const results = await randomCol - .pipeline() - .select( - 'title', - logicalMaximum(Constant.of(1960), Field.of('published')).as( - 'published-safe' + it('cond works', async () => { + const results = await randomCol + .pipeline() + .select( + 'title', + cond( + lt(Field.of('published'), 1960), + Constant.of(1960), + Field.of('published') + ).as('published-safe') ) - ) - .sort(Field.of('title').ascending()) - .limit(3) - .execute(); - expectResults( - results, - { title: '1984', 'published-safe': 1960 }, - { title: 'Crime and Punishment', 'published-safe': 1960 }, - { title: 'Dune', 'published-safe': 1965 } - ); - }); + .sort(Field.of('title').ascending()) + .limit(3) + .execute(); + expectResults( + results, + { title: '1984', 'published-safe': 1960 }, + { title: 'Crime and Punishment', 'published-safe': 1960 }, + { title: 'Dune', 'published-safe': 1965 } + ); + }); - it('cond works', async () => { - const results = await randomCol - .pipeline() - .select( - 'title', - cond( - lt(Field.of('published'), 1960), - Constant.of(1960), - Field.of('published') - ).as('published-safe') - ) - .sort(Field.of('title').ascending()) - .limit(3) - .execute(); - expectResults( - results, - { title: '1984', 'published-safe': 1960 }, - { title: 'Crime and Punishment', 'published-safe': 1960 }, - { title: 'Dune', 'published-safe': 1965 } - ); - }); + it('eqAny works', async () => { + const results = await randomCol + .pipeline() + .where(eqAny('published', [1979, 1999, 1967])) + .select('title') + .execute(); + expectResults( + results, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'One Hundred Years of Solitude' } + ); + }); - it('eqAny works', async () => { - const results = await randomCol - .pipeline() - .where(eqAny('published', [1979, 1999, 1967])) - .select('title') - .execute(); - expectResults( - results, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'One Hundred Years of Solitude' } - ); - }); + it('notEqAny works', async () => { + const results = await randomCol + .pipeline() + .where( + notEqAny( + 'published', + [1965, 1925, 1949, 1960, 1866, 1985, 1954, 1967, 1979] + ) + ) + .select('title') + .execute(); + expectResults(results, { title: 'Pride and Prejudice' }); + }); + + it('arrayContains works', async () => { + const results = await randomCol + .pipeline() + .where(arrayContains('tags', 'comedy')) + .select('title') + .execute(); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy" + }); + }); - it('notEqAny works', async () => { - const results = await randomCol - .pipeline() - .where( - notEqAny( - 'published', - [1965, 1925, 1949, 1960, 1866, 1985, 1954, 1967, 1979] + it('arrayContainsAny works', async () => { + const results = await randomCol + .pipeline() + .where(arrayContainsAny('tags', ['comedy', 'classic'])) + .select('title') + .execute(); + expectResults( + results, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'Pride and Prejudice' } + ); + }); + + it('arrayContainsAll works', async () => { + const results = await randomCol + .pipeline() + .where(Field.of('tags').arrayContainsAll('adventure', 'magic')) + .select('title') + .execute(); + expectResults(results, { title: 'The Lord of the Rings' }); + }); + + it('arrayLength works', async () => { + const results = await randomCol + .pipeline() + .select(Field.of('tags').arrayLength().as('tagsCount')) + .where(eq('tagsCount', 3)) + .execute(); + expect(results.length).to.equal(10); + }); + + // skip: arrayConcat not supported + // it.skip('arrayConcat works', async () => { + // const results = await randomCol + // .pipeline() + // .select( + // Field.of('tags').arrayConcat(['newTag1', 'newTag2']).as('modifiedTags') + // ) + // .limit(1) + // .execute(); + // expectResults(results, { + // modifiedTags: ['comedy', 'space', 'adventure', 'newTag1', 'newTag2'] + // }); + // }); + + it('testStrConcat', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('author') + .strConcat(' - ', Field.of('title')) + .as('bookInfo') ) - ) - .select('title') - .execute(); - expectResults(results, { title: 'Pride and Prejudice' }); - }); + .limit(1) + .execute(); + expectResults(results, { + bookInfo: "Douglas Adams - The Hitchhiker's Guide to the Galaxy" + }); + }); - it('arrayContains works', async () => { - const results = await randomCol - .pipeline() - .where(arrayContains('tags', 'comedy')) - .select('title') - .execute(); - expectResults(results, { title: "The Hitchhiker's Guide to the Galaxy" }); - }); + it('testStartsWith', async () => { + const results = await randomCol + .pipeline() + .where(startsWith('title', 'The')) + .select('title') + .sort(Field.of('title').ascending()) + .execute(); + expectResults( + results, + { title: 'The Great Gatsby' }, + { title: "The Handmaid's Tale" }, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'The Lord of the Rings' } + ); + }); - it('arrayContainsAny works', async () => { - const results = await randomCol - .pipeline() - .where(arrayContainsAny('tags', ['comedy', 'classic'])) - .select('title') - .execute(); - expectResults( - results, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'Pride and Prejudice' } - ); - }); + it('testEndsWith', async () => { + const results = await randomCol + .pipeline() + .where(endsWith('title', 'y')) + .select('title') + .sort(Field.of('title').descending()) + .execute(); + expectResults( + results, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'The Great Gatsby' } + ); + }); - it('arrayContainsAll works', async () => { - const results = await randomCol - .pipeline() - .where(Field.of('tags').arrayContainsAll('adventure', 'magic')) - .select('title') - .execute(); - expectResults(results, { title: 'The Lord of the Rings' }); - }); + it('testLength', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('title').charLength().as('titleLength'), + Field.of('title') + ) + .where(gt('titleLength', 20)) + .sort(Field.of('title').ascending()) + .execute(); + + expectResults( + results, + + { + titleLength: 29, + title: 'One Hundred Years of Solitude' + }, + { + titleLength: 36, + title: "The Hitchhiker's Guide to the Galaxy" + }, + { + titleLength: 21, + title: 'The Lord of the Rings' + }, + { + titleLength: 21, + title: 'To Kill a Mockingbird' + } + ); + }); + + // skip: toLower not supported + // it.skip('testToLowercase', async () => { + // const results = await randomCol + // .pipeline() + // .select(Field.of('title').toLower().as('lowercaseTitle')) + // .limit(1) + // .execute(); + // expectResults(results, { + // lowercaseTitle: "the hitchhiker's guide to the galaxy" + // }); + // }); + + // skip: toUpper not supported + // it.skip('testToUppercase', async () => { + // const results = await randomCol + // .pipeline() + // .select(Field.of('author').toUpper().as('uppercaseAuthor')) + // .limit(1) + // .execute(); + // expectResults(results, { uppercaseAuthor: 'DOUGLAS ADAMS' }); + // }); + + // skip: trim not supported + // it.skip('testTrim', async () => { + // const results = await randomCol + // .pipeline() + // .addFields(strConcat(' ', Field.of('title'), ' ').as('spacedTitle')) + // .select( + // Field.of('spacedTitle').trim().as('trimmedTitle'), + // Field.of('spacedTitle') + // ) + // .limit(1) + // .execute(); + // expectResults(results, { + // spacedTitle: " The Hitchhiker's Guide to the Galaxy ", + // trimmedTitle: "The Hitchhiker's Guide to the Galaxy" + // }); + // }); + + it('testLike', async () => { + const results = await randomCol + .pipeline() + .where(like('title', '%Guide%')) + .select('title') + .execute(); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy" + }); + }); + + it('testRegexContains', async () => { + const results = await randomCol + .pipeline() + .where(regexContains('title', '(?i)(the|of)')) + .execute(); + expect(results.length).to.equal(5); + }); + + it('testRegexMatches', async () => { + const results = await randomCol + .pipeline() + .where(regexMatch('title', '.*(?i)(the|of).*')) + .execute(); + expect(results.length).to.equal(5); + }); + + it('testArithmeticOperations', async () => { + const results = await randomCol + .pipeline() + .select( + add(Field.of('rating'), 1).as('ratingPlusOne'), + subtract(Field.of('published'), 1900).as('yearsSince1900'), + Field.of('rating').multiply(10).as('ratingTimesTen'), + Field.of('rating').divide(2).as('ratingDividedByTwo') + ) + .limit(1) + .execute(); + expectResults(results, { + ratingPlusOne: 5.2, + yearsSince1900: 79, + ratingTimesTen: 42, + ratingDividedByTwo: 2.1 + }); + }); + + it('testComparisonOperators', async () => { + const results = await randomCol + .pipeline() + .where( + andFunction( + gt('rating', 4.2), + lte(Field.of('rating'), 4.5), + neq('genre', 'Science Fiction') + ) + ) + .select('rating', 'title') + .sort(Field.of('title').ascending()) + .execute(); + expectResults( + results, + { rating: 4.3, title: 'Crime and Punishment' }, + { + rating: 4.3, + title: 'One Hundred Years of Solitude' + }, + { rating: 4.5, title: 'Pride and Prejudice' } + ); + }); + + it('testLogicalOperators', async () => { + const results = await randomCol + .pipeline() + .where( + orFunction( + andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')), + lt('published', 1900) + ) + ) + .select('title') + .sort(Field.of('title').ascending()) + .execute(); + expectResults( + results, + { title: 'Crime and Punishment' }, + { title: 'Dune' }, + { title: 'Pride and Prejudice' } + ); + }); + + it('testChecks', async () => { + const results = await randomCol + .pipeline() + .where(not(Field.of('rating').isNaN())) + .select( + Field.of('rating').eq(null).as('ratingIsNull'), + not(Field.of('rating').isNaN()).as('ratingIsNotNaN') + ) + .limit(1) + .execute(); + expectResults(results, { ratingIsNull: false, ratingIsNotNaN: true }); + }); + + it('testMapGet', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('awards').mapGet('hugo').as('hugoAward'), + Field.of('awards').mapGet('others').as('others'), + Field.of('title') + ) + .where(eq('hugoAward', true)) + .execute(); + expectResults( + results, + { + hugoAward: true, + title: "The Hitchhiker's Guide to the Galaxy", + others: { unknown: { year: 1980 } } + }, + { hugoAward: true, title: 'Dune', others: null } + ); + }); + + // it('testParent', async () => { + // const results = await randomCol + // .pipeline() + // .select( + // parent(randomCol.doc('chile').collection('subCollection').path).as( + // 'parent' + // ) + // ) + // .limit(1) + // .execute(); + // expect(results[0].data().parent.endsWith('/books')).to.be.true; + // }); + // + // it('testCollectionId', async () => { + // const results = await randomCol + // .pipeline() + // .select(collectionId(randomCol.doc('chile')).as('collectionId')) + // .limit(1) + // .execute(); + // expectResults(results, {collectionId: 'books'}); + // }); + + it('testDistanceFunctions', async () => { + const sourceVector = [0.1, 0.1]; + const targetVector = [0.5, 0.8]; + const results = await randomCol + .pipeline() + .select( + cosineDistance(Constant.vector(sourceVector), targetVector).as( + 'cosineDistance' + ), + dotProduct(Constant.vector(sourceVector), targetVector).as( + 'dotProductDistance' + ), + euclideanDistance(Constant.vector(sourceVector), targetVector).as( + 'euclideanDistance' + ) + ) + .limit(1) + .execute(); + + expectResults(results, { + cosineDistance: 0.02560880430538015, + dotProductDistance: 0.13, + euclideanDistance: 0.806225774829855 + }); + }); + + it('testNestedFields', async () => { + const results = await randomCol + .pipeline() + .where(eq('awards.hugo', true)) + .select('title', 'awards.hugo') + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + 'awards.hugo': true + }, + { title: 'Dune', 'awards.hugo': true } + ); + }); + + it('test mapGet with field name including . notation', async () => { + const results = await randomCol + .pipeline() + .where(eq('awards.hugo', true)) + .select( + 'title', + Field.of('nestedField.level.1'), + mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') + ) + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + 'nestedField.level.`1`': null, + nested: true + }, + { title: 'Dune', 'nestedField.level.`1`': null, nested: null } + ); + }); + + it('supports internal serialization to proto', async () => { + const pipeline = firestore + .pipeline() + .collection('books') + .where(eq('awards.hugo', true)) + .select( + 'title', + Field.of('nestedField.level.1'), + mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') + ); + + const proto = _internalPipelineToExecutePipelineRequestProto(pipeline); + expect(proto).not.to.be.null; + }); + + describe('pagination', () => { + async function addBooks( + collection: CollectionReference + ): Promise { + await setDoc(doc(randomCol, 'book11'), { + title: 'Jonathan Strange & Mr Norrell', + author: 'Susanna Clarke', + genre: 'Fantasy', + published: 2004, + rating: 4.6, + tags: [ + 'historical fantasy', + 'magic', + 'alternate history', + 'england' + ], + awards: { hugo: false, nebula: false } + }); + await setDoc(doc(randomCol, 'book12'), { + title: 'The Master and Margarita', + author: 'Mikhail Bulgakov', + genre: 'Satire', + published: 1967, // Though written much earlier + rating: 4.6, + tags: [ + 'russian literature', + 'supernatural', + 'philosophy', + 'dark comedy' + ], + awards: {} + }); + await setDoc(doc(randomCol, 'book13'), { + title: 'A Long Way to a Small, Angry Planet', + author: 'Becky Chambers', + genre: 'Science Fiction', + published: 2014, + rating: 4.6, + tags: [ + 'space opera', + 'found family', + 'character-driven', + 'optimistic' + ], + awards: { hugo: false, nebula: false, kitschies: true } + }); + } + + it('supports pagination with filters', async () => { + await addBooks(randomCol); + const pageSize = 2; + const pipeline = randomCol + .pipeline() + .select('title', 'rating', '__name__') + .sort( + Field.of('rating').descending(), + Field.of('__name__').ascending() + ); + + let results = await pipeline.limit(pageSize).execute(); + expectResults( + results, + { title: 'The Lord of the Rings', rating: 4.7 }, + { title: 'Jonathan Strange & Mr Norrell', rating: 4.6 } + ); + + const lastDoc = results[results.length - 1]; + + results = await pipeline + .where( + orFunction( + andFunction( + Field.of('rating').eq(lastDoc.get('rating')), + Field.of('__path__').gt(lastDoc.ref?.path) + ), + Field.of('rating').lt(lastDoc.get('rating')) + ) + ) + .limit(pageSize) + .execute(); + expectResults( + results, + { title: 'Pride and Prejudice', rating: 4.5 }, + { title: 'Crime and Punishment', rating: 4.3 } + ); + }); - it('arrayLength works', async () => { - const results = await randomCol - .pipeline() - .select(Field.of('tags').arrayLength().as('tagsCount')) - .where(eq('tagsCount', 3)) - .execute(); - expect(results.length).to.equal(10); + it('supports pagination with offsets', async () => { + await addBooks(randomCol); + + const secondFilterField = '__path__'; + + const pipeline = randomCol + .pipeline() + .select('title', 'rating', secondFilterField) + .sort( + Field.of('rating').descending(), + Field.of(secondFilterField).ascending() + ); + + const pageSize = 2; + let currPage = 0; + + let results = await pipeline + .offset(currPage++ * pageSize) + .limit(pageSize) + .execute(); + + expectResults( + results, + { + title: 'The Lord of the Rings', + rating: 4.7 + }, + { title: 'Dune', rating: 4.6 } + ); + + results = await pipeline + .offset(currPage++ * pageSize) + .limit(pageSize) + .execute(); + expectResults( + results, + { + title: 'Jonathan Strange & Mr Norrell', + rating: 4.6 + }, + { title: 'The Master and Margarita', rating: 4.6 } + ); + + results = await pipeline + .offset(currPage++ * pageSize) + .limit(pageSize) + .execute(); + expectResults( + results, + { + title: 'A Long Way to a Small, Angry Planet', + rating: 4.6 + }, + { + title: 'Pride and Prejudice', + rating: 4.5 + } + ); + }); + }); }); - // skip: arrayConcat not supported - // it.skip('arrayConcat works', async () => { - // const results = await randomCol - // .pipeline() - // .select( - // Field.of('tags').arrayConcat(['newTag1', 'newTag2']).as('modifiedTags') - // ) - // .limit(1) - // .execute(); - // expectResults(results, { - // modifiedTags: ['comedy', 'space', 'adventure', 'newTag1', 'newTag2'] - // }); - // }); - - it('testStrConcat', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('author').strConcat(' - ', Field.of('title')).as('bookInfo') - ) - .limit(1) - .execute(); - expectResults(results, { - bookInfo: "Douglas Adams - The Hitchhiker's Guide to the Galaxy" + describe('modular API', () => { + it('works when creating a pipeline from a Firestore instance', async () => { + const myPipeline = pipeline(firestore) + .collection(randomCol.path) + .where(lt(Field.of('published'), 1984)) + .aggregate({ + accumulators: [avgFunction('rating').as('avgRating')], + groups: ['genre'] + }) + .where(gt('avgRating', 4.3)) + .sort(Field.of('avgRating').descending()); + + const results = await execute(myPipeline); + + expectResults( + results, + { avgRating: 4.7, genre: 'Fantasy' }, + { avgRating: 4.5, genre: 'Romance' }, + { avgRating: 4.4, genre: 'Science Fiction' } + ); + }); + + it('works when creating a pipeline from a collection', async () => { + const myPipeline = pipeline(randomCol) + .where(lt(Field.of('published'), 1984)) + .aggregate({ + accumulators: [avgFunction('rating').as('avgRating')], + groups: ['genre'] + }) + .where(gt('avgRating', 4.3)) + .sort(Field.of('avgRating').descending()); + + const results = await execute(myPipeline); + + expectResults( + results, + { avgRating: 4.7, genre: 'Fantasy' }, + { avgRating: 4.5, genre: 'Romance' }, + { avgRating: 4.4, genre: 'Science Fiction' } + ); }); }); + }); - it('testStartsWith', async () => { - const results = await randomCol - .pipeline() - .where(startsWith('title', 'The')) - .select('title') - .sort(Field.of('title').ascending()) - .execute(); - expectResults( - results, - { title: 'The Great Gatsby' }, - { title: "The Handmaid's Tale" }, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'The Lord of the Rings' } + // This is the Query integration tests from the lite API (no cache support) + // with some additional test cases added for more complete coverage. + describe('Query to Pipeline', () => { + function verifyResults( + actual: Array>, + ...expected: DocumentData[] + ): void { + expect(actual.length).to.equal(expected.length); + + for (let i = 0; i < expected.length; ++i) { + expect(actual[i].data()).to.deep.equal(expected[i]); + } + } + + it('supports default query', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { 1: { foo: 1 } }, + async collRef => { + const result = await collRef.pipeline().execute(); + verifyResults(result, { foo: 1 }); + } ); }); - it('testEndsWith', async () => { - const results = await randomCol - .pipeline() - .where(endsWith('title', 'y')) - .select('title') - .sort(Field.of('title').descending()) - .execute(); - expectResults( - results, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'The Great Gatsby' } + it('supports filtered query', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, where('foo', '==', 1)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }); + } ); }); - it('testLength', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('title').charLength().as('titleLength'), - Field.of('title') - ) - .where(gt('titleLength', 20)) - .sort(Field.of('title').ascending()) - .execute(); - - expectResults( - results, - + it('supports filtered query (with FieldPath)', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, { - titleLength: 29, - title: 'One Hundred Years of Solitude' + 1: { foo: 1 }, + 2: { foo: 2 } }, + async collRef => { + const query1 = query(collRef, where(new FieldPath('foo'), '==', 1)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }); + } + ); + }); + + it('supports ordered query (with default order)', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, { - titleLength: 36, - title: "The Hitchhiker's Guide to the Galaxy" + 1: { foo: 1 }, + 2: { foo: 2 } }, + async collRef => { + const query1 = query(collRef, orderBy('foo')); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }, { foo: 2 }); + } + ); + }); + + it('supports ordered query (with asc)', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, { - titleLength: 21, - title: 'The Lord of the Rings' + 1: { foo: 1 }, + 2: { foo: 2 } }, - { - titleLength: 21, - title: 'To Kill a Mockingbird' + async collRef => { + const query1 = query(collRef, orderBy('foo', 'asc')); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }, { foo: 2 }); } ); }); - // skip: toLower not supported - // it.skip('testToLowercase', async () => { - // const results = await randomCol - // .pipeline() - // .select(Field.of('title').toLower().as('lowercaseTitle')) - // .limit(1) - // .execute(); - // expectResults(results, { - // lowercaseTitle: "the hitchhiker's guide to the galaxy" - // }); - // }); - - // skip: toUpper not supported - // it.skip('testToUppercase', async () => { - // const results = await randomCol - // .pipeline() - // .select(Field.of('author').toUpper().as('uppercaseAuthor')) - // .limit(1) - // .execute(); - // expectResults(results, { uppercaseAuthor: 'DOUGLAS ADAMS' }); - // }); - - // skip: trim not supported - // it.skip('testTrim', async () => { - // const results = await randomCol - // .pipeline() - // .addFields(strConcat(' ', Field.of('title'), ' ').as('spacedTitle')) - // .select( - // Field.of('spacedTitle').trim().as('trimmedTitle'), - // Field.of('spacedTitle') - // ) - // .limit(1) - // .execute(); - // expectResults(results, { - // spacedTitle: " The Hitchhiker's Guide to the Galaxy ", - // trimmedTitle: "The Hitchhiker's Guide to the Galaxy" - // }); - // }); - - it('testLike', async () => { - const results = await randomCol - .pipeline() - .where(like('title', '%Guide%')) - .select('title') - .execute(); - expectResults(results, { title: "The Hitchhiker's Guide to the Galaxy" }); + it('supports ordered query (with desc)', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo', 'desc')); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 2 }, { foo: 1 }); + } + ); }); - it('testRegexContains', async () => { - const results = await randomCol - .pipeline() - .where(regexContains('title', '(?i)(the|of)')) - .execute(); - expect(results.length).to.equal(5); + it('supports limit query', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo'), limit(1)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }); + } + ); }); - it('testRegexMatches', async () => { - const results = await randomCol - .pipeline() - .where(regexMatch('title', '.*(?i)(the|of).*')) - .execute(); - expect(results.length).to.equal(5); + it('supports limitToLast query', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 }, + 3: { foo: 3 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo'), limitToLast(2)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 2 }, { foo: 3 }); + } + ); }); - it('testArithmeticOperations', async () => { - const results = await randomCol - .pipeline() - .select( - add(Field.of('rating'), 1).as('ratingPlusOne'), - subtract(Field.of('published'), 1900).as('yearsSince1900'), - Field.of('rating').multiply(10).as('ratingTimesTen'), - Field.of('rating').divide(2).as('ratingDividedByTwo') - ) - .limit(1) - .execute(); - expectResults(results, { - ratingPlusOne: 5.2, - yearsSince1900: 79, - ratingTimesTen: 42, - ratingDividedByTwo: 2.1 - }); + it('supports startAt', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo'), startAt(2)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 2 }); + } + ); }); - it('testComparisonOperators', async () => { - const results = await randomCol - .pipeline() - .where( - andFunction( - gt('rating', 4.2), - lte(Field.of('rating'), 4.5), - neq('genre', 'Science Fiction') - ) - ) - .select('rating', 'title') - .sort(Field.of('title').ascending()) - .execute(); - expectResults( - results, - { rating: 4.3, title: 'Crime and Punishment' }, + it('supports startAfter (with DocumentReference)', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, { - rating: 4.3, - title: 'One Hundred Years of Solitude' + 1: { id: 1, foo: 1, bar: 1, baz: 1 }, + 2: { id: 2, foo: 1, bar: 1, baz: 2 }, + 3: { id: 3, foo: 1, bar: 1, baz: 2 }, + 4: { id: 4, foo: 1, bar: 2, baz: 1 }, + 5: { id: 5, foo: 1, bar: 2, baz: 2 }, + 6: { id: 6, foo: 1, bar: 2, baz: 2 }, + 7: { id: 7, foo: 2, bar: 1, baz: 1 }, + 8: { id: 8, foo: 2, bar: 1, baz: 2 }, + 9: { id: 9, foo: 2, bar: 1, baz: 2 }, + 10: { id: 10, foo: 2, bar: 2, baz: 1 }, + 11: { id: 11, foo: 2, bar: 2, baz: 2 }, + 12: { id: 12, foo: 2, bar: 2, baz: 2 } }, - { rating: 4.5, title: 'Pride and Prejudice' } + async collRef => { + let docRef = await getDoc(doc(collRef, '2')); + let query1 = query( + collRef, + orderBy('foo'), + orderBy('bar'), + orderBy('baz'), + startAfter(docRef) + ); + let result = await query1.pipeline().execute(); + verifyResults( + result, + { id: 3, foo: 1, bar: 1, baz: 2 }, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 }, + { id: 11, foo: 2, bar: 2, baz: 2 }, + { id: 12, foo: 2, bar: 2, baz: 2 } + ); + + docRef = await getDoc(doc(collRef, '3')); + query1 = query( + collRef, + orderBy('foo'), + orderBy('bar'), + orderBy('baz'), + startAfter(docRef) + ); + result = await query1.pipeline().execute(); + verifyResults( + result, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 }, + { id: 11, foo: 2, bar: 2, baz: 2 }, + { id: 12, foo: 2, bar: 2, baz: 2 } + ); + } ); }); - it('testLogicalOperators', async () => { - const results = await randomCol - .pipeline() - .where( - orFunction( - andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')), - lt('published', 1900) - ) - ) - .select('title') - .sort(Field.of('title').ascending()) - .execute(); - expectResults( - results, - { title: 'Crime and Punishment' }, - { title: 'Dune' }, - { title: 'Pride and Prejudice' } + it('supports startAt (with DocumentReference)', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { id: 1, foo: 1, bar: 1, baz: 1 }, + 2: { id: 2, foo: 1, bar: 1, baz: 2 }, + 3: { id: 3, foo: 1, bar: 1, baz: 2 }, + 4: { id: 4, foo: 1, bar: 2, baz: 1 }, + 5: { id: 5, foo: 1, bar: 2, baz: 2 }, + 6: { id: 6, foo: 1, bar: 2, baz: 2 }, + 7: { id: 7, foo: 2, bar: 1, baz: 1 }, + 8: { id: 8, foo: 2, bar: 1, baz: 2 }, + 9: { id: 9, foo: 2, bar: 1, baz: 2 }, + 10: { id: 10, foo: 2, bar: 2, baz: 1 }, + 11: { id: 11, foo: 2, bar: 2, baz: 2 }, + 12: { id: 12, foo: 2, bar: 2, baz: 2 } + }, + async collRef => { + let docRef = await getDoc(doc(collRef, '2')); + let query1 = query( + collRef, + orderBy('foo'), + orderBy('bar'), + orderBy('baz'), + startAt(docRef) + ); + let result = await query1.pipeline().execute(); + verifyResults( + result, + { id: 2, foo: 1, bar: 1, baz: 2 }, + { id: 3, foo: 1, bar: 1, baz: 2 }, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 }, + { id: 11, foo: 2, bar: 2, baz: 2 }, + { id: 12, foo: 2, bar: 2, baz: 2 } + ); + + docRef = await getDoc(doc(collRef, '3')); + query1 = query( + collRef, + orderBy('foo'), + orderBy('bar'), + orderBy('baz'), + startAt(docRef) + ); + result = await query1.pipeline().execute(); + verifyResults( + result, + { id: 3, foo: 1, bar: 1, baz: 2 }, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 }, + { id: 11, foo: 2, bar: 2, baz: 2 }, + { id: 12, foo: 2, bar: 2, baz: 2 } + ); + } ); }); - it('testChecks', async () => { - const results = await randomCol - .pipeline() - .where(not(Field.of('rating').isNaN())) - .select( - Field.of('rating').eq(null).as('ratingIsNull'), - not(Field.of('rating').isNaN()).as('ratingIsNotNaN') - ) - .limit(1) - .execute(); - expectResults(results, { ratingIsNull: false, ratingIsNotNaN: true }); + it('supports startAfter', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo'), startAfter(1)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 2 }); + } + ); }); - it('testMapGet', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('awards').mapGet('hugo').as('hugoAward'), - Field.of('awards').mapGet('others').as('others'), - Field.of('title') - ) - .where(eq('hugoAward', true)) - .execute(); - expectResults( - results, + it('supports endAt', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, { - hugoAward: true, - title: "The Hitchhiker's Guide to the Galaxy", - others: { unknown: { year: 1980 } } + 1: { foo: 1 }, + 2: { foo: 2 } }, - { hugoAward: true, title: 'Dune', others: null } + async collRef => { + const query1 = query(collRef, orderBy('foo'), endAt(1)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }); + } ); }); - // it('testParent', async () => { - // const results = await randomCol - // .pipeline() - // .select( - // parent(randomCol.doc('chile').collection('subCollection').path).as( - // 'parent' - // ) - // ) - // .limit(1) - // .execute(); - // expect(results[0].data().parent.endsWith('/books')).to.be.true; - // }); - // - // it('testCollectionId', async () => { - // const results = await randomCol - // .pipeline() - // .select(collectionId(randomCol.doc('chile')).as('collectionId')) - // .limit(1) - // .execute(); - // expectResults(results, {collectionId: 'books'}); - // }); - - it('testDistanceFunctions', async () => { - const sourceVector = [0.1, 0.1]; - const targetVector = [0.5, 0.8]; - const results = await randomCol - .pipeline() - .select( - cosineDistance(Constant.vector(sourceVector), targetVector).as( - 'cosineDistance' - ), - dotProduct(Constant.vector(sourceVector), targetVector).as( - 'dotProductDistance' - ), - euclideanDistance(Constant.vector(sourceVector), targetVector).as( - 'euclideanDistance' - ) - ) - .limit(1) - .execute(); - - expectResults(results, { - cosineDistance: 0.02560880430538015, - dotProductDistance: 0.13, - euclideanDistance: 0.806225774829855 - }); + it('supports endBefore', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo'), endBefore(2)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }); + } + ); }); - it('testNestedFields', async () => { - const results = await randomCol - .pipeline() - .where(eq('awards.hugo', true)) - .select('title', 'awards.hugo') - .execute(); - expectResults( - results, - { title: "The Hitchhiker's Guide to the Galaxy", 'awards.hugo': true }, - { title: 'Dune', 'awards.hugo': true } + it('supports pagination', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + let query1 = query(collRef, orderBy('foo'), limit(1)); + const pipeline1 = query1.pipeline(); + let result = await pipeline1.execute(); + verifyResults(result, { foo: 1 }); + + // Pass the document snapshot from the previous result + query1 = query(query1, startAfter(result[0].get('foo'))); + result = await query1.pipeline().execute(); + verifyResults(result, { foo: 2 }); + } ); }); - it('test mapGet with field name including . notation', async () => { - const results = await randomCol - .pipeline() - .where(eq('awards.hugo', true)) - .select( - 'title', - Field.of('nestedField.level.1'), - mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') - ) - .execute(); - expectResults( - results, + it('supports pagination on DocumentIds', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, { - title: "The Hitchhiker's Guide to the Galaxy", - 'nestedField.level.`1`': null, - nested: true + 1: { foo: 1 }, + 2: { foo: 2 } }, - { title: 'Dune', 'nestedField.level.`1`': null, nested: null } + async collRef => { + let query1 = query( + collRef, + orderBy('foo'), + orderBy(documentId(), 'asc'), + limit(1) + ); + const pipeline1 = query1.pipeline(); + let result = await pipeline1.execute(); + verifyResults(result, { foo: 1 }); + + // Pass the document snapshot from the previous result + query1 = query( + query1, + startAfter(result[0].get('foo'), result[0].ref?.id) + ); + result = await query1.pipeline().execute(); + verifyResults(result, { foo: 2 }); + } ); }); - it('supports internal serialization to proto', async () => { - const pipeline = firestore - .pipeline() - .collection('books') - .where(eq('awards.hugo', true)) - .select( - 'title', - Field.of('nestedField.level.1'), - mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') - ); + it('supports collection groups', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + {}, + async collRef => { + const collectionGroupId = `${collRef.id}group`; + + const fooDoc = doc( + collRef.firestore, + `${collRef.id}/foo/${collectionGroupId}/doc1` + ); + const barDoc = doc( + collRef.firestore, + `${collRef.id}/bar/baz/boo/${collectionGroupId}/doc2` + ); + await setDoc(fooDoc, { foo: 1 }); + await setDoc(barDoc, { bar: 1 }); + + const query1 = collectionGroup(collRef.firestore, collectionGroupId); + const result = await query1.pipeline().execute(); + + verifyResults(result, { bar: 1 }, { foo: 1 }); + } + ); + }); + + it('supports query over collection path with special characters', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + {}, + async collRef => { + const docWithSpecials = doc(collRef, 'so!@#$%^&*()_+special'); + + const collectionWithSpecials = collection( + docWithSpecials, + 'so!@#$%^&*()_+special' + ); + await addDoc(collectionWithSpecials, { foo: 1 }); + await addDoc(collectionWithSpecials, { foo: 2 }); + + const result = await query( + collectionWithSpecials, + orderBy('foo', 'asc') + ) + .pipeline() + .execute(); - const proto = _internalPipelineToExecutePipelineRequestProto(pipeline); - expect(proto).not.to.be.null; + verifyResults(result, { foo: 1 }, { foo: 2 }); + } + ); }); - }); - describe('modular API', () => { - it('works when creating a pipeline from a Firestore instance', async () => { - const myPipeline = pipeline(firestore) - .collection(randomCol.path) - .where(lt(Field.of('published'), 1984)) - .aggregate({ - accumulators: [avgFunction('rating').as('avgRating')], - groups: ['genre'] - }) - .where(gt('avgRating', 4.3)) - .sort(Field.of('avgRating').descending()); - - const results = await execute(myPipeline); - - expectResults( - results, - { avgRating: 4.7, genre: 'Fantasy' }, - { avgRating: 4.5, genre: 'Romance' }, - { avgRating: 4.4, genre: 'Science Fiction' } + it('supports multiple inequality on same field', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + '01': { id: 1, foo: 1, bar: 1, baz: 1 }, + '02': { id: 2, foo: 1, bar: 1, baz: 2 }, + '03': { id: 3, foo: 1, bar: 1, baz: 2 }, + '04': { id: 4, foo: 1, bar: 2, baz: 1 }, + '05': { id: 5, foo: 1, bar: 2, baz: 2 }, + '06': { id: 6, foo: 1, bar: 2, baz: 2 }, + '07': { id: 7, foo: 2, bar: 1, baz: 1 }, + '08': { id: 8, foo: 2, bar: 1, baz: 2 }, + '09': { id: 9, foo: 2, bar: 1, baz: 2 }, + '10': { id: 10, foo: 2, bar: 2, baz: 1 }, + '11': { id: 11, foo: 2, bar: 2, baz: 2 }, + '12': { id: 12, foo: 2, bar: 2, baz: 2 } + }, + async collRef => { + const query1 = query( + collRef, + and(where('id', '>', 2), where('id', '<=', 10)) + ); + const result = await query1.pipeline().execute(); + verifyResults( + result, + { id: 3, foo: 1, bar: 1, baz: 2 }, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 } + ); + } ); }); - it('works when creating a pipeline from a collection', async () => { - const myPipeline = pipeline(randomCol) - .where(lt(Field.of('published'), 1984)) - .aggregate({ - accumulators: [avgFunction('rating').as('avgRating')], - groups: ['genre'] - }) - .where(gt('avgRating', 4.3)) - .sort(Field.of('avgRating').descending()); - - const results = await execute(myPipeline); - - expectResults( - results, - { avgRating: 4.7, genre: 'Fantasy' }, - { avgRating: 4.5, genre: 'Romance' }, - { avgRating: 4.4, genre: 'Science Fiction' } + it('supports multiple inequality on different fields', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + '01': { id: 1, foo: 1, bar: 1, baz: 1 }, + '02': { id: 2, foo: 1, bar: 1, baz: 2 }, + '03': { id: 3, foo: 1, bar: 1, baz: 2 }, + '04': { id: 4, foo: 1, bar: 2, baz: 1 }, + '05': { id: 5, foo: 1, bar: 2, baz: 2 }, + '06': { id: 6, foo: 1, bar: 2, baz: 2 }, + '07': { id: 7, foo: 2, bar: 1, baz: 1 }, + '08': { id: 8, foo: 2, bar: 1, baz: 2 }, + '09': { id: 9, foo: 2, bar: 1, baz: 2 }, + '10': { id: 10, foo: 2, bar: 2, baz: 1 }, + '11': { id: 11, foo: 2, bar: 2, baz: 2 }, + '12': { id: 12, foo: 2, bar: 2, baz: 2 } + }, + async collRef => { + const query1 = query( + collRef, + and(where('id', '>=', 2), where('baz', '<', 2)) + ); + const result = await query1.pipeline().execute(); + verifyResults( + result, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 10, foo: 2, bar: 2, baz: 1 } + ); + } ); }); }); From 50a65e43c4315bb28fe9022b634a1d8e44c00c3e Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 23 Jan 2025 12:51:04 -0700 Subject: [PATCH 16/75] API tweaks from review. Selectable, FilterCondition, and Accumulator are abstract classes not interfaces. Removed extraneous Pipeline.sort overload --- packages/firestore/src/core/pipeline-util.ts | 138 +--------------- .../firestore/src/lite-api/expressions.ts | 88 +++++----- packages/firestore/src/lite-api/pipeline.ts | 1 - packages/firestore/src/util/proto.ts | 155 ++++++++++++++++++ 4 files changed, 200 insertions(+), 182 deletions(-) create mode 100644 packages/firestore/src/util/proto.ts diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index 7f1e0dfde64..0800eba85ea 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -29,24 +29,13 @@ import { gt, lte, gte, - Expr, eq, Or } from '../lite-api/expressions'; import { Pipeline } from '../lite-api/pipeline'; import { doc } from '../lite-api/reference'; import { isNanValue, isNullValue } from '../model/values'; -import { - ArrayValue as ProtoArrayValue, - Function as ProtoFunction, - LatLng as ProtoLatLng, - MapValue as ProtoMapValue, - Pipeline as ProtoPipeline, - Timestamp as ProtoTimestamp, - Value as ProtoValue -} from '../protos/firestore_proto_api'; import { fail } from '../util/assert'; -import { isPlainObject } from '../util/input_validation'; import { Bound } from './bound'; import { @@ -67,131 +56,6 @@ import { /* eslint @typescript-eslint/no-explicit-any: 0 */ -function isITimestamp(obj: any): obj is ProtoTimestamp { - if (typeof obj !== 'object' || obj === null) { - return false; // Must be a non-null object - } - if ( - 'seconds' in obj && - (obj.seconds === null || - typeof obj.seconds === 'number' || - typeof obj.seconds === 'string') && - 'nanos' in obj && - (obj.nanos === null || typeof obj.nanos === 'number') - ) { - return true; - } - - return false; -} -function isILatLng(obj: any): obj is ProtoLatLng { - if (typeof obj !== 'object' || obj === null) { - return false; // Must be a non-null object - } - if ( - 'latitude' in obj && - (obj.latitude === null || typeof obj.latitude === 'number') && - 'longitude' in obj && - (obj.longitude === null || typeof obj.longitude === 'number') - ) { - return true; - } - - return false; -} -function isIArrayValue(obj: any): obj is ProtoArrayValue { - if (typeof obj !== 'object' || obj === null) { - return false; // Must be a non-null object - } - if ('values' in obj && (obj.values === null || Array.isArray(obj.values))) { - return true; - } - - return false; -} -function isIMapValue(obj: any): obj is ProtoMapValue { - if (typeof obj !== 'object' || obj === null) { - return false; // Must be a non-null object - } - if ('fields' in obj && (obj.fields === null || isPlainObject(obj.fields))) { - return true; - } - - return false; -} -function isIFunction(obj: any): obj is ProtoFunction { - if (typeof obj !== 'object' || obj === null) { - return false; // Must be a non-null object - } - if ( - 'name' in obj && - (obj.name === null || typeof obj.name === 'string') && - 'args' in obj && - (obj.args === null || Array.isArray(obj.args)) - ) { - return true; - } - - return false; -} - -function isIPipeline(obj: any): obj is ProtoPipeline { - if (typeof obj !== 'object' || obj === null) { - return false; // Must be a non-null object - } - if ('stages' in obj && (obj.stages === null || Array.isArray(obj.stages))) { - return true; - } - - return false; -} - -export function isFirestoreValue(obj: any): obj is ProtoValue { - if (typeof obj !== 'object' || obj === null) { - return false; // Must be a non-null object - } - - // Check optional properties and their types - if ( - ('nullValue' in obj && - (obj.nullValue === null || obj.nullValue === 'NULL_VALUE')) || - ('booleanValue' in obj && - (obj.booleanValue === null || typeof obj.booleanValue === 'boolean')) || - ('integerValue' in obj && - (obj.integerValue === null || - typeof obj.integerValue === 'number' || - typeof obj.integerValue === 'string')) || - ('doubleValue' in obj && - (obj.doubleValue === null || typeof obj.doubleValue === 'number')) || - ('timestampValue' in obj && - (obj.timestampValue === null || isITimestamp(obj.timestampValue))) || - ('stringValue' in obj && - (obj.stringValue === null || typeof obj.stringValue === 'string')) || - ('bytesValue' in obj && - (obj.bytesValue === null || obj.bytesValue instanceof Uint8Array)) || - ('referenceValue' in obj && - (obj.referenceValue === null || - typeof obj.referenceValue === 'string')) || - ('geoPointValue' in obj && - (obj.geoPointValue === null || isILatLng(obj.geoPointValue))) || - ('arrayValue' in obj && - (obj.arrayValue === null || isIArrayValue(obj.arrayValue))) || - ('mapValue' in obj && - (obj.mapValue === null || isIMapValue(obj.mapValue))) || - ('fieldReferenceValue' in obj && - (obj.fieldReferenceValue === null || - typeof obj.fieldReferenceValue === 'string')) || - ('functionValue' in obj && - (obj.functionValue === null || isIFunction(obj.functionValue))) || - ('pipelineValue' in obj && - (obj.pipelineValue === null || isIPipeline(obj.pipelineValue))) - ) { - return true; - } - - return false; -} - export function toPipelineFilterCondition(f: FilterInternal): FilterCondition { if (f instanceof FieldFilterInternal) { const field = Field.of(f.field.toString()); @@ -355,7 +219,7 @@ function whereConditionsFromCursor( bound: Bound, orderings: Ordering[], position: 'before' | 'after' -): Expr { +): FilterCondition { const cursors = bound.position.map(value => Constant._fromProto(value)); const filterFunc = position === 'before' ? lt : gt; const filterInclusiveFunc = position === 'before' ? lte : gte; diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 4caee458bb3..f757e49f495 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -17,7 +17,6 @@ /* eslint @typescript-eslint/no-explicit-any: 0 */ -import { isFirestoreValue } from '../core/pipeline-util'; import { DOCUMENT_KEY_NAME, FieldPath as InternalFieldPath @@ -30,6 +29,7 @@ import { UserData } from '../remote/serializer'; import { hardAssert } from '../util/assert'; +import { isFirestoreValue } from '../util/proto'; import { documentId, FieldPath } from './field_path'; import { GeoPoint } from './geo_point'; @@ -44,45 +44,6 @@ import { } from './user_data_reader'; import { VectorValue } from './vector_value'; -/** - * @beta - * - * An interface that represents a selectable expression. - */ -export interface Selectable extends Expr { - selectable: true; -} - -/** - * @beta - * - * An interface that represents a filter condition. - */ -export interface FilterCondition extends Expr { - filterable: true; -} - -/** - * @beta - * - * An interface that represents an accumulator. - */ -export interface Accumulator extends Expr { - accumulator: true; - /** - * @private - * @internal - */ - _toProto(serializer: JsonProtoSerializer): ProtoValue; -} - -/** - * @beta - * - * An accumulator target, which is an expression with an alias that also implements the Accumulator interface. - */ -export type AccumulatorTarget = ExprWithAlias; - /** * @beta * @@ -1821,10 +1782,50 @@ export abstract class Expr implements ProtoSerializable, UserData { abstract _readUserData(dataReader: UserDataReader): void; } +/** + * @beta + * + * An interface that represents a selectable expression. + */ +export abstract class Selectable extends Expr { + selectable: true = true; +} + +/** + * @beta + * + * An interface that represents a filter condition. + */ +export abstract class FilterCondition extends Expr { + filterable: true = true; +} + +/** + * @beta + * + * An interface that represents an accumulator. + */ +export abstract class Accumulator extends Expr { + accumulator: true = true; + + /** + * @private + * @internal + */ + abstract _toProto(serializer: JsonProtoSerializer): ProtoValue; +} + +/** + * @beta + * + * An accumulator target, which is an expression with an alias that also implements the Accumulator interface. + */ +export type AccumulatorTarget = ExprWithAlias; + /** * @beta */ -export class ExprWithAlias extends Expr implements Selectable { +export class ExprWithAlias extends Selectable { exprType: ExprType = 'ExprWithAlias'; selectable = true as const; @@ -1897,7 +1898,7 @@ class ListOfExprs extends Expr { * const cityField = Field.of("address.city"); * ``` */ -export class Field extends Expr implements Selectable { +export class Field extends Selectable { exprType: ExprType = 'Field'; selectable = true as const; @@ -1927,7 +1928,6 @@ export class Field extends Expr implements Selectable { */ static of(name: string): Field; static of(path: FieldPath): Field; - static of(pipeline: Pipeline, name: string): Field; static of( pipelineOrName: Pipeline | string | FieldPath, name?: string @@ -1974,7 +1974,7 @@ export class Field extends Expr implements Selectable { /** * @beta */ -export class Fields extends Expr implements Selectable { +export class Fields extends Selectable { exprType: ExprType = 'Field'; selectable = true as const; diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index 2e4a2f03dc3..2145952c004 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -620,7 +620,6 @@ export class Pipeline implements ProtoSerializable { * @return A new {@code Pipeline} object with this stage appended to the stage list. */ sort(...orderings: Ordering[]): Pipeline; - sort(options: { orderings: Ordering[] }): Pipeline; sort( optionsOrOrderings: | Ordering diff --git a/packages/firestore/src/util/proto.ts b/packages/firestore/src/util/proto.ts new file mode 100644 index 00000000000..a99f73cfa9c --- /dev/null +++ b/packages/firestore/src/util/proto.ts @@ -0,0 +1,155 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ArrayValue as ProtoArrayValue, + Function as ProtoFunction, + LatLng as ProtoLatLng, + MapValue as ProtoMapValue, + Pipeline as ProtoPipeline, + Timestamp as ProtoTimestamp, + Value as ProtoValue +} from '../protos/firestore_proto_api'; + +import { isPlainObject } from './input_validation'; + +/* eslint @typescript-eslint/no-explicit-any: 0 */ + +function isITimestamp(obj: any): obj is ProtoTimestamp { + if (typeof obj !== 'object' || obj === null) { + return false; // Must be a non-null object + } + if ( + 'seconds' in obj && + (obj.seconds === null || + typeof obj.seconds === 'number' || + typeof obj.seconds === 'string') && + 'nanos' in obj && + (obj.nanos === null || typeof obj.nanos === 'number') + ) { + return true; + } + + return false; +} +function isILatLng(obj: any): obj is ProtoLatLng { + if (typeof obj !== 'object' || obj === null) { + return false; // Must be a non-null object + } + if ( + 'latitude' in obj && + (obj.latitude === null || typeof obj.latitude === 'number') && + 'longitude' in obj && + (obj.longitude === null || typeof obj.longitude === 'number') + ) { + return true; + } + + return false; +} +function isIArrayValue(obj: any): obj is ProtoArrayValue { + if (typeof obj !== 'object' || obj === null) { + return false; // Must be a non-null object + } + if ('values' in obj && (obj.values === null || Array.isArray(obj.values))) { + return true; + } + + return false; +} +function isIMapValue(obj: any): obj is ProtoMapValue { + if (typeof obj !== 'object' || obj === null) { + return false; // Must be a non-null object + } + if ('fields' in obj && (obj.fields === null || isPlainObject(obj.fields))) { + return true; + } + + return false; +} +function isIFunction(obj: any): obj is ProtoFunction { + if (typeof obj !== 'object' || obj === null) { + return false; // Must be a non-null object + } + if ( + 'name' in obj && + (obj.name === null || typeof obj.name === 'string') && + 'args' in obj && + (obj.args === null || Array.isArray(obj.args)) + ) { + return true; + } + + return false; +} + +function isIPipeline(obj: any): obj is ProtoPipeline { + if (typeof obj !== 'object' || obj === null) { + return false; // Must be a non-null object + } + if ('stages' in obj && (obj.stages === null || Array.isArray(obj.stages))) { + return true; + } + + return false; +} + +export function isFirestoreValue(obj: any): obj is ProtoValue { + if (typeof obj !== 'object' || obj === null) { + return false; // Must be a non-null object + } + + // Check optional properties and their types + if ( + ('nullValue' in obj && + (obj.nullValue === null || obj.nullValue === 'NULL_VALUE')) || + ('booleanValue' in obj && + (obj.booleanValue === null || typeof obj.booleanValue === 'boolean')) || + ('integerValue' in obj && + (obj.integerValue === null || + typeof obj.integerValue === 'number' || + typeof obj.integerValue === 'string')) || + ('doubleValue' in obj && + (obj.doubleValue === null || typeof obj.doubleValue === 'number')) || + ('timestampValue' in obj && + (obj.timestampValue === null || isITimestamp(obj.timestampValue))) || + ('stringValue' in obj && + (obj.stringValue === null || typeof obj.stringValue === 'string')) || + ('bytesValue' in obj && + (obj.bytesValue === null || obj.bytesValue instanceof Uint8Array)) || + ('referenceValue' in obj && + (obj.referenceValue === null || + typeof obj.referenceValue === 'string')) || + ('geoPointValue' in obj && + (obj.geoPointValue === null || isILatLng(obj.geoPointValue))) || + ('arrayValue' in obj && + (obj.arrayValue === null || isIArrayValue(obj.arrayValue))) || + ('mapValue' in obj && + (obj.mapValue === null || isIMapValue(obj.mapValue))) || + ('fieldReferenceValue' in obj && + (obj.fieldReferenceValue === null || + typeof obj.fieldReferenceValue === 'string')) || + ('functionValue' in obj && + (obj.functionValue === null || isIFunction(obj.functionValue))) || + ('pipelineValue' in obj && + (obj.pipelineValue === null || isIPipeline(obj.pipelineValue))) + ) { + return true; + } + + return false; +} From d2291d0117c92743dea1d743cc750d78acaee869 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 27 Jan 2025 12:39:09 -0700 Subject: [PATCH 17/75] Remove console.log statements from prune-dts.ts --- repo-scripts/prune-dts/prune-dts.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/repo-scripts/prune-dts/prune-dts.ts b/repo-scripts/prune-dts/prune-dts.ts index 35a94b3fae1..6c426924a4e 100644 --- a/repo-scripts/prune-dts/prune-dts.ts +++ b/repo-scripts/prune-dts/prune-dts.ts @@ -527,7 +527,6 @@ function findExternalExport( // implementation currently does not handle function exports, // which is the only place we expect name collisions. if (symbol.name === localSymbolName) { - console.log(`===== removing external export ${symbol.name}`) return otherExportSourceFile; } } @@ -586,8 +585,6 @@ function dropPrivateApiTransformer( // Remove any types that are exported externally const externalExportFile = findExternalExport(typeChecker, sourceFile, node, otherExportSourceFiles); if (externalExportFile && node.name) { - console.log(`==== sourceFile.filename ${sourceFile.fileName}`) - console.log(`==== externalExportFile.filename ${externalExportFile.fileName}`) ensureImportsForFile(path.relative(path.dirname(sourceFile.fileName), externalExportFile.fileName)).push(node.name.text); return ts.factory.createNotEmittedStatement(node); } From f44ea4da9e727e0b2bae962cc78a407d5a2ebb37 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 27 Jan 2025 12:56:06 -0700 Subject: [PATCH 18/75] code cleanup in prune-dts --- repo-scripts/prune-dts/extract-public-api.ts | 6 +- repo-scripts/prune-dts/prune-dts.ts | 71 +++++++++++++++----- 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/repo-scripts/prune-dts/extract-public-api.ts b/repo-scripts/prune-dts/extract-public-api.ts index aa25ba3fc57..4e3c0c3c1fc 100644 --- a/repo-scripts/prune-dts/extract-public-api.ts +++ b/repo-scripts/prune-dts/extract-public-api.ts @@ -240,5 +240,9 @@ void generateApi( path.resolve(argv.rollupDts), path.resolve(argv.untrimmedRollupDts), path.resolve(argv.publicDts), - argv.otherExportsPublicDtsFiles ? argv.otherExportsPublicDtsFiles.split(',').map(filePath => path.resolve(filePath)) : [] + argv.otherExportsPublicDtsFiles + ? argv.otherExportsPublicDtsFiles + .split(',') + .map(filePath => path.resolve(filePath)) + : [] ); diff --git a/repo-scripts/prune-dts/prune-dts.ts b/repo-scripts/prune-dts/prune-dts.ts index 6c426924a4e..087d12a3d4b 100644 --- a/repo-scripts/prune-dts/prune-dts.ts +++ b/repo-scripts/prune-dts/prune-dts.ts @@ -34,17 +34,32 @@ import { ESLint } from 'eslint'; * @param inputLocation The file path to the .d.ts produced by API explorer. * @param outputLocation The output location for the pruned .d.ts file. */ -export function pruneDts(inputLocation: string, outputLocation: string, otherExportFileLocations: string[] = []): void { +export function pruneDts( + inputLocation: string, + outputLocation: string, + otherExportFileLocations: string[] = [] +): void { const compilerOptions = {}; const host = ts.createCompilerHost(compilerOptions); - const program = ts.createProgram([inputLocation, ...otherExportFileLocations], compilerOptions, host); + const program = ts.createProgram( + [inputLocation, ...otherExportFileLocations], + compilerOptions, + host + ); const printer: ts.Printer = ts.createPrinter(); const sourceFile = program.getSourceFile(inputLocation)!; - const otherExportSourceFiles = otherExportFileLocations.map(otherFileLocation => program.getSourceFile(otherFileLocation)).filter(value => value !== undefined) as ts.SourceFile[]; + const otherExportSourceFiles = otherExportFileLocations + .map(otherFileLocation => program.getSourceFile(otherFileLocation)) + .filter(value => value !== undefined) as ts.SourceFile[]; const result: ts.TransformationResult = ts.transform(sourceFile, [ - dropPrivateApiTransformer.bind(null, program, host, otherExportSourceFiles ) + dropPrivateApiTransformer.bind( + null, + program, + host, + otherExportSourceFiles + ) ]); const transformedSourceFile: ts.SourceFile = result.transformed[0]; let content = printer.printFile(transformedSourceFile); @@ -424,7 +439,7 @@ function extractJSDocComment( function extractExportedSymbol( typeChecker: ts.TypeChecker, sourceFile: ts.SourceFile, - typeName: ts.Node, + typeName: ts.Node ): ts.Symbol | undefined { if (!ts.isIdentifier(typeName)) { return undefined; @@ -508,7 +523,11 @@ function extractExportedSymbol( function findExternalExport( typeChecker: ts.TypeChecker, sourceFile: ts.SourceFile, - node: ts.InterfaceDeclaration | ts.ClassDeclaration | ts.TypeAliasDeclaration | ts.EnumDeclaration, + node: + | ts.InterfaceDeclaration + | ts.ClassDeclaration + | ts.TypeAliasDeclaration + | ts.EnumDeclaration, otherExportSourceFiles: ts.SourceFile[] ): ts.SourceFile | undefined { if (!node.name) return undefined; @@ -516,7 +535,6 @@ function findExternalExport( const localSymbolName = node.name.text; for (const otherExportSourceFile of otherExportSourceFiles) { - const otherExportedSymbols = typeChecker.getExportsOfModule( typeChecker.getSymbolAtLocation(otherExportSourceFile)! ); @@ -539,8 +557,7 @@ function dropPrivateApiTransformer( program: ts.Program, host: ts.CompilerHost, otherExportSourceFiles: ts.SourceFile[], - context: ts.TransformationContext, - + context: ts.TransformationContext ): ts.Transformer { const typeChecker = program.getTypeChecker(); @@ -583,9 +600,19 @@ function dropPrivateApiTransformer( ts.isEnumDeclaration(node) ) { // Remove any types that are exported externally - const externalExportFile = findExternalExport(typeChecker, sourceFile, node, otherExportSourceFiles); + const externalExportFile = findExternalExport( + typeChecker, + sourceFile, + node, + otherExportSourceFiles + ); if (externalExportFile && node.name) { - ensureImportsForFile(path.relative(path.dirname(sourceFile.fileName), externalExportFile.fileName)).push(node.name.text); + ensureImportsForFile( + path.relative( + path.dirname(sourceFile.fileName), + externalExportFile.fileName + ) + ).push(node.name.text); return ts.factory.createNotEmittedStatement(node); } } @@ -645,20 +672,34 @@ function dropPrivateApiTransformer( for (let filename in imports) { const importSpecifiers: ts.ImportSpecifier[] = []; for (let identifier of imports[filename]) { - importSpecifiers.push(ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier(identifier))); + importSpecifiers.push( + ts.factory.createImportSpecifier( + false, + undefined, + ts.factory.createIdentifier(identifier) + ) + ); } let outFileName = filename.startsWith('.') ? filename : `./${filename}`; outFileName = outFileName.replace('.d.ts', ''); const importDeclaration = ts.factory.createImportDeclaration( [], - ts.factory.createImportClause(true, undefined, ts.factory.createNamedImports(importSpecifiers)), + ts.factory.createImportClause( + true, + undefined, + ts.factory.createNamedImports(importSpecifiers) + ), ts.factory.createStringLiteral(outFileName, true) - ) + ); moreImports.push(importDeclaration); } - return ts.factory.updateSourceFile(result, [...moreImports, ...result.statements], true); + return ts.factory.updateSourceFile( + result, + [...moreImports, ...result.statements], + true + ); }; } From 16cfd2494b39f2a383f23b0009aab31d0be92dff Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 27 Jan 2025 13:10:33 -0700 Subject: [PATCH 19/75] Add missing imports to pipelines.ts --- packages/firestore/lite/pipelines/pipelines.ts | 3 ++- packages/firestore/pipelines/pipelines.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index 1c32c4939e8..d3e31f5e52b 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -44,7 +44,8 @@ export type { SetOptions, QueryDocumentSnapshot, Primitive, - FieldValue + FieldValue, + Bytes } from '../index'; export { PipelineSource } from '../../src/lite-api/pipeline-source'; diff --git a/packages/firestore/pipelines/pipelines.ts b/packages/firestore/pipelines/pipelines.ts index 478535e2a16..b056059adf4 100644 --- a/packages/firestore/pipelines/pipelines.ts +++ b/packages/firestore/pipelines/pipelines.ts @@ -44,7 +44,8 @@ export type { SnapshotOptions, Primitive, FieldValue, - SnapshotMetadata + SnapshotMetadata, + Bytes } from '../src/api'; export * from '../src/api_pipelines'; From 7d6aec1aabc27bfb5f48a736b7b31bbcd7fb25a2 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:58:10 -0700 Subject: [PATCH 20/75] If argument to FunctionExpr is a plain object or array, convert these to expression using map(...) or array(...) --- packages/firestore/src/core/pipeline-util.ts | 41 ++- .../firestore/src/lite-api/expressions.ts | 274 ++++++++---------- packages/firestore/src/lite-api/pipeline.ts | 6 - .../src/lite-api/user_data_reader.ts | 8 +- 4 files changed, 163 insertions(+), 166 deletions(-) diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index 0800eba85ea..8f584db30bb 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -76,34 +76,55 @@ export function toPipelineFilterCondition(f: FilterInternal): FilterCondition { const value = f.value; switch (f.op) { case Operator.LESS_THAN: - return andFunction(field.exists(), field.lt(value)); + return andFunction( + field.exists(), + field.lt(Constant._fromProto(value)) + ); case Operator.LESS_THAN_OR_EQUAL: - return andFunction(field.exists(), field.lte(value)); + return andFunction( + field.exists(), + field.lte(Constant._fromProto(value)) + ); case Operator.GREATER_THAN: - return andFunction(field.exists(), field.gt(value)); + return andFunction( + field.exists(), + field.gt(Constant._fromProto(value)) + ); case Operator.GREATER_THAN_OR_EQUAL: - return andFunction(field.exists(), field.gte(value)); + return andFunction( + field.exists(), + field.gte(Constant._fromProto(value)) + ); case Operator.EQUAL: - return andFunction(field.exists(), field.eq(value)); + return andFunction( + field.exists(), + field.eq(Constant._fromProto(value)) + ); case Operator.NOT_EQUAL: - return andFunction(field.exists(), field.neq(value)); + return andFunction( + field.exists(), + field.neq(Constant._fromProto(value)) + ); case Operator.ARRAY_CONTAINS: - return andFunction(field.exists(), field.arrayContains(value)); + return andFunction( + field.exists(), + field.arrayContains(Constant._fromProto(value)) + ); case Operator.IN: { const values = value?.arrayValue?.values?.map((val: any) => - Constant.of(val) + Constant._fromProto(val) ); return andFunction(field.exists(), field.eqAny(...values!)); } case Operator.ARRAY_CONTAINS_ANY: { const values = value?.arrayValue?.values?.map((val: any) => - Constant.of(val) + Constant._fromProto(val) ); return andFunction(field.exists(), field.arrayContainsAny(values!)); } case Operator.NOT_IN: { const values = value?.arrayValue?.values?.map((val: any) => - Constant.of(val) + Constant._fromProto(val) ); return andFunction(field.exists(), not(field.eqAny(...values!))); } diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 03e5c5e747e..bd8f84b718e 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -29,6 +29,7 @@ import { UserData } from '../remote/serializer'; import { hardAssert } from '../util/assert'; +import { isPlainObject } from '../util/input_validation'; import { isFirestoreValue } from '../util/proto'; import { Bytes } from './bytes'; @@ -57,6 +58,26 @@ export type ExprType = | 'ListOfExprs' | 'ExprWithAlias'; +/** + * Converts a value to an Expr, Returning either a Constant, MapFunction, + * ArrayFunction, or the input itself (if it's already an expression). + * + * @private + * @internal + * @param value + */ +function valueToDefaultExpr(value: unknown): Expr { + if (value instanceof Expr) { + return value; + } else if (isPlainObject(value)) { + return map(value); + } else if (value instanceof Array) { + return array(value); + } else { + return Constant.of(value); + } +} + /** * @beta * @@ -85,28 +106,25 @@ export abstract class Expr implements ProtoSerializable, UserData { * Field.of("quantity").add(Field.of("reserve")); * ``` * - * @param other The expression to add to this expression. + * @param expression The expression to add to this expression. * @return A new `Expr` representing the addition operation. */ - add(other: Expr): Add; + add(expression: Expr): Add; /** - * Creates an expression that adds this expression to a constant value. + * Creates an expression that adds this expression to another expression or constant value. * * ```typescript * // Add 5 to the value of the 'age' field * Field.of("age").add(5); * ``` * - * @param other The constant value to add. + * @param value The constant value to add. * @return A new `Expr` representing the addition operation. */ - add(other: any): Add; - add(other: any): Add { - if (other instanceof Expr) { - return new Add(this, other); - } - return new Add(this, Constant.of(other)); + add(value: any): Add; + add(other: Expr | any): Add { + return new Add(this, valueToDefaultExpr(other)); } /** @@ -135,10 +153,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ subtract(other: any): Subtract; subtract(other: any): Subtract { - if (other instanceof Expr) { - return new Subtract(this, other); - } - return new Subtract(this, Constant.of(other)); + return new Subtract(this, valueToDefaultExpr(other)); } /** @@ -167,10 +182,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ multiply(other: any): Multiply; multiply(other: any): Multiply { - if (other instanceof Expr) { - return new Multiply(this, other); - } - return new Multiply(this, Constant.of(other)); + return new Multiply(this, valueToDefaultExpr(other)); } /** @@ -199,10 +211,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ divide(other: any): Divide; divide(other: any): Divide { - if (other instanceof Expr) { - return new Divide(this, other); - } - return new Divide(this, Constant.of(other)); + return new Divide(this, valueToDefaultExpr(other)); } /** @@ -231,10 +240,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ mod(other: any): Mod; mod(other: any): Mod { - if (other instanceof Expr) { - return new Mod(this, other); - } - return new Mod(this, Constant.of(other)); + return new Mod(this, valueToDefaultExpr(other)); } // /** @@ -437,10 +443,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ eq(other: any): Eq; eq(other: any): Eq { - if (other instanceof Expr) { - return new Eq(this, other); - } - return new Eq(this, Constant.of(other)); + return new Eq(this, valueToDefaultExpr(other)); } /** @@ -469,10 +472,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ neq(other: any): Neq; neq(other: any): Neq { - if (other instanceof Expr) { - return new Neq(this, other); - } - return new Neq(this, Constant.of(other)); + return new Neq(this, valueToDefaultExpr(other)); } /** @@ -501,10 +501,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ lt(other: any): Lt; lt(other: any): Lt { - if (other instanceof Expr) { - return new Lt(this, other); - } - return new Lt(this, Constant.of(other)); + return new Lt(this, valueToDefaultExpr(other)); } /** @@ -534,10 +531,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ lte(other: any): Lte; lte(other: any): Lte { - if (other instanceof Expr) { - return new Lte(this, other); - } - return new Lte(this, Constant.of(other)); + return new Lte(this, valueToDefaultExpr(other)); } /** @@ -566,10 +560,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ gt(other: any): Gt; gt(other: any): Gt { - if (other instanceof Expr) { - return new Gt(this, other); - } - return new Gt(this, Constant.of(other)); + return new Gt(this, valueToDefaultExpr(other)); } /** @@ -600,10 +591,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ gte(other: any): Gte; gte(other: any): Gte { - if (other instanceof Expr) { - return new Gte(this, other); - } - return new Gte(this, Constant.of(other)); + return new Gte(this, valueToDefaultExpr(other)); } /** @@ -633,7 +621,7 @@ export abstract class Expr implements ProtoSerializable, UserData { arrayConcat(...arrays: any[][]): ArrayConcat; arrayConcat(...arrays: any[]): ArrayConcat { const exprValues = arrays.map(value => - value instanceof Expr ? value : Constant.of(value) + value instanceof Expr ? value : valueToDefaultExpr(value) ); return new ArrayConcat(this, exprValues); } @@ -664,10 +652,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ arrayContains(element: any): ArrayContains; arrayContains(element: any): ArrayContains { - if (element instanceof Expr) { - return new ArrayContains(this, element); - } - return new ArrayContains(this, Constant.of(element)); + return new ArrayContains(this, valueToDefaultExpr(element)); } /** @@ -697,7 +682,7 @@ export abstract class Expr implements ProtoSerializable, UserData { arrayContainsAll(...values: any[]): ArrayContainsAll; arrayContainsAll(...values: any[]): ArrayContainsAll { const exprValues = values.map(value => - value instanceof Expr ? value : Constant.of(value) + value instanceof Expr ? value : valueToDefaultExpr(value) ); return new ArrayContainsAll(this, exprValues); } @@ -730,7 +715,7 @@ export abstract class Expr implements ProtoSerializable, UserData { arrayContainsAny(...values: any[]): ArrayContainsAny; arrayContainsAny(...values: any[]): ArrayContainsAny { const exprValues = values.map(value => - value instanceof Expr ? value : Constant.of(value) + value instanceof Expr ? value : valueToDefaultExpr(value) ); return new ArrayContainsAny(this, exprValues); } @@ -778,7 +763,7 @@ export abstract class Expr implements ProtoSerializable, UserData { eqAny(...others: any[]): EqAny; eqAny(...others: any[]): EqAny { const exprOthers = others.map(other => - other instanceof Expr ? other : Constant.of(other) + other instanceof Expr ? other : valueToDefaultExpr(other) ); return new EqAny(this, exprOthers); } @@ -812,7 +797,7 @@ export abstract class Expr implements ProtoSerializable, UserData { notEqAny(...others: any[]): NotEqAny; notEqAny(...others: any[]): NotEqAny { const exprOthers = others.map(other => - other instanceof Expr ? other : Constant.of(other) + other instanceof Expr ? other : valueToDefaultExpr(other) ); return new NotEqAny(this, exprOthers); } @@ -1334,10 +1319,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ logicalMaximum(other: any): LogicalMaximum; logicalMaximum(other: any): LogicalMaximum { - if (other instanceof Expr) { - return new LogicalMaximum(this, other as Expr); - } - return new LogicalMaximum(this, Constant.of(other)); + return new LogicalMaximum(this, valueToDefaultExpr(other)); } /** @@ -1366,10 +1348,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ logicalMinimum(other: any): LogicalMinimum; logicalMinimum(other: any): LogicalMinimum { - if (other instanceof Expr) { - return new LogicalMinimum(this, other as Expr); - } - return new LogicalMinimum(this, Constant.of(other)); + return new LogicalMinimum(this, valueToDefaultExpr(other)); } /** @@ -1972,50 +1951,6 @@ export class Field extends Selectable { _readUserData(dataReader: UserDataReader): void {} } -/** - * @beta - */ -export class Fields extends Selectable { - exprType: ExprType = 'Field'; - selectable = true as const; - - private constructor(private fields: Field[]) { - super(); - } - - static of(name: string, ...others: string[]): Fields { - return new Fields([Field.of(name), ...others.map(Field.of)]); - } - - static ofAll(): Fields { - return new Fields([]); - } - - fieldList(): Field[] { - return this.fields.map(f => f); - } - - /** - * @private - * @internal - */ - _toProto(serializer: JsonProtoSerializer): ProtoValue { - return { - arrayValue: { - values: this.fields.map(f => f._toProto(serializer)) - } - }; - } - - /** - * @private - * @internal - */ - _readUserData(dataReader: UserDataReader): void { - this.fields.forEach(expr => expr._readUserData(dataReader)); - } -} - /** * @beta * @@ -2211,10 +2146,8 @@ export class Constant extends Expr { 'Constant.of' ); - if (isFirestoreValue(this.value)) { - // Special case where value is a proto value. - // This can occur when converting a Query to Pipeline. - this._protoValue = this.value; + if (isFirestoreValue(this._protoValue)) { + return; } else if (this.value === undefined) { // TODO(pipeline) how should we treat the value of `undefined`? this._protoValue = parseData(null, context)!; @@ -2306,6 +2239,18 @@ export class Mod extends FirestoreFunction { } } +export class MapFunction extends FirestoreFunction { + constructor(private elements: Expr[]) { + super('map', elements); + } +} + +export class ArrayFunction extends FirestoreFunction { + constructor(private elements: Expr[]) { + super('array', elements); + } +} + // /** // * @beta // */ @@ -3007,7 +2952,8 @@ export function add(left: string, right: Expr): Add; export function add(left: string, right: any): Add; export function add(left: Expr | string, right: Expr | any): Add { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = right instanceof Expr ? right : Constant.of(right); + const normalizedRight = + right instanceof Expr ? right : valueToDefaultExpr(right); return new Add(normalizedLeft, normalizedRight); } @@ -3076,7 +3022,8 @@ export function subtract(left: string, right: Expr): Subtract; export function subtract(left: string, right: any): Subtract; export function subtract(left: Expr | string, right: Expr | any): Subtract { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = right instanceof Expr ? right : Constant.of(right); + const normalizedRight = + right instanceof Expr ? right : valueToDefaultExpr(right); return new Subtract(normalizedLeft, normalizedRight); } @@ -3145,7 +3092,8 @@ export function multiply(left: string, right: Expr): Multiply; export function multiply(left: string, right: any): Multiply; export function multiply(left: Expr | string, right: Expr | any): Multiply { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = right instanceof Expr ? right : Constant.of(right); + const normalizedRight = + right instanceof Expr ? right : valueToDefaultExpr(right); return new Multiply(normalizedLeft, normalizedRight); } @@ -3214,7 +3162,8 @@ export function divide(left: string, right: Expr): Divide; export function divide(left: string, right: any): Divide; export function divide(left: Expr | string, right: Expr | any): Divide { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = right instanceof Expr ? right : Constant.of(right); + const normalizedRight = + right instanceof Expr ? right : valueToDefaultExpr(right); return new Divide(normalizedLeft, normalizedRight); } @@ -3283,10 +3232,29 @@ export function mod(left: string, right: Expr): Mod; export function mod(left: string, right: any): Mod; export function mod(left: Expr | string, right: Expr | any): Mod { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = right instanceof Expr ? right : Constant.of(right); + const normalizedRight = + right instanceof Expr ? right : valueToDefaultExpr(right); return new Mod(normalizedLeft, normalizedRight); } +export function map(elements: Record): MapFunction { + const result: any[] = []; + for (const key in elements) { + if (Object.prototype.hasOwnProperty.call(elements, key)) { + const value = elements[key]; + result.push(Constant.of(key)); + result.push(valueToDefaultExpr(value)); + } + } + return new MapFunction(result); +} + +export function array(elements: any[]): ArrayFunction { + return new ArrayFunction( + elements.map(element => valueToDefaultExpr(element)) + ); +} + // /** // * @beta // * @@ -3352,7 +3320,7 @@ export function mod(left: Expr | string, right: Expr | any): Mod { // export function bitAnd(left: string, right: any): BitAnd; // export function bitAnd(left: Expr | string, right: Expr | any): BitAnd { // const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; -// const normalizedRight = right instanceof Expr ? right : Constant.of(right); +// const normalizedRight = right instanceof Expr ? right : valueToDefaultExpr(right); // return new BitAnd(normalizedLeft, normalizedRight); // } // @@ -3421,7 +3389,7 @@ export function mod(left: Expr | string, right: Expr | any): Mod { // export function bitOr(left: string, right: any): BitOr; // export function bitOr(left: Expr | string, right: Expr | any): BitOr { // const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; -// const normalizedRight = right instanceof Expr ? right : Constant.of(right); +// const normalizedRight = right instanceof Expr ? right : valueToDefaultExpr(right); // return new BitOr(normalizedLeft, normalizedRight); // } // @@ -3490,7 +3458,7 @@ export function mod(left: Expr | string, right: Expr | any): Mod { // export function bitXor(left: string, right: any): BitXor; // export function bitXor(left: Expr | string, right: Expr | any): BitXor { // const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; -// const normalizedRight = right instanceof Expr ? right : Constant.of(right); +// const normalizedRight = right instanceof Expr ? right : valueToDefaultExpr(right); // return new BitXor(normalizedLeft, normalizedRight); // } // @@ -3597,7 +3565,7 @@ export function mod(left: Expr | string, right: Expr | any): Mod { // right: Expr | any // ): BitLeftShift { // const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; -// const normalizedRight = right instanceof Expr ? right : Constant.of(right); +// const normalizedRight = right instanceof Expr ? right : valueToDefaultExpr(right); // return new BitLeftShift(normalizedLeft, normalizedRight); // } // @@ -3669,7 +3637,7 @@ export function mod(left: Expr | string, right: Expr | any): Mod { // right: Expr | any // ): BitRightShift { // const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; -// const normalizedRight = right instanceof Expr ? right : Constant.of(right); +// const normalizedRight = right instanceof Expr ? right : valueToDefaultExpr(right); // return new BitRightShift(normalizedLeft, normalizedRight); // } @@ -3738,7 +3706,7 @@ export function eq(left: string, right: Expr): Eq; export function eq(left: string, right: any): Eq; export function eq(left: Expr | string, right: any): Eq { const leftExpr = left instanceof Expr ? left : Field.of(left); - const rightExpr = right instanceof Expr ? right : Constant.of(right); + const rightExpr = right instanceof Expr ? right : valueToDefaultExpr(right); return new Eq(leftExpr, rightExpr); } @@ -3807,7 +3775,7 @@ export function neq(left: string, right: Expr): Neq; export function neq(left: string, right: any): Neq; export function neq(left: Expr | string, right: any): Neq { const leftExpr = left instanceof Expr ? left : Field.of(left); - const rightExpr = right instanceof Expr ? right : Constant.of(right); + const rightExpr = right instanceof Expr ? right : valueToDefaultExpr(right); return new Neq(leftExpr, rightExpr); } @@ -3876,7 +3844,7 @@ export function lt(left: string, right: Expr): Lt; export function lt(left: string, right: any): Lt; export function lt(left: Expr | string, right: any): Lt { const leftExpr = left instanceof Expr ? left : Field.of(left); - const rightExpr = right instanceof Expr ? right : Constant.of(right); + const rightExpr = right instanceof Expr ? right : valueToDefaultExpr(right); return new Lt(leftExpr, rightExpr); } @@ -3944,7 +3912,7 @@ export function lte(left: string, right: Expr): Lte; export function lte(left: string, right: any): Lte; export function lte(left: Expr | string, right: any): Lte { const leftExpr = left instanceof Expr ? left : Field.of(left); - const rightExpr = right instanceof Expr ? right : Constant.of(right); + const rightExpr = right instanceof Expr ? right : valueToDefaultExpr(right); return new Lte(leftExpr, rightExpr); } @@ -4014,7 +3982,7 @@ export function gt(left: string, right: Expr): Gt; export function gt(left: string, right: any): Gt; export function gt(left: Expr | string, right: any): Gt { const leftExpr = left instanceof Expr ? left : Field.of(left); - const rightExpr = right instanceof Expr ? right : Constant.of(right); + const rightExpr = right instanceof Expr ? right : valueToDefaultExpr(right); return new Gt(leftExpr, rightExpr); } @@ -4086,7 +4054,7 @@ export function gte(left: string, right: Expr): Gte; export function gte(left: string, right: any): Gte; export function gte(left: Expr | string, right: any): Gte { const leftExpr = left instanceof Expr ? left : Field.of(left); - const rightExpr = right instanceof Expr ? right : Constant.of(right); + const rightExpr = right instanceof Expr ? right : valueToDefaultExpr(right); return new Gte(leftExpr, rightExpr); } @@ -4159,7 +4127,7 @@ export function arrayConcat( ): ArrayConcat { const arrayExpr = array instanceof Expr ? array : Field.of(array); const exprValues = elements.map(element => - element instanceof Expr ? element : Constant.of(element) + element instanceof Expr ? element : valueToDefaultExpr(element) ); return new ArrayConcat(arrayExpr, exprValues); } @@ -4232,7 +4200,8 @@ export function arrayContains( element: any ): ArrayContains { const arrayExpr = array instanceof Expr ? array : Field.of(array); - const elementExpr = element instanceof Expr ? element : Constant.of(element); + const elementExpr = + element instanceof Expr ? element : valueToDefaultExpr(element); return new ArrayContains(arrayExpr, elementExpr); } @@ -4317,7 +4286,7 @@ export function arrayContainsAny( ): ArrayContainsAny { const arrayExpr = array instanceof Expr ? array : Field.of(array); const exprValues = values.map(value => - value instanceof Expr ? value : Constant.of(value) + value instanceof Expr ? value : valueToDefaultExpr(value) ); return new ArrayContainsAny(arrayExpr, exprValues); } @@ -4399,7 +4368,7 @@ export function arrayContainsAll( ): ArrayContainsAll { const arrayExpr = array instanceof Expr ? array : Field.of(array); const exprValues = values.map(value => - value instanceof Expr ? value : Constant.of(value) + value instanceof Expr ? value : valueToDefaultExpr(value) ); return new ArrayContainsAll(arrayExpr, exprValues); } @@ -4491,7 +4460,7 @@ export function eqAny(element: string, others: any[]): EqAny; export function eqAny(element: Expr | string, others: any[]): EqAny { const elementExpr = element instanceof Expr ? element : Field.of(element); const exprOthers = others.map(other => - other instanceof Expr ? other : Constant.of(other) + other instanceof Expr ? other : valueToDefaultExpr(other) ); return new EqAny(elementExpr, exprOthers); } @@ -4566,7 +4535,7 @@ export function notEqAny(element: string, others: any[]): NotEqAny; export function notEqAny(element: Expr | string, others: any[]): NotEqAny { const elementExpr = element instanceof Expr ? element : Field.of(element); const exprOthers = others.map(other => - other instanceof Expr ? other : Constant.of(other) + other instanceof Expr ? other : valueToDefaultExpr(other) ); return new NotEqAny(elementExpr, exprOthers); } @@ -4704,7 +4673,8 @@ export function logicalMaximum( right: Expr | any ): LogicalMaximum { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = right instanceof Expr ? right : Constant.of(right); + const normalizedRight = + right instanceof Expr ? right : valueToDefaultExpr(right); return new LogicalMaximum(normalizedLeft, normalizedRight); } @@ -4776,7 +4746,8 @@ export function logicalMinimum( right: Expr | any ): LogicalMinimum { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = right instanceof Expr ? right : Constant.of(right); + const normalizedRight = + right instanceof Expr ? right : valueToDefaultExpr(right); return new LogicalMinimum(normalizedLeft, normalizedRight); } @@ -5164,7 +5135,8 @@ export function like(left: Expr, pattern: string): Like; export function like(left: Expr, pattern: Expr): Like; export function like(left: Expr | string, pattern: Expr | string): Like { const leftExpr = left instanceof Expr ? left : Field.of(left); - const patternExpr = pattern instanceof Expr ? pattern : Constant.of(pattern); + const patternExpr = + pattern instanceof Expr ? pattern : valueToDefaultExpr(pattern); return new Like(leftExpr, patternExpr); } @@ -5240,7 +5212,8 @@ export function regexContains( pattern: Expr | string ): RegexContains { const leftExpr = left instanceof Expr ? left : Field.of(left); - const patternExpr = pattern instanceof Expr ? pattern : Constant.of(pattern); + const patternExpr = + pattern instanceof Expr ? pattern : valueToDefaultExpr(pattern); return new RegexContains(leftExpr, patternExpr); } @@ -5314,7 +5287,8 @@ export function regexMatch( pattern: Expr | string ): RegexMatch { const leftExpr = left instanceof Expr ? left : Field.of(left); - const patternExpr = pattern instanceof Expr ? pattern : Constant.of(pattern); + const patternExpr = + pattern instanceof Expr ? pattern : valueToDefaultExpr(pattern); return new RegexMatch(leftExpr, patternExpr); } @@ -5387,7 +5361,7 @@ export function strContains( ): StrContains { const leftExpr = left instanceof Expr ? left : Field.of(left); const substringExpr = - substring instanceof Expr ? substring : Constant.of(substring); + substring instanceof Expr ? substring : valueToDefaultExpr(substring); return new StrContains(leftExpr, substringExpr); } @@ -5459,7 +5433,8 @@ export function startsWith( prefix: Expr | string ): StartsWith { const exprLeft = expr instanceof Expr ? expr : Field.of(expr); - const prefixExpr = prefix instanceof Expr ? prefix : Constant.of(prefix); + const prefixExpr = + prefix instanceof Expr ? prefix : valueToDefaultExpr(prefix); return new StartsWith(exprLeft, prefixExpr); } @@ -5528,7 +5503,8 @@ export function endsWith(expr: Expr, suffix: string): EndsWith; export function endsWith(expr: Expr, suffix: Expr): EndsWith; export function endsWith(expr: Expr | string, suffix: Expr | string): EndsWith { const exprLeft = expr instanceof Expr ? expr : Field.of(expr); - const suffixExpr = suffix instanceof Expr ? suffix : Constant.of(suffix); + const suffixExpr = + suffix instanceof Expr ? suffix : valueToDefaultExpr(suffix); return new EndsWith(exprLeft, suffixExpr); } @@ -5671,7 +5647,9 @@ export function strConcat( first: string | Expr, ...elements: Array ): StrConcat { - const exprs = elements.map(e => (e instanceof Expr ? e : Constant.of(e))); + const exprs = elements.map(e => + e instanceof Expr ? e : valueToDefaultExpr(e) + ); return new StrConcat(first instanceof Expr ? first : Field.of(first), exprs); } @@ -6565,7 +6543,7 @@ export function timestampAdd( ): TimestampAdd { const normalizedTimestamp = typeof timestamp === 'string' ? Field.of(timestamp) : timestamp; - const normalizedUnit = unit instanceof Expr ? unit : Constant.of(unit); + const normalizedUnit = unit instanceof Expr ? unit : valueToDefaultExpr(unit); const normalizedAmount = typeof amount === 'number' ? Constant.of(amount) : amount; return new TimestampAdd( @@ -6651,7 +6629,7 @@ export function timestampSub( ): TimestampSub { const normalizedTimestamp = typeof timestamp === 'string' ? Field.of(timestamp) : timestamp; - const normalizedUnit = unit instanceof Expr ? unit : Constant.of(unit); + const normalizedUnit = unit instanceof Expr ? unit : valueToDefaultExpr(unit); const normalizedAmount = typeof amount === 'number' ? Constant.of(amount) : amount; return new TimestampSub( diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index 2145952c004..c040139aac2 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -38,7 +38,6 @@ import { Expr, ExprWithAlias, Field, - Fields, FilterCondition, Ordering, Selectable @@ -238,11 +237,6 @@ export class Pipeline implements ProtoSerializable { result.set(selectable as string, Field.of(selectable)); } else if (selectable instanceof Field) { result.set((selectable as Field).fieldName(), selectable); - } else if (selectable instanceof Fields) { - const fields = selectable as Fields; - for (const field of fields.fieldList()) { - result.set(field.fieldName(), field); - } } else if (selectable instanceof ExprWithAlias) { const expr = selectable as ExprWithAlias; result.set(expr.alias, expr.expr); diff --git a/packages/firestore/src/lite-api/user_data_reader.ts b/packages/firestore/src/lite-api/user_data_reader.ts index 42f905d5cab..7d24482c95e 100644 --- a/packages/firestore/src/lite-api/user_data_reader.ts +++ b/packages/firestore/src/lite-api/user_data_reader.ts @@ -65,6 +65,7 @@ import { Dict, forEach, isEmpty } from '../util/obj'; import { Bytes } from './bytes'; import { Firestore } from './database'; +import { Expr } from './expressions'; import { FieldPath } from './field_path'; import { FieldValue } from './field_value'; import { GeoPoint } from './geo_point'; @@ -909,6 +910,8 @@ export function parseScalarValue( }; } else if (value instanceof VectorValue) { return parseVectorValue(value, context); + } else if (value instanceof Expr) { + return value._toProto(context.serializer); } else { throw context.createError( `Unsupported field value: ${valueDescription(value)}` @@ -955,7 +958,7 @@ export function parseVectorValue( * GeoPoints, etc. are not considered to look like JSON objects since they map * to specific FieldValue types other than ObjectValue. */ -function looksLikeJsonObject(input: unknown): boolean { +export function looksLikeJsonObject(input: unknown): boolean { return ( typeof input === 'object' && input !== null && @@ -966,7 +969,8 @@ function looksLikeJsonObject(input: unknown): boolean { !(input instanceof Bytes) && !(input instanceof DocumentReference) && !(input instanceof FieldValue) && - !(input instanceof VectorValue) + !(input instanceof VectorValue) && + !(input instanceof Expr) ); } From e923dfdf7bd974da808b1db599529d5dcf9a6ef5 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:59:22 -0700 Subject: [PATCH 21/75] Add tests for evaluating expressions in arrays and maps --- .../test/integration/api/pipeline.test.ts | 171 ++++++++++++++++-- 1 file changed, 156 insertions(+), 15 deletions(-) diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 48441c26065..a890ab7346d 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -19,6 +19,7 @@ import { expect, use } from 'chai'; import chaiAsPromised from 'chai-as-promised'; import { Bytes, vector } from '../../../src/api'; +import { array, map } from '../../../src/lite-api/expressions'; import { GeoPoint } from '../../../src/lite-api/geo_point'; import { Timestamp } from '../../../src/lite-api/timestamp'; import { addEqualityMatcher } from '../../util/equality_matcher'; @@ -79,7 +80,8 @@ import { and, documentId, addDoc, - getDoc + getDoc, + multiply } from '../util/firebase_export'; import { apiDescribe, @@ -283,6 +285,142 @@ apiDescribe.only('Pipelines', persistence => { expect(result.length).to.equal(10); }); + it('evaluates expression in map', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .addFields( + map({ + genre: Field.of('genre'), + rating: Field.of('rating').multiply(10) + }).as('metadata') + ) + .execute(); + + expect(result.length).to.equal(1); + expectResults(result, { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + genre: 'Fantasy', + published: 1954, + rating: 4.7, + tags: ['adventure', 'magic', 'epic'], + awards: { hugo: false, nebula: false }, + metadata: { + genre: 'Fantasy', + rating: 47 + } + }); + }); + + it('evaluates expression in array', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .addFields( + array([1, 2, Field.of('genre'), multiply('rating', 10)]).as( + 'metadata' + ) + ) + .execute(); + expect(result.length).to.equal(1); + expectResults(result, { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + genre: 'Fantasy', + published: 1954, + rating: 4.7, + tags: ['adventure', 'magic', 'epic'], + awards: { hugo: false, nebula: false }, + metadata: [1, 2, 'Fantasy', 47] + }); + }); + + it('converts arrays and plain objects to functionValues if the customer intent is unspecified', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .addFields( + array([ + 1, + 2, + Field.of('genre'), + multiply('rating', 10), + [Field.of('title')], + { + published: Field.of('published') + } + ]).as('metadataArray'), + map({ + genre: Field.of('genre'), + rating: multiply('rating', 10), + nestedArray: [Field.of('title')], + nestedMap: { + published: Field.of('published') + } + }).as('metadata') + ) + .where( + andFunction( + eq('metadataArray', [ + 1, + 2, + Field.of('genre'), + multiply('rating', 10), + [Field.of('title')], + { + published: Field.of('published') + } + ]), + eq('metadata', { + genre: Field.of('genre'), + rating: multiply('rating', 10), + nestedArray: [Field.of('title')], + nestedMap: { + published: Field.of('published') + } + }) + ) + ) + .execute(); + + expect(result.length).to.equal(1); + + expectResults(result, { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + genre: 'Fantasy', + published: 1954, + rating: 4.7, + tags: ['adventure', 'magic', 'epic'], + awards: { hugo: false, nebula: false }, + metadataArray: [ + 1, + 2, + 'Fantasy', + 47, + ['The Lord of the Rings'], + { + published: 1954 + } + ], + metadata: { + genre: 'Fantasy', + rating: 47, + nestedArray: ['The Lord of the Rings'], + nestedMap: { + published: 1954 + } + } + }); + }); + it('returns aggregate results as expected', async () => { let result = await firestore .pipeline() @@ -681,18 +819,20 @@ apiDescribe.only('Pipelines', persistence => { }); // skip: arrayConcat not supported - // it.skip('arrayConcat works', async () => { - // const results = await randomCol - // .pipeline() - // .select( - // Field.of('tags').arrayConcat(['newTag1', 'newTag2']).as('modifiedTags') - // ) - // .limit(1) - // .execute(); - // expectResults(results, { - // modifiedTags: ['comedy', 'space', 'adventure', 'newTag1', 'newTag2'] - // }); - // }); + it('arrayConcat works', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('tags') + .arrayConcat(['newTag1', 'newTag2']) + .as('modifiedTags') + ) + .limit(1) + .execute(); + expectResults(results, { + modifiedTags: ['comedy', 'space', 'adventure', 'newTag1', 'newTag2'] + }); + }); it('testStrConcat', async () => { const results = await randomCol @@ -917,6 +1057,7 @@ apiDescribe.only('Pipelines', persistence => { it('testMapGet', async () => { const results = await randomCol .pipeline() + .sort(Field.of('published').descending()) .select( Field.of('awards').mapGet('hugo').as('hugoAward'), Field.of('awards').mapGet('others').as('others'), @@ -931,7 +1072,7 @@ apiDescribe.only('Pipelines', persistence => { title: "The Hitchhiker's Guide to the Galaxy", others: { unknown: { year: 1980 } } }, - { hugoAward: true, title: 'Dune', others: null } + { hugoAward: true, hugoAward2: true, title: 'Dune', others: null } ); }); @@ -1108,7 +1249,7 @@ apiDescribe.only('Pipelines', persistence => { orFunction( andFunction( Field.of('rating').eq(lastDoc.get('rating')), - Field.of('__path__').gt(lastDoc.ref?.path) + Field.of('__path__').gt(lastDoc.ref?.id) ), Field.of('rating').lt(lastDoc.get('rating')) ) From 29149c0611f65a02b2e06051cbd0c6e1ad7c2264 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 13 Feb 2025 15:02:36 -0700 Subject: [PATCH 22/75] implement new FunctionExpressions as standalone functions --- .../firestore/lite/pipelines/pipelines.ts | 1 - packages/firestore/src/api/pipeline_impl.ts | 19 +- packages/firestore/src/api_pipelines.ts | 53 +- .../firestore/src/lite-api/expressions.ts | 859 +++++++- .../firestore/src/lite-api/pipeline-source.ts | 71 +- packages/firestore/src/lite-api/pipeline.ts | 2 + .../firestore/src/lite-api/pipeline_impl.ts | 2 +- packages/firestore/src/lite-api/stage.ts | 12 +- packages/firestore/src/util/types.ts | 4 + .../test/integration/api/pipeline.test.ts | 1909 +++++++++++------ 10 files changed, 2266 insertions(+), 666 deletions(-) diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index d3e31f5e52b..ee770a3855c 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -137,7 +137,6 @@ export { descending, ExprWithAlias, Field, - Fields, Constant, FirestoreFunction, Add, diff --git a/packages/firestore/src/api/pipeline_impl.ts b/packages/firestore/src/api/pipeline_impl.ts index 9e7c25e69ab..458669246d1 100644 --- a/packages/firestore/src/api/pipeline_impl.ts +++ b/packages/firestore/src/api/pipeline_impl.ts @@ -51,14 +51,17 @@ export function pipeline( ): PipelineSource | Pipeline { if (firestoreOrQuery instanceof Firestore) { const firestore = firestoreOrQuery; - return new PipelineSource((stages: Stage[]) => { - return new Pipeline( - firestore, - newUserDataReader(firestore), - new ExpUserDataWriter(firestore), - stages - ); - }); + return new PipelineSource( + firestore._databaseId, + (stages: Stage[]) => { + return new Pipeline( + firestore, + newUserDataReader(firestore), + new ExpUserDataWriter(firestore), + stages + ); + } + ); } else { const query = firestoreOrQuery; const db = cast(query.firestore, Firestore); diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index 90fe836932f..bbf39f35f22 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -107,10 +107,61 @@ export { genericFunction, ascending, descending, + countif, + bitAnd, + bitOr, + bitXor, + bitNot, + bitLeftShift, + bitRightShift, + rand, + array, + arrayOffset, + currentContext, + isError, + ifError, + isAbsent, + isNull, + isNotNull, + isNotNan, + map, + mapRemove, + mapMerge, + parent, + collectionId, + documentIdFunction, + key, + substr, + manhattanDistance, + Countif, + BitAnd, + BitOr, + BitXor, + BitNot, + BitLeftShift, + BitRightShift, + Rand, + ArrayFunction, + ArrayOffset, + CurrentContext, + IsError, + IfError, + IsAbsent, + IsNull, + IsNotNull, + IsNotNan, + MapFunction, + MapRemove, + MapMerge, + Parent, + CollectionId, + DocumentId, + Key, + Substr, + ManhattanDistance, Expr, ExprWithAlias, Field, - Fields, Constant, FirestoreFunction, Add, diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index bd8f84b718e..e416fdbbc50 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -25,12 +25,14 @@ import { Value as ProtoValue } from '../protos/firestore_proto_api'; import { JsonProtoSerializer, ProtoSerializable, + toMapValue, toStringValue, UserData } from '../remote/serializer'; import { hardAssert } from '../util/assert'; import { isPlainObject } from '../util/input_validation'; import { isFirestoreValue } from '../util/proto'; +import { isString } from '../util/types'; import { Bytes } from './bytes'; import { documentId, FieldPath } from './field_path'; @@ -66,7 +68,7 @@ export type ExprType = * @internal * @param value */ -function valueToDefaultExpr(value: unknown): Expr { +function valueToDefaultExpr(value: any): Expr { if (value instanceof Expr) { return value; } else if (isPlainObject(value)) { @@ -78,6 +80,22 @@ function valueToDefaultExpr(value: unknown): Expr { } } +/** + * Converts a value to an Expr, Returning either a Constant, MapFunction, + * ArrayFunction, or the input itself (if it's already an expression). + * + * @private + * @internal + * @param value + */ +function fieldOfOrExpr(value: string | Expr): Expr { + if (isString(value)) { + return Field.of(value); + } else { + return value; + } +} + /** * @beta * @@ -2190,7 +2208,9 @@ export class FirestoreFunction extends Expr { * @internal */ _readUserData(dataReader: UserDataReader): void { - this.params.forEach(expr => expr._readUserData(dataReader)); + this.params.forEach(expr => { + return expr._readUserData(dataReader); + }); } } @@ -2887,6 +2907,835 @@ export class TimestampSub extends FirestoreFunction { } } +/** + * @beta + */ +export class Countif extends FirestoreFunction implements Accumulator { + constructor(private booleanExpr: Expr) { + super('countif', [booleanExpr]); + } + accumulator = true as const; +} + +/** + * @beta + * Creates an aggregation that counts the number of stage inputs where the provided + * boolean expression evaluates to true. + * + * ```typescript + * // Count the number of documents where 'is_active' field equals true + * countif(Field.of("is_active")).as("numActiveDocuments"); + * ``` + * + * @param booleanExpr - The boolean expression to evaluate on each input. + * @returns A new `Accumulator` representing the 'countif' aggregation. + */ +export function countif(booleanExpr: Expr): Countif { + return new Countif(booleanExpr); +} + +/** + * @beta + */ +export class Rand extends FirestoreFunction { + constructor() { + super('rand', []); + } +} + +export function rand(): Rand { + return new Rand(); +} + +/** + * @beta + */ +export class BitAnd extends FirestoreFunction { + constructor(private left: Expr, private right: Expr) { + super('bit_and', [left, right]); + } +} + +export function bitAnd(field: string, otherBits: number | Bytes): BitAnd; +export function bitAnd(field: string, bitsExpression: Expr): BitAnd; +export function bitAnd(bitsExpression: Expr, otherBits: number | Bytes): BitAnd; +export function bitAnd(bitsExpression: Expr, otherBitsExpression: Expr): BitAnd; +export function bitAnd( + fieldOrExpression: string | Expr, + bitsOrExpression: number | Expr | Bytes +): BitAnd { + const left = + fieldOrExpression instanceof Expr + ? fieldOrExpression + : Field.of(fieldOrExpression); + // @ts-ignore + const right = + bitsOrExpression instanceof Expr + ? bitsOrExpression + : Constant.of(bitsOrExpression); + return new BitAnd(left, right); +} + +/** + * @beta + */ +export class BitOr extends FirestoreFunction { + constructor(private left: Expr, private right: Expr) { + super('bit_or', [left, right]); + } +} + +export function bitOr(field: string, otherBits: number | Bytes): BitOr; +export function bitOr(field: string, bitsExpression: Expr): BitOr; +export function bitOr(bitsExpression: Expr, otherBits: number | Bytes): BitOr; +export function bitOr(bitsExpression: Expr, otherBitsExpression: Expr): BitOr; +export function bitOr( + fieldOrExpression: string | Expr, + bitsOrExpression: number | Expr | Bytes +): BitOr { + const left = + fieldOrExpression instanceof Expr + ? fieldOrExpression + : Field.of(fieldOrExpression); + // @ts-ignore + const right = + bitsOrExpression instanceof Expr + ? bitsOrExpression + : Constant.of(bitsOrExpression); + return new BitOr(left, right); +} + +/** + * @beta + */ +export class BitXor extends FirestoreFunction { + constructor(private left: Expr, private right: Expr) { + super('bit_xor', [left, right]); + } +} + +export function bitXor(field: string, otherBits: number | Bytes): BitXor; +export function bitXor(field: string, bitsExpression: Expr): BitXor; +export function bitXor(bitsExpression: Expr, otherBits: number | Bytes): BitXor; +export function bitXor(bitsExpression: Expr, otherBitsExpression: Expr): BitXor; +export function bitXor( + fieldOrExpression: string | Expr, + bitsOrExpression: number | Expr | Bytes +): BitXor { + const left = + fieldOrExpression instanceof Expr + ? fieldOrExpression + : Field.of(fieldOrExpression); + // @ts-ignore + const right = + bitsOrExpression instanceof Expr + ? bitsOrExpression + : Constant.of(bitsOrExpression); + return new BitXor(left, right); +} + +/** + * @beta + */ +export class BitNot extends FirestoreFunction { + constructor(private value: Expr) { + super('bit_not', [value]); + } +} +export function bitNot(field: string): BitNot; +export function bitNot(bitsValue: number | Bytes): BitNot; +export function bitNot(bitsValueExpression: Expr): BitNot; +export function bitNot(bits: string | number | Bytes | Expr): BitNot { + return new BitNot(isString(bits) ? Field.of(bits) : valueToDefaultExpr(bits)); +} + +/** + * @beta + */ +export class BitLeftShift extends FirestoreFunction { + constructor(value: Expr, y: Expr) { + super('bit_left_shift', [value, y]); + } +} + +export function bitLeftShift(field: string, y: number): BitRightShift; +export function bitLeftShift(field: string, numberExpr: Expr): BitRightShift; +export function bitLeftShift(xValue: number | Bytes, y: number): BitRightShift; +export function bitLeftShift( + xValue: number | Bytes, + numberExpr: Expr +): BitRightShift; +export function bitLeftShift(xValue: Expr, y: number): BitRightShift; +export function bitLeftShift(xValue: Expr, numberExpr: Expr): BitRightShift; +export function bitLeftShift( + xValue: string | number | Bytes, + numberExpr: number | Expr +): BitRightShift { + return new BitLeftShift( + isString(xValue) ? Field.of(xValue) : valueToDefaultExpr(xValue), + valueToDefaultExpr(numberExpr) + ); +} + +/** + * @beta + */ +export class BitRightShift extends FirestoreFunction { + constructor(value: Expr, y: Expr) { + super('bit_right_shift', [value, y]); + } +} + +export function bitRightShift(field: string, y: number): BitRightShift; +export function bitRightShift(field: string, numberExpr: Expr): BitRightShift; +export function bitRightShift(xValue: number | Bytes, y: number): BitRightShift; +export function bitRightShift( + xValue: number | Bytes, + numberExpr: Expr +): BitRightShift; +export function bitRightShift(xValue: Expr, y: number): BitRightShift; +export function bitRightShift(xValue: Expr, numberExpr: Expr): BitRightShift; +export function bitRightShift( + xValue: string | number | Bytes | Expr, + numberExpr: number | Expr +): BitRightShift { + return new BitRightShift( + isString(xValue) ? Field.of(xValue) : valueToDefaultExpr(xValue), + valueToDefaultExpr(numberExpr) + ); +} + +/** + * @beta + */ +export class ArrayOffset extends FirestoreFunction { + constructor(private arrayExpression: Expr, private offset: Expr) { + super('array_offset', [arrayExpression, offset]); + } +} + +/** + * @beta + * + * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN(Field.of("value").divide(0)); + * ``` + * + * @param value The expression to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function arrayOffset(arrayField: string, offset: number): ArrayOffset; + +/** + * @beta + * + * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN(Field.of("value").divide(0)); + * ``` + * + * @param value The expression to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function arrayOffset(arrayField: string, offsetExpr: Expr): ArrayOffset; + +/** + * @beta + * + * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN(Field.of("value").divide(0)); + * ``` + * + * @param value The expression to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function arrayOffset(arrayExpression: Expr, offset: number): ArrayOffset; + +/** + * @beta + * + * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN(Field.of("value").divide(0)); + * ``` + * + * @param value The expression to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function arrayOffset( + arrayExpression: Expr, + offsetExpr: Expr +): ArrayOffset; +export function arrayOffset( + array: Expr | string, + offset: Expr | number +): ArrayOffset { + return new ArrayOffset(fieldOfOrExpr(array), valueToDefaultExpr(offset)); +} + +/** + * @beta + */ +export class CurrentContext extends FirestoreFunction { + constructor() { + super('current_context', []); + } +} + +export function currentContext(): CurrentContext { + return new CurrentContext(); +} + +/** + * @beta + */ +export class IsError extends FirestoreFunction implements FilterCondition { + constructor(private expr: Expr) { + super('is_error', [expr]); + } + filterable = true as const; +} + +/** + * @beta + * + * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN(Field.of("value").divide(0)); + * ``` + * + * @param value The expression to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function isError(value: Expr): IsError { + return new IsError(value); +} + +/** + * @beta + */ +export class IfError extends FirestoreFunction { + constructor(private tryExpr: Expr, private catchExpr: Expr) { + super('if_error', [tryExpr, catchExpr]); + } +} + +/** + * @beta + * + * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN(Field.of("value").divide(0)); + * ``` + * + * @param value The expression to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function ifError(tryExpr: Expr, catchExpr: Expr): IfError; + +/** + * @beta + * + * Creates an expression that checks if a field's value evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN("value"); + * ``` + * + * @param value The name of the field to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function ifError(tryExpr: Expr, catchValue: any): IfError; +export function ifError(tryExpr: Expr, catchValue: any): IfError { + return new IfError(tryExpr, valueToDefaultExpr(catchValue)); +} + +/** + * @beta + */ +export class IsAbsent extends FirestoreFunction implements FilterCondition { + constructor(private expr: Expr) { + super('is_absent', [expr]); + } + filterable = true as const; +} + +/** + * @beta + * + * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN(Field.of("value").divide(0)); + * ``` + * + * @param value The expression to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function isAbsent(value: Expr): IsAbsent; + +/** + * @beta + * + * Creates an expression that checks if a field's value evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN("value"); + * ``` + * + * @param value The name of the field to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function isAbsent(value: string): IsAbsent; +export function isAbsent(value: Expr | string): IsAbsent { + return new IsAbsent(fieldOfOrExpr(value)); +} + +/** + * @beta + */ +export class IsNull extends FirestoreFunction implements FilterCondition { + constructor(private expr: Expr) { + super('is_null', [expr]); + } + filterable = true as const; +} + +/** + * @beta + * + * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN(Field.of("value").divide(0)); + * ``` + * + * @param value The expression to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function isNull(value: Expr): IsNull; + +/** + * @beta + * + * Creates an expression that checks if a field's value evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN("value"); + * ``` + * + * @param value The name of the field to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function isNull(value: string): IsNull; +export function isNull(value: Expr | string): IsNull { + return new IsNull(fieldOfOrExpr(value)); +} + +/** + * @beta + */ +export class IsNotNull extends FirestoreFunction implements FilterCondition { + constructor(private expr: Expr) { + super('is_not_null', [expr]); + } + filterable = true as const; +} + +/** + * @beta + * + * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN(Field.of("value").divide(0)); + * ``` + * + * @param value The expression to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function isNotNull(value: Expr): IsNotNull; + +/** + * @beta + * + * Creates an expression that checks if a field's value evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN("value"); + * ``` + * + * @param value The name of the field to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function isNotNull(value: string): IsNotNull; +export function isNotNull(value: Expr | string): IsNotNull { + return new IsNotNull(fieldOfOrExpr(value)); +} + +/** + * @beta + */ +export class IsNotNan extends FirestoreFunction implements FilterCondition { + constructor(private expr: Expr) { + super('is_not_nan', [expr]); + } + filterable = true as const; +} + +/** + * @beta + * + * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN(Field.of("value").divide(0)); + * ``` + * + * @param value The expression to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function isNotNan(value: Expr): IsNotNan; + +/** + * @beta + * + * Creates an expression that checks if a field's value evaluates to 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NaN + * isNaN("value"); + * ``` + * + * @param value The name of the field to check. + * @return A new {@code Expr} representing the 'isNaN' check. + */ +export function isNotNan(value: string): IsNotNan; +export function isNotNan(value: Expr | string): IsNotNan { + return new IsNotNan(fieldOfOrExpr(value)); +} + +/** + * @beta + */ +export class MapRemove extends FirestoreFunction { + constructor(map: Expr, nameExpr: Expr) { + super('map_remove', [map, nameExpr]); + } +} + +export function mapRemove(mapField: string, name: string): MapRemove; + +export function mapRemove(mapExpr: Expr, name: string): MapRemove; + +export function mapRemove(mapField: string, stringExpr: Expr): MapRemove; + +export function mapRemove(mapExpr: Expr, stringExpr: Expr): MapRemove; + +export function mapRemove( + mapExpr: Expr | string, + stringExpr: Expr | string +): MapRemove { + return new MapRemove(fieldOfOrExpr(mapExpr), valueToDefaultExpr(stringExpr)); +} + +/** + * @beta + */ +export class MapMerge extends FirestoreFunction { + constructor(maps: Expr[]) { + super('map_merge', maps); + } +} + +export function mapMerge( + mapField: string, + secondMap: Record | Expr, + ...otherMaps: Array | Expr> +): MapMerge; + +export function mapMerge( + firstMap: Record | Expr, + secondMap: Record | Expr, + ...otherMaps: Array | Expr> +): MapMerge; + +export function mapMerge( + firstMap: string | Record | Expr, + secondMap: Record | Expr, + ...otherMaps: Array | Expr> +): MapMerge { + const firstMapExpr = + typeof firstMap === 'string' + ? Field.of(firstMap) + : valueToDefaultExpr(firstMap); + const secondMapExpr = valueToDefaultExpr(secondMap); + const otherMapExprs = otherMaps.map(valueToDefaultExpr); + return new MapMerge([firstMapExpr, secondMapExpr, ...otherMapExprs]); +} + +/** + * @beta + */ +export class Parent extends FirestoreFunction { + constructor(pathExpr: Expr) { + super('parent', [pathExpr]); + } +} + +export function parent(path: string | DocumentReference): Parent; + +export function parent(pathExpr: Expr): Parent; + +export function parent(path: Expr | string | DocumentReference): Parent { + // @ts-ignore + const pathExpr = valueToDefaultExpr(path); + return new Parent(pathExpr); +} + +/** + * @beta + */ +export class CollectionId extends FirestoreFunction { + constructor(pathExpr: Expr) { + super('collection_id', [pathExpr]); + } +} + +export function collectionId(path: string | DocumentReference): CollectionId; + +export function collectionId(pathExpr: Expr): CollectionId; + +export function collectionId( + path: Expr | string | DocumentReference +): CollectionId { + // @ts-ignore + const pathExpr = valueToDefaultExpr(path); + return new CollectionId(pathExpr); +} + +/** + * @beta + */ +export class DocumentId extends FirestoreFunction { + constructor(pathExpr: Expr) { + super('document_id', [pathExpr]); + } +} + +export function documentIdFunction( + documentPath: string | DocumentReference +): DocumentId; + +export function documentIdFunction(documentPathExpr: Expr): DocumentId; + +export function documentIdFunction( + documentPath: Expr | string | DocumentReference +): DocumentId { + // @ts-ignore + const documentPathExpr = valueToDefaultExpr(documentPath); + return new DocumentId(documentPathExpr); +} + +/** + * @beta + */ +export class Key extends FirestoreFunction { + constructor(namespaceExpr: Expr, pathExpr: Expr) { + super('key', [namespaceExpr, pathExpr]); + } +} + +export function key(namespace: string, path: string): Key; + +export function key(namespaceExpr: Expr, pathExpr: Expr): Key; + +export function key(namespace: Expr | string, path: Expr | string): Key { + const namespaceExpr = valueToDefaultExpr(namespace); + const pathExpr = path instanceof Expr ? path : Constant.of(path); + return new Key(namespaceExpr, pathExpr); +} + +/** + * @beta + */ +export class Substr extends FirestoreFunction { + constructor(inputExpr: Expr, position: Expr, length: Expr) { + super('substr', [inputExpr, position, length]); + } +} + +export function substr(field: string, position: number, length: number): Substr; + +export function substr( + stringExpr: Expr, + position: number, + length: number +): Substr; + +export function substr(field: string, position: Expr, length: Expr): Substr; + +export function substr(stringExpr: Expr, position: Expr, length: Expr): Substr; + +export function substr( + field: Expr | string, + position: Expr | number, + length: Expr | number +): Substr { + const fieldExpr = fieldOfOrExpr(field); + const positionExpr = valueToDefaultExpr(position); + const lengthExpr = valueToDefaultExpr(length); + return new Substr(fieldExpr, positionExpr, lengthExpr); +} + +/** + * @beta + */ +export class ManhattanDistance extends FirestoreFunction { + constructor(vector1: Expr, vector2: Expr) { + super('manhattan_distance', [vector1, vector2]); + } +} + +/** + * @beta + * + * Calculates the Manhattan distance between a field's vector value and a double array. + * + * ```typescript + * // Calculate the Manhattan distance between the 'location' field and a target location + * manhattanDistance("location", [37.7749, -122.4194]); + * ``` + * + * @param expr The name of the field containing the first vector. + * @param other The other vector (as an array of doubles) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ +export function manhattanDistance( + expr: string, + other: number[] +): ManhattanDistance; + +/** + * @beta + * + * Calculates the Manhattan distance between a field's vector value and a VectorValue. + * + * ```typescript + * // Calculate the Manhattan distance between the 'location' field and a target location + * manhattanDistance("location", new VectorValue([37.7749, -122.4194])); + * ``` + * + * @param expr The name of the field containing the first vector. + * @param other The other vector (as a VectorValue) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ +export function manhattanDistance( + expr: string, + other: VectorValue +): ManhattanDistance; + +/** + * @beta + * + * Calculates the Manhattan distance between a field's vector value and a vector expression. + * + * ```typescript + * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' + * manhattanDistance("pointA", Field.of("pointB")); + * ``` + * + * @param expr The name of the field containing the first vector. + * @param other The other vector (represented as an Expr) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ +export function manhattanDistance(expr: string, other: Expr): ManhattanDistance; + +/** + * @beta + * + * Calculates the Manhattan distance between a vector expression and a double array. + * + * ```typescript + * // Calculate the Manhattan distance between the 'location' field and a target location + * + * manhattanDistance(Field.of("location"), [37.7749, -122.4194]); + * ``` + * + * @param expr The first vector (represented as an Expr) to compare against. + * @param other The other vector (as an array of doubles) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ +export function manhattanDistance( + expr: Expr, + other: number[] +): ManhattanDistance; + +/** + * @beta + * + * Calculates the Manhattan distance between a vector expression and a VectorValue. + * + * ```typescript + * // Calculate the Manhattan distance between the 'location' field and a target location + * manhattanDistance(Field.of("location"), new VectorValue([37.7749, -122.4194])); + * ``` + * + * @param expr The first vector (represented as an Expr) to compare against. + * @param other The other vector (as a VectorValue) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ +export function manhattanDistance( + expr: Expr, + other: VectorValue +): ManhattanDistance; + +/** + * @beta + * + * Calculates the Manhattan distance between two vector expressions. + * + * ```typescript + * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' + * manhattanDistance(Field.of("pointA"), Field.of("pointB")); + * ``` + * + * @param expr The first vector (represented as an Expr) to compare against. + * @param other The other vector (represented as an Expr) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ +export function manhattanDistance(expr: Expr, other: Expr): ManhattanDistance; +export function manhattanDistance( + expr: Expr | string, + other: Expr | number[] | VectorValue +): ManhattanDistance { + const expr1 = fieldOfOrExpr(expr); + const expr2 = other instanceof Expr ? other : Constant.vector(other); + return new ManhattanDistance(expr1, expr2); +} + /** * @beta * @@ -6737,8 +7586,10 @@ export function ascending(expr: Expr): Ordering { * @param expr The expression to create a descending ordering for. * @return A new `Ordering` for descending sorting. */ -export function descending(expr: Expr): Ordering { - return new Ordering(expr, 'descending'); +export function descending(expr: Expr): Ordering; +export function descending(fieldName: string): Ordering; +export function descending(field: Expr | string): Ordering { + return new Ordering(fieldOfOrExpr(field), 'descending'); } /** diff --git a/packages/firestore/src/lite-api/pipeline-source.ts b/packages/firestore/src/lite-api/pipeline-source.ts index 856096037f8..fb596a626bc 100644 --- a/packages/firestore/src/lite-api/pipeline-source.ts +++ b/packages/firestore/src/lite-api/pipeline-source.ts @@ -15,7 +15,10 @@ * limitations under the License. */ -import { DocumentReference } from './reference'; +import { DatabaseId } from '../core/database_info'; +import { FirestoreError, Code } from '../util/error'; + +import { CollectionReference, DocumentReference } from './reference'; import { CollectionGroupSource, CollectionSource, @@ -35,6 +38,7 @@ export class PipelineSource { * @param _createPipeline */ constructor( + private databaseId: DatabaseId, /** * @internal * @private @@ -42,19 +46,78 @@ export class PipelineSource { public _createPipeline: (stages: Stage[]) => PipelineType ) {} - collection(collectionPath: string): PipelineType { - return this._createPipeline([new CollectionSource(collectionPath)]); + /** + * Set the pipeline's source to the collection specified by the given path. + * + * @param collectionPath A path to a collection that will be the source of this pipeline. + */ + collection(collectionPath: string): PipelineType; + + /** + * Set the pipeline's source to the collection specified by the given CollectionReference. + * + * @param collectionReference A CollectionReference for a collection that will be the source of this pipeline. + * The converter for this CollectionReference will be ignored and not have an effect on this pipeline. + * + * @throws {@FirestoreError} Thrown if the provided CollectionReference targets a different project or database than the pipeline. + */ + collection(collectionReference: CollectionReference): PipelineType; + collection(collection: CollectionReference | string): PipelineType { + if (collection instanceof CollectionReference) { + this._validateReference(collection); + return this._createPipeline([new CollectionSource(collection.path)]); + } else { + return this._createPipeline([new CollectionSource(collection)]); + } } + /** + * Set the pipeline's source to the collection group with the given id. + * + * @param collectionid The id of a collection group that will be the source of this pipeline. + */ collectionGroup(collectionId: string): PipelineType { return this._createPipeline([new CollectionGroupSource(collectionId)]); } + /** + * Set the pipeline's source to be all documents in this database. + */ database(): PipelineType { return this._createPipeline([new DatabaseSource()]); } - documents(docs: DocumentReference[]): PipelineType { + /** + * Set the pipeline's source to the documents specified by the given paths and DocumentReferences. + * + * @param docs An array of paths and DocumentReferences specifying the individual documents that will be the source of this pipeline. + * The converters for these DocumentReferences will be ignored and not have an effect on this pipeline. + * + * @throws {@FirestoreError} Thrown if any of the provided DocumentReferences target a different project or database than the pipeline. + */ + documents(docs: Array): PipelineType { + docs.forEach(doc => { + if (doc instanceof DocumentReference) { + this._validateReference(doc); + } + }); + return this._createPipeline([DocumentsSource.of(docs)]); } + + _validateReference(reference: CollectionReference | DocumentReference): void { + const refDbId = reference.firestore._databaseId; + if (!refDbId.isEqual(this.databaseId)) { + throw new FirestoreError( + Code.INVALID_ARGUMENT, + `Invalid ${ + reference instanceof CollectionReference + ? 'CollectionReference' + : 'DocumentReference' + }. ` + + `The project ID ("${refDbId.projectId}") or the database ("${refDbId.database}") does not match ` + + `the project ID ("${this.databaseId.projectId}") and database ("${this.databaseId.database}") of the target database of this Pipeline.` + ); + } + } } diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index c040139aac2..3663c7a88d5 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -29,12 +29,14 @@ import { JsonProtoSerializer, ProtoSerializable } from '../remote/serializer'; +import { isPlainObject } from '../util/input_validation'; import { getDatastore } from './components'; import { Firestore } from './database'; import { Accumulator, AccumulatorTarget, + Constant, Expr, ExprWithAlias, Field, diff --git a/packages/firestore/src/lite-api/pipeline_impl.ts b/packages/firestore/src/lite-api/pipeline_impl.ts index 98b121ad485..5050595e142 100644 --- a/packages/firestore/src/lite-api/pipeline_impl.ts +++ b/packages/firestore/src/lite-api/pipeline_impl.ts @@ -64,7 +64,7 @@ export function pipeline( const db = firestoreOrQuery; const userDataWriter = new LiteUserDataWriter(db); const userDataReader = newUserDataReader(db); - return new PipelineSource((stages: Stage[]) => { + return new PipelineSource(db._databaseId, (stages: Stage[]) => { return new Pipeline(db, userDataReader, userDataWriter, stages); }); } else { diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index 46f8fe60654..886daf98a8d 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -181,8 +181,16 @@ export class DocumentsSource implements Stage { constructor(private docPaths: string[]) {} - static of(refs: DocumentReference[]): DocumentsSource { - return new DocumentsSource(refs.map(ref => '/' + ref.path)); + static of(refs: Array): DocumentsSource { + return new DocumentsSource( + refs.map(ref => + ref instanceof DocumentReference + ? '/' + ref.path + : ref.startsWith('/') + ? ref + : '/' + ref + ) + ); } /** diff --git a/packages/firestore/src/util/types.ts b/packages/firestore/src/util/types.ts index c298bfe2131..361ebda1935 100644 --- a/packages/firestore/src/util/types.ts +++ b/packages/firestore/src/util/types.ts @@ -51,6 +51,10 @@ export function isSafeInteger(value: unknown): boolean { ); } +export function isString(value: unknown): value is string { + return typeof value === 'string'; +} + /** The subset of the browser's Window interface used by the SDK. */ export interface WindowLike { readonly localStorage: Storage; diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index a890ab7346d..2b07351427d 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -18,8 +18,13 @@ import { expect, use } from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import { Bytes, vector } from '../../../src/api'; -import { array, map } from '../../../src/lite-api/expressions'; +import { Bytes, getFirestore, terminate, vector } from '../../../src/api'; +import { + array, + descending, + genericFunction, + map +} from '../../../src/lite-api/expressions'; import { GeoPoint } from '../../../src/lite-api/geo_point'; import { Timestamp } from '../../../src/lite-api/timestamp'; import { addEqualityMatcher } from '../../util/equality_matcher'; @@ -81,7 +86,28 @@ import { documentId, addDoc, getDoc, - multiply + multiply, + countif, + bitAnd, + bitOr, + bitXor, + bitNot, + bitLeftShift, + bitRightShift, + rand, + arrayOffset, + currentContext, + isError, + ifError, + isAbsent, + isNull, + isNotNull, + isNotNan, + mapRemove, + mapMerge, + documentIdFunction, + substr, + manhattanDistance } from '../util/firebase_export'; import { apiDescribe, @@ -180,7 +206,9 @@ apiDescribe.only('Pipelines', persistence => { published: 1954, rating: 4.7, tags: ['adventure', 'magic', 'epic'], - awards: { hugo: false, nebula: false } + awards: { hugo: false, nebula: false }, + remarks: null, + cost: NaN }, book5: { title: "The Handmaid's Tale", @@ -285,59 +313,46 @@ apiDescribe.only('Pipelines', persistence => { expect(result.length).to.equal(10); }); - it('evaluates expression in map', async () => { + it('supports CollectionReference as source', async () => { const result = await firestore .pipeline() - .collection(randomCol.path) - .sort(Field.of('rating').descending()) - .limit(1) - .addFields( - map({ - genre: Field.of('genre'), - rating: Field.of('rating').multiply(10) - }).as('metadata') - ) + .collection(randomCol) .execute(); - - expect(result.length).to.equal(1); - expectResults(result, { - title: 'The Lord of the Rings', - author: 'J.R.R. Tolkien', - genre: 'Fantasy', - published: 1954, - rating: 4.7, - tags: ['adventure', 'magic', 'epic'], - awards: { hugo: false, nebula: false }, - metadata: { - genre: 'Fantasy', - rating: 47 - } - }); + expect(result.length).to.equal(10); }); - it('evaluates expression in array', async () => { + it('supports list of documents as source', async () => { + const collName = randomCol.id; + const result = await firestore .pipeline() - .collection(randomCol.path) - .sort(Field.of('rating').descending()) - .limit(1) - .addFields( - array([1, 2, Field.of('genre'), multiply('rating', 10)]).as( - 'metadata' - ) - ) + .documents([ + `${collName}/book1`, + doc(randomCol, 'book2'), + doc(randomCol, 'book3').path + ]) .execute(); - expect(result.length).to.equal(1); - expectResults(result, { - title: 'The Lord of the Rings', - author: 'J.R.R. Tolkien', - genre: 'Fantasy', - published: 1954, - rating: 4.7, - tags: ['adventure', 'magic', 'epic'], - awards: { hugo: false, nebula: false }, - metadata: [1, 2, 'Fantasy', 47] - }); + expect(result.length).to.equal(3); + }); + + it('reject CollectionReference for another DB', async () => { + const db2 = getFirestore(firestore.app, 'notDefault'); + + expect(() => { + firestore.pipeline().collection(collection(db2, 'foo')); + }).to.throw(/Invalid CollectionReference/); + + await terminate(db2); + }); + + it('reject DocumentReference for another DB', async () => { + const db2 = getFirestore(firestore.app, 'notDefault'); + + expect(() => { + firestore.pipeline().documents([doc(db2, 'foo/bar')]); + }).to.throw(/Invalid DocumentReference/); + + await terminate(db2); }); it('converts arrays and plain objects to functionValues if the customer intent is unspecified', async () => { @@ -421,202 +436,6 @@ apiDescribe.only('Pipelines', persistence => { }); }); - it('returns aggregate results as expected', async () => { - let result = await firestore - .pipeline() - .collection(randomCol.path) - .aggregate(countAll().as('count')) - .execute(); - expectResults(result, { count: 10 }); - - result = await randomCol - .pipeline() - .where(eq('genre', 'Science Fiction')) - .aggregate( - countAll().as('count'), - avgFunction('rating').as('avgRating'), - Field.of('rating').maximum().as('maxRating') - ) - .execute(); - expectResults(result, { count: 2, avgRating: 4.4, maxRating: 4.6 }); - }); - - it('rejects groups without accumulators', async () => { - await expect( - randomCol - .pipeline() - .where(lt('published', 1900)) - .aggregate({ - accumulators: [], - groups: ['genre'] - }) - .execute() - ).to.be.rejected; - }); - - it('returns distinct values as expected', async () => { - const results = await randomCol - .pipeline() - .distinct('genre', 'author') - .sort(Field.of('genre').ascending(), Field.of('author').ascending()) - .execute(); - expectResults( - results, - { genre: 'Dystopian', author: 'George Orwell' }, - { genre: 'Dystopian', author: 'Margaret Atwood' }, - { genre: 'Fantasy', author: 'J.R.R. Tolkien' }, - { genre: 'Magical Realism', author: 'Gabriel García Márquez' }, - { genre: 'Modernist', author: 'F. Scott Fitzgerald' }, - { genre: 'Psychological Thriller', author: 'Fyodor Dostoevsky' }, - { genre: 'Romance', author: 'Jane Austen' }, - { genre: 'Science Fiction', author: 'Douglas Adams' }, - { genre: 'Science Fiction', author: 'Frank Herbert' }, - { genre: 'Southern Gothic', author: 'Harper Lee' } - ); - }); - - it('returns group and accumulate results', async () => { - const results = await randomCol - .pipeline() - .where(lt(Field.of('published'), 1984)) - .aggregate({ - accumulators: [avgFunction('rating').as('avgRating')], - groups: ['genre'] - }) - .where(gt('avgRating', 4.3)) - .sort(Field.of('avgRating').descending()) - .execute(); - expectResults( - results, - { avgRating: 4.7, genre: 'Fantasy' }, - { avgRating: 4.5, genre: 'Romance' }, - { avgRating: 4.4, genre: 'Science Fiction' } - ); - }); - - it('returns min and max accumulations', async () => { - const results = await randomCol - .pipeline() - .aggregate( - countAll().as('count'), - Field.of('rating').maximum().as('maxRating'), - Field.of('published').minimum().as('minPublished') - ) - .execute(); - expectResults(results, { - count: 10, - maxRating: 4.7, - minPublished: 1813 - }); - }); - - it('can select fields', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author') - .sort(Field.of('author').ascending()) - .execute(); - expectResults( - results, - { - title: "The Hitchhiker's Guide to the Galaxy", - author: 'Douglas Adams' - }, - { title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' }, - { title: 'Dune', author: 'Frank Herbert' }, - { title: 'Crime and Punishment', author: 'Fyodor Dostoevsky' }, - { - title: 'One Hundred Years of Solitude', - author: 'Gabriel García Márquez' - }, - { title: '1984', author: 'George Orwell' }, - { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, - { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' }, - { title: 'Pride and Prejudice', author: 'Jane Austen' }, - { title: "The Handmaid's Tale", author: 'Margaret Atwood' } - ); - }); - - it('where with and', async () => { - const results = await randomCol - .pipeline() - .where(andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction'))) - .execute(); - expectResults(results, 'book10'); - }); - - it('where with or', async () => { - const results = await randomCol - .pipeline() - .where(orFunction(eq('genre', 'Romance'), eq('genre', 'Dystopian'))) - .select('title') - .execute(); - expectResults( - results, - { title: 'Pride and Prejudice' }, - { title: "The Handmaid's Tale" }, - { title: '1984' } - ); - }); - - it('offset and limits', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('author').ascending()) - .offset(5) - .limit(3) - .select('title', 'author') - .execute(); - expectResults( - results, - { title: '1984', author: 'George Orwell' }, - { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, - { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' } - ); - }); - - it('logical min works', async () => { - const results = await randomCol - .pipeline() - .select( - 'title', - logicalMinimum(Constant.of(1960), Field.of('published')).as( - 'published-safe' - ) - ) - .sort(Field.of('title').ascending()) - .limit(3) - .execute(); - expectResults( - results, - { title: '1984', 'published-safe': 1949 }, - { title: 'Crime and Punishment', 'published-safe': 1866 }, - { title: 'Dune', 'published-safe': 1960 } - ); - }); - - it('logical max works', async () => { - const results = await randomCol - .pipeline() - .select( - 'title', - logicalMaximum(Constant.of(1960), Field.of('published')).as( - 'published-safe' - ) - ) - .sort(Field.of('title').ascending()) - .limit(3) - .execute(); - expectResults( - results, - { title: '1984', 'published-safe': 1960 }, - { title: 'Crime and Punishment', 'published-safe': 1960 }, - { title: 'Dune', 'published-safe': 1965 } - ); - }); - it('accepts and returns all data types', async () => { const refDate = new Date(); const refTimestamp = Timestamp.now(); @@ -727,456 +546,1256 @@ apiDescribe.only('Pipelines', persistence => { }); }); - it('cond works', async () => { - const results = await randomCol + it('supports internal serialization to proto', async () => { + const pipeline = firestore .pipeline() + .collection('books') + .where(eq('awards.hugo', true)) .select( 'title', - cond( - lt(Field.of('published'), 1960), - Constant.of(1960), - Field.of('published') - ).as('published-safe') - ) - .sort(Field.of('title').ascending()) - .limit(3) - .execute(); - expectResults( - results, - { title: '1984', 'published-safe': 1960 }, - { title: 'Crime and Punishment', 'published-safe': 1960 }, - { title: 'Dune', 'published-safe': 1965 } - ); - }); + Field.of('nestedField.level.1'), + mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') + ); - it('eqAny works', async () => { - const results = await randomCol - .pipeline() - .where(eqAny('published', [1979, 1999, 1967])) - .select('title') - .execute(); - expectResults( - results, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'One Hundred Years of Solitude' } - ); + const proto = _internalPipelineToExecutePipelineRequestProto(pipeline); + expect(proto).not.to.be.null; }); - it('notEqAny works', async () => { - const results = await randomCol - .pipeline() - .where( - notEqAny( - 'published', - [1965, 1925, 1949, 1960, 1866, 1985, 1954, 1967, 1979] - ) - ) - .select('title') - .execute(); - expectResults(results, { title: 'Pride and Prejudice' }); - }); + describe('aggregate stage', () => { + it('supports aggregate', async () => { + let result = await firestore + .pipeline() + .collection(randomCol.path) + .aggregate(countAll().as('count')) + .execute(); + expectResults(result, { count: 10 }); - it('arrayContains works', async () => { - const results = await randomCol - .pipeline() - .where(arrayContains('tags', 'comedy')) - .select('title') - .execute(); - expectResults(results, { - title: "The Hitchhiker's Guide to the Galaxy" + result = await randomCol + .pipeline() + .where(eq('genre', 'Science Fiction')) + .aggregate( + countAll().as('count'), + avgFunction('rating').as('avgRating'), + Field.of('rating').maximum().as('maxRating') + ) + .execute(); + expectResults(result, { count: 2, avgRating: 4.4, maxRating: 4.6 }); }); - }); - it('arrayContainsAny works', async () => { - const results = await randomCol - .pipeline() - .where(arrayContainsAny('tags', ['comedy', 'classic'])) - .select('title') - .execute(); - expectResults( - results, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'Pride and Prejudice' } - ); - }); + it('rejects groups without accumulators', async () => { + await expect( + randomCol + .pipeline() + .where(lt('published', 1900)) + .aggregate({ + accumulators: [], + groups: ['genre'] + }) + .execute() + ).to.be.rejected; + }); - it('arrayContainsAll works', async () => { - const results = await randomCol - .pipeline() - .where(Field.of('tags').arrayContainsAll('adventure', 'magic')) - .select('title') - .execute(); - expectResults(results, { title: 'The Lord of the Rings' }); - }); + it('returns group and accumulate results', async () => { + const results = await randomCol + .pipeline() + .where(lt(Field.of('published'), 1984)) + .aggregate({ + accumulators: [avgFunction('rating').as('avgRating')], + groups: ['genre'] + }) + .where(gt('avgRating', 4.3)) + .sort(Field.of('avgRating').descending()) + .execute(); + expectResults( + results, + { avgRating: 4.7, genre: 'Fantasy' }, + { avgRating: 4.5, genre: 'Romance' }, + { avgRating: 4.4, genre: 'Science Fiction' } + ); + }); - it('arrayLength works', async () => { - const results = await randomCol - .pipeline() - .select(Field.of('tags').arrayLength().as('tagsCount')) - .where(eq('tagsCount', 3)) - .execute(); - expect(results.length).to.equal(10); + it('returns min and max accumulations', async () => { + const results = await randomCol + .pipeline() + .aggregate( + countAll().as('count'), + Field.of('rating').maximum().as('maxRating'), + Field.of('published').minimum().as('minPublished') + ) + .execute(); + expectResults(results, { + count: 10, + maxRating: 4.7, + minPublished: 1813 + }); + }); }); - // skip: arrayConcat not supported - it('arrayConcat works', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('tags') - .arrayConcat(['newTag1', 'newTag2']) - .as('modifiedTags') - ) - .limit(1) - .execute(); - expectResults(results, { - modifiedTags: ['comedy', 'space', 'adventure', 'newTag1', 'newTag2'] + describe('distinct stage', () => { + it('returns distinct values as expected', async () => { + const results = await randomCol + .pipeline() + .distinct('genre', 'author') + .sort(Field.of('genre').ascending(), Field.of('author').ascending()) + .execute(); + expectResults( + results, + { genre: 'Dystopian', author: 'George Orwell' }, + { genre: 'Dystopian', author: 'Margaret Atwood' }, + { genre: 'Fantasy', author: 'J.R.R. Tolkien' }, + { genre: 'Magical Realism', author: 'Gabriel García Márquez' }, + { genre: 'Modernist', author: 'F. Scott Fitzgerald' }, + { genre: 'Psychological Thriller', author: 'Fyodor Dostoevsky' }, + { genre: 'Romance', author: 'Jane Austen' }, + { genre: 'Science Fiction', author: 'Douglas Adams' }, + { genre: 'Science Fiction', author: 'Frank Herbert' }, + { genre: 'Southern Gothic', author: 'Harper Lee' } + ); }); }); - it('testStrConcat', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('author') - .strConcat(' - ', Field.of('title')) - .as('bookInfo') - ) - .limit(1) - .execute(); - expectResults(results, { - bookInfo: "Douglas Adams - The Hitchhiker's Guide to the Galaxy" + describe('select stage', () => { + it('can select fields', async () => { + const results = await firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .sort(Field.of('author').ascending()) + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams' + }, + { title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' }, + { title: 'Dune', author: 'Frank Herbert' }, + { title: 'Crime and Punishment', author: 'Fyodor Dostoevsky' }, + { + title: 'One Hundred Years of Solitude', + author: 'Gabriel García Márquez' + }, + { title: '1984', author: 'George Orwell' }, + { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, + { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' }, + { title: 'Pride and Prejudice', author: 'Jane Austen' }, + { title: "The Handmaid's Tale", author: 'Margaret Atwood' } + ); }); }); - it('testStartsWith', async () => { - const results = await randomCol - .pipeline() - .where(startsWith('title', 'The')) - .select('title') - .sort(Field.of('title').ascending()) - .execute(); - expectResults( - results, - { title: 'The Great Gatsby' }, - { title: "The Handmaid's Tale" }, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'The Lord of the Rings' } - ); + describe('addField stage', () => { + it('can add fields', async () => { + const results = await firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .addFields(Constant.of('bar').as('foo')) + .sort(Field.of('author').ascending()) + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + foo: 'bar' + }, + { + title: 'The Great Gatsby', + author: 'F. Scott Fitzgerald', + foo: 'bar' + }, + { title: 'Dune', author: 'Frank Herbert', foo: 'bar' }, + { + title: 'Crime and Punishment', + author: 'Fyodor Dostoevsky', + foo: 'bar' + }, + { + title: 'One Hundred Years of Solitude', + author: 'Gabriel García Márquez', + foo: 'bar' + }, + { title: '1984', author: 'George Orwell', foo: 'bar' }, + { + title: 'To Kill a Mockingbird', + author: 'Harper Lee', + foo: 'bar' + }, + { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + foo: 'bar' + }, + { title: 'Pride and Prejudice', author: 'Jane Austen', foo: 'bar' }, + { + title: "The Handmaid's Tale", + author: 'Margaret Atwood', + foo: 'bar' + } + ); + }); }); - it('testEndsWith', async () => { - const results = await randomCol - .pipeline() - .where(endsWith('title', 'y')) - .select('title') - .sort(Field.of('title').descending()) - .execute(); - expectResults( - results, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'The Great Gatsby' } - ); + describe('where stage', () => { + it('where with and', async () => { + const results = await randomCol + .pipeline() + .where( + andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')) + ) + .execute(); + expectResults(results, 'book10'); + }); + it('where with or', async () => { + const results = await randomCol + .pipeline() + .where(orFunction(eq('genre', 'Romance'), eq('genre', 'Dystopian'))) + .select('title') + .execute(); + expectResults( + results, + { title: 'Pride and Prejudice' }, + { title: "The Handmaid's Tale" }, + { title: '1984' } + ); + }); }); - it('testLength', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('title').charLength().as('titleLength'), - Field.of('title') - ) - .where(gt('titleLength', 20)) - .sort(Field.of('title').ascending()) - .execute(); + describe('sort, offset, and limit stages', () => { + it('supports sort, offset, and limits', async () => { + const results = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('author').ascending()) + .offset(5) + .limit(3) + .select('title', 'author') + .execute(); + expectResults( + results, + { title: '1984', author: 'George Orwell' }, + { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, + { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' } + ); + }); + }); - expectResults( - results, + describe('generic stage', () => { + it('can select fields', async () => { + const results = await firestore + .pipeline() + .collection(randomCol.path) + .genericStage('select', [ + { + title: Field.of('title'), + metadata: { + 'author': Field.of('author') + } + } + ]) + .sort(Field.of('author').ascending()) + .limit(1) + .execute(); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy", + metadata: { + author: 'Douglas Adams' + } + }); + }); - { - titleLength: 29, - title: 'One Hundred Years of Solitude' - }, - { - titleLength: 36, - title: "The Hitchhiker's Guide to the Galaxy" - }, - { - titleLength: 21, - title: 'The Lord of the Rings' - }, - { - titleLength: 21, - title: 'To Kill a Mockingbird' - } - ); - }); + it('can add fields', async () => { + const results = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('author').ascending()) + .limit(1) + .select('title', 'author') + .genericStage('add_fields', [ + { + display: Field.of('title').strConcat(' - ', Field.of('author')) + } + ]) + .execute(); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + display: "The Hitchhiker's Guide to the Galaxy - Douglas Adams" + }); + }); - // skip: toLower not supported - // it.skip('testToLowercase', async () => { - // const results = await randomCol - // .pipeline() - // .select(Field.of('title').toLower().as('lowercaseTitle')) - // .limit(1) - // .execute(); - // expectResults(results, { - // lowercaseTitle: "the hitchhiker's guide to the galaxy" - // }); - // }); - - // skip: toUpper not supported - // it.skip('testToUppercase', async () => { - // const results = await randomCol - // .pipeline() - // .select(Field.of('author').toUpper().as('uppercaseAuthor')) - // .limit(1) - // .execute(); - // expectResults(results, { uppercaseAuthor: 'DOUGLAS ADAMS' }); - // }); - - // skip: trim not supported - // it.skip('testTrim', async () => { - // const results = await randomCol - // .pipeline() - // .addFields(strConcat(' ', Field.of('title'), ' ').as('spacedTitle')) - // .select( - // Field.of('spacedTitle').trim().as('trimmedTitle'), - // Field.of('spacedTitle') - // ) - // .limit(1) - // .execute(); - // expectResults(results, { - // spacedTitle: " The Hitchhiker's Guide to the Galaxy ", - // trimmedTitle: "The Hitchhiker's Guide to the Galaxy" - // }); - // }); - - it('testLike', async () => { - const results = await randomCol - .pipeline() - .where(like('title', '%Guide%')) - .select('title') - .execute(); - expectResults(results, { - title: "The Hitchhiker's Guide to the Galaxy" + it('can filter with where', async () => { + const results = await firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .genericStage('where', [Field.of('author').eq('Douglas Adams')]) + .execute(); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams' + }); }); - }); - it('testRegexContains', async () => { - const results = await randomCol - .pipeline() - .where(regexContains('title', '(?i)(the|of)')) - .execute(); - expect(results.length).to.equal(5); - }); + it('can limit, offset, and sort', async () => { + const results = await firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .genericStage('sort', [ + { + direction: 'ascending', + expression: Field.of('author') + } + ]) + .genericStage('offset', [3]) + .genericStage('limit', [1]) + .execute(); + expectResults(results, { + author: 'Fyodor Dostoevsky', + title: 'Crime and Punishment' + }); + }); - it('testRegexMatches', async () => { - const results = await randomCol - .pipeline() - .where(regexMatch('title', '.*(?i)(the|of).*')) - .execute(); - expect(results.length).to.equal(5); - }); + it('can perform aggregate query', async () => { + const results = await firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author', 'rating') + .genericStage('aggregate', [ + { averageRating: Field.of('rating').avg() }, + {} + ]) + .execute(); + expectResults(results, { + averageRating: 4.3100000000000005 + }); + }); - it('testArithmeticOperations', async () => { - const results = await randomCol - .pipeline() - .select( - add(Field.of('rating'), 1).as('ratingPlusOne'), - subtract(Field.of('published'), 1900).as('yearsSince1900'), - Field.of('rating').multiply(10).as('ratingTimesTen'), - Field.of('rating').divide(2).as('ratingDividedByTwo') - ) - .limit(1) - .execute(); - expectResults(results, { - ratingPlusOne: 5.2, - yearsSince1900: 79, - ratingTimesTen: 42, - ratingDividedByTwo: 2.1 + it('can perform distinct query', async () => { + const results = await firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author', 'rating') + .genericStage('distinct', [{ rating: Field.of('rating') }]) + .sort(Field.of('rating').descending()) + .execute(); + expectResults( + results, + { + rating: 4.7 + }, + { + rating: 4.6 + }, + { + rating: 4.5 + }, + { + rating: 4.3 + }, + { + rating: 4.2 + }, + { + rating: 4.1 + }, + { + rating: 4.0 + } + ); }); }); + it('logical max works', async () => { + const results = await randomCol + .pipeline() + .select( + 'title', + logicalMaximum(Constant.of(1960), Field.of('published')).as( + 'published-safe' + ) + ) + .sort(Field.of('title').ascending()) + .limit(3) + .execute(); + expectResults( + results, + { title: '1984', 'published-safe': 1960 }, + { title: 'Crime and Punishment', 'published-safe': 1960 }, + { title: 'Dune', 'published-safe': 1965 } + ); + }); - it('testComparisonOperators', async () => { - const results = await randomCol - .pipeline() - .where( - andFunction( - gt('rating', 4.2), - lte(Field.of('rating'), 4.5), - neq('genre', 'Science Fiction') + it('cond works', async () => { + const results = await randomCol + .pipeline() + .select( + 'title', + cond( + lt(Field.of('published'), 1960), + Constant.of(1960), + Field.of('published') + ).as('published-safe') ) - ) - .select('rating', 'title') - .sort(Field.of('title').ascending()) - .execute(); - expectResults( - results, - { rating: 4.3, title: 'Crime and Punishment' }, - { - rating: 4.3, - title: 'One Hundred Years of Solitude' - }, - { rating: 4.5, title: 'Pride and Prejudice' } - ); - }); + .sort(Field.of('title').ascending()) + .limit(3) + .execute(); + expectResults( + results, + { title: '1984', 'published-safe': 1960 }, + { title: 'Crime and Punishment', 'published-safe': 1960 }, + { title: 'Dune', 'published-safe': 1965 } + ); + }); - it('testLogicalOperators', async () => { - const results = await randomCol - .pipeline() - .where( - orFunction( - andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')), - lt('published', 1900) + it('eqAny works', async () => { + const results = await randomCol + .pipeline() + .where(eqAny('published', [1979, 1999, 1967])) + .select('title') + .execute(); + expectResults( + results, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'One Hundred Years of Solitude' } + ); + }); + + it('notEqAny works', async () => { + const results = await randomCol + .pipeline() + .where( + notEqAny( + 'published', + [1965, 1925, 1949, 1960, 1866, 1985, 1954, 1967, 1979] + ) ) - ) - .select('title') - .sort(Field.of('title').ascending()) - .execute(); - expectResults( - results, - { title: 'Crime and Punishment' }, - { title: 'Dune' }, - { title: 'Pride and Prejudice' } - ); - }); + .select('title') + .execute(); + expectResults(results, { title: 'Pride and Prejudice' }); + }); - it('testChecks', async () => { - const results = await randomCol - .pipeline() - .where(not(Field.of('rating').isNaN())) - .select( - Field.of('rating').eq(null).as('ratingIsNull'), - not(Field.of('rating').isNaN()).as('ratingIsNotNaN') - ) - .limit(1) - .execute(); - expectResults(results, { ratingIsNull: false, ratingIsNotNaN: true }); - }); + it('arrayContains works', async () => { + const results = await randomCol + .pipeline() + .where(arrayContains('tags', 'comedy')) + .select('title') + .execute(); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy" + }); + }); - it('testMapGet', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('published').descending()) - .select( - Field.of('awards').mapGet('hugo').as('hugoAward'), - Field.of('awards').mapGet('others').as('others'), - Field.of('title') - ) - .where(eq('hugoAward', true)) - .execute(); - expectResults( - results, - { - hugoAward: true, - title: "The Hitchhiker's Guide to the Galaxy", - others: { unknown: { year: 1980 } } - }, - { hugoAward: true, hugoAward2: true, title: 'Dune', others: null } - ); - }); + it('arrayContainsAny works', async () => { + const results = await randomCol + .pipeline() + .where(arrayContainsAny('tags', ['comedy', 'classic'])) + .select('title') + .execute(); + expectResults( + results, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'Pride and Prejudice' } + ); + }); - // it('testParent', async () => { - // const results = await randomCol - // .pipeline() - // .select( - // parent(randomCol.doc('chile').collection('subCollection').path).as( - // 'parent' - // ) - // ) - // .limit(1) - // .execute(); - // expect(results[0].data().parent.endsWith('/books')).to.be.true; - // }); - // - // it('testCollectionId', async () => { - // const results = await randomCol - // .pipeline() - // .select(collectionId(randomCol.doc('chile')).as('collectionId')) - // .limit(1) - // .execute(); - // expectResults(results, {collectionId: 'books'}); - // }); - - it('testDistanceFunctions', async () => { - const sourceVector = [0.1, 0.1]; - const targetVector = [0.5, 0.8]; - const results = await randomCol - .pipeline() - .select( - cosineDistance(Constant.vector(sourceVector), targetVector).as( - 'cosineDistance' - ), - dotProduct(Constant.vector(sourceVector), targetVector).as( - 'dotProductDistance' - ), - euclideanDistance(Constant.vector(sourceVector), targetVector).as( - 'euclideanDistance' + it('arrayContainsAll works', async () => { + const results = await randomCol + .pipeline() + .where(Field.of('tags').arrayContainsAll('adventure', 'magic')) + .select('title') + .execute(); + expectResults(results, { title: 'The Lord of the Rings' }); + }); + + it('arrayLength works', async () => { + const results = await randomCol + .pipeline() + .select(Field.of('tags').arrayLength().as('tagsCount')) + .where(eq('tagsCount', 3)) + .execute(); + expect(results.length).to.equal(10); + }); + + it('testStrConcat', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('author') + .strConcat(' - ', Field.of('title')) + .as('bookInfo') ) - ) - .limit(1) - .execute(); + .limit(1) + .execute(); + expectResults(results, { + bookInfo: "Douglas Adams - The Hitchhiker's Guide to the Galaxy" + }); + }); - expectResults(results, { - cosineDistance: 0.02560880430538015, - dotProductDistance: 0.13, - euclideanDistance: 0.806225774829855 + it('testStartsWith', async () => { + const results = await randomCol + .pipeline() + .where(startsWith('title', 'The')) + .select('title') + .sort(Field.of('title').ascending()) + .execute(); + expectResults( + results, + { title: 'The Great Gatsby' }, + { title: "The Handmaid's Tale" }, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'The Lord of the Rings' } + ); }); - }); - it('testNestedFields', async () => { - const results = await randomCol - .pipeline() - .where(eq('awards.hugo', true)) - .select('title', 'awards.hugo') - .execute(); - expectResults( - results, - { - title: "The Hitchhiker's Guide to the Galaxy", - 'awards.hugo': true - }, - { title: 'Dune', 'awards.hugo': true } - ); - }); + it('testEndsWith', async () => { + const results = await randomCol + .pipeline() + .where(endsWith('title', 'y')) + .select('title') + .sort(Field.of('title').descending()) + .execute(); + expectResults( + results, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'The Great Gatsby' } + ); + }); - it('test mapGet with field name including . notation', async () => { - const results = await randomCol - .pipeline() - .where(eq('awards.hugo', true)) - .select( - 'title', - Field.of('nestedField.level.1'), - mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') - ) - .execute(); - expectResults( - results, - { - title: "The Hitchhiker's Guide to the Galaxy", - 'nestedField.level.`1`': null, - nested: true - }, - { title: 'Dune', 'nestedField.level.`1`': null, nested: null } - ); - }); + it('testLength', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('title').charLength().as('titleLength'), + Field.of('title') + ) + .where(gt('titleLength', 20)) + .sort(Field.of('title').ascending()) + .execute(); - it('supports internal serialization to proto', async () => { - const pipeline = firestore - .pipeline() - .collection('books') - .where(eq('awards.hugo', true)) - .select( - 'title', - Field.of('nestedField.level.1'), - mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') + expectResults( + results, + + { + titleLength: 29, + title: 'One Hundred Years of Solitude' + }, + { + titleLength: 36, + title: "The Hitchhiker's Guide to the Galaxy" + }, + { + titleLength: 21, + title: 'The Lord of the Rings' + }, + { + titleLength: 21, + title: 'To Kill a Mockingbird' + } ); + }); - const proto = _internalPipelineToExecutePipelineRequestProto(pipeline); - expect(proto).not.to.be.null; + it('testLike', async () => { + const results = await randomCol + .pipeline() + .where(like('title', '%Guide%')) + .select('title') + .execute(); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy" + }); + }); + + it('testRegexContains', async () => { + const results = await randomCol + .pipeline() + .where(regexContains('title', '(?i)(the|of)')) + .execute(); + expect(results.length).to.equal(5); + }); + + it('testRegexMatches', async () => { + const results = await randomCol + .pipeline() + .where(regexMatch('title', '.*(?i)(the|of).*')) + .execute(); + expect(results.length).to.equal(5); + }); + + it('testArithmeticOperations', async () => { + const results = await randomCol + .pipeline() + .select( + add(Field.of('rating'), 1).as('ratingPlusOne'), + subtract(Field.of('published'), 1900).as('yearsSince1900'), + Field.of('rating').multiply(10).as('ratingTimesTen'), + Field.of('rating').divide(2).as('ratingDividedByTwo') + ) + .limit(1) + .execute(); + expectResults(results, { + ratingPlusOne: 5.2, + yearsSince1900: 79, + ratingTimesTen: 42, + ratingDividedByTwo: 2.1 + }); + }); + + it('testComparisonOperators', async () => { + const results = await randomCol + .pipeline() + .where( + andFunction( + gt('rating', 4.2), + lte(Field.of('rating'), 4.5), + neq('genre', 'Science Fiction') + ) + ) + .select('rating', 'title') + .sort(Field.of('title').ascending()) + .execute(); + expectResults( + results, + { rating: 4.3, title: 'Crime and Punishment' }, + { + rating: 4.3, + title: 'One Hundred Years of Solitude' + }, + { rating: 4.5, title: 'Pride and Prejudice' } + ); + }); + + it('testLogicalOperators', async () => { + const results = await randomCol + .pipeline() + .where( + orFunction( + andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')), + lt('published', 1900) + ) + ) + .select('title') + .sort(Field.of('title').ascending()) + .execute(); + expectResults( + results, + { title: 'Crime and Punishment' }, + { title: 'Dune' }, + { title: 'Pride and Prejudice' } + ); + }); + + it('testChecks', async () => { + const results = await randomCol + .pipeline() + .where(not(Field.of('rating').isNaN())) + .select( + Field.of('rating').eq(null).as('ratingIsNull'), + not(Field.of('rating').isNaN()).as('ratingIsNotNaN') + ) + .limit(1) + .execute(); + expectResults(results, { ratingIsNull: false, ratingIsNotNaN: true }); + }); + + it('testMapGet', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('published').descending()) + .select( + Field.of('awards').mapGet('hugo').as('hugoAward'), + Field.of('awards').mapGet('others').as('others'), + Field.of('title') + ) + .where(eq('hugoAward', true)) + .execute(); + expectResults( + results, + { + hugoAward: true, + title: "The Hitchhiker's Guide to the Galaxy", + others: { unknown: { year: 1980 } } + }, + { hugoAward: true, hugoAward2: true, title: 'Dune', others: null } + ); + }); + + it('testDistanceFunctions', async () => { + const sourceVector = [0.1, 0.1]; + const targetVector = [0.5, 0.8]; + const results = await randomCol + .pipeline() + .select( + cosineDistance(Constant.vector(sourceVector), targetVector).as( + 'cosineDistance' + ), + dotProduct(Constant.vector(sourceVector), targetVector).as( + 'dotProductDistance' + ), + euclideanDistance(Constant.vector(sourceVector), targetVector).as( + 'euclideanDistance' + ) + ) + .limit(1) + .execute(); + + expectResults(results, { + cosineDistance: 0.02560880430538015, + dotProductDistance: 0.13, + euclideanDistance: 0.806225774829855 + }); + }); + + it('testNestedFields', async () => { + const results = await randomCol + .pipeline() + .where(eq('awards.hugo', true)) + .select('title', 'awards.hugo') + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + 'awards.hugo': true + }, + { title: 'Dune', 'awards.hugo': true } + ); + }); + + it('test mapGet with field name including . notation', async () => { + const results = await randomCol + .pipeline() + .where(eq('awards.hugo', true)) + .select( + 'title', + Field.of('nestedField.level.1'), + mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') + ) + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + 'nestedField.level.`1`': null, + nested: true + }, + { title: 'Dune', 'nestedField.level.`1`': null, nested: null } + ); + }); + + it('supports countIf', async () => { + const results = await randomCol + .pipeline() + .aggregate(countif(Field.of('rating').gt(4.3)).as('count')) + .execute(); + expectResults(results, { + count: 3 + }); + }); + + describe('genericFunction', () => { + it('add selectable', async () => { + const results = await randomCol + .pipeline() + .sort(descending('rating')) + .limit(1) + .select( + genericFunction('add', [Field.of('rating'), Constant.of(1)]).as( + 'rating' + ) + ) + .execute(); + expectResults(results, { + rating: 5.7 + }); + }); + + it('and (variadic) selectable', async () => { + const results = await randomCol + .pipeline() + .where( + genericFunction('and', [ + Field.of('rating').gt(0), + Field.of('title').charLength().lt(5), + Field.of('tags').arrayContains('propaganda') + ]) + ) + .select('title') + .execute(); + expectResults(results, { + title: '1984' + }); + }); + + it('array contains any', async () => { + const results = await randomCol + .pipeline() + .where( + genericFunction('array_contains_any', [ + Field.of('tags'), + ['politics'] + ]) + ) + .select('title') + .execute(); + expectResults(results, { + title: 'Dune' + }); + }); + + it('countif aggregate', async () => { + const results = await randomCol + .pipeline() + .aggregate( + genericFunction('countif', [Field.of('rating').gte(4.5)]).as( + 'countOfBest' + ) + ) + .execute(); + expectResults(results, { + countOfBest: 3 + }); + }); + + it('sort by char_len', async () => { + const results = await randomCol + .pipeline() + .sort( + genericFunction('char_length', [Field.of('title')]).ascending(), + descending('__name__') + ) + .limit(3) + .select('title') + .execute(); + expectResults( + results, + { + title: '1984' + }, + { + title: 'Dune' + }, + { + title: 'The Great Gatsby' + } + ); + }); + }); + + describe.skip('not implemented in backend', () => { + it('supports Bit_and', async () => { + const results = await randomCol + .pipeline() + .limit(1) + .select(bitAnd(Constant.of(5), 12).as('result')) + .execute(); + expectResults(results, { + result: 4 + }); + }); + + it('supports Bit_or', async () => { + const results = await randomCol + .pipeline() + .limit(1) + .select(bitOr(Constant.of(5), 12).as('result')) + .execute(); + expectResults(results, { + result: 13 + }); + }); + + it('supports Bit_xor', async () => { + const results = await randomCol + .pipeline() + .limit(1) + .select(bitXor(Constant.of(5), 12).as('result')) + .execute(); + expectResults(results, { + result: 9 + }); + }); + + it('supports Bit_not', async () => { + const results = await randomCol + .pipeline() + .limit(1) + .select( + bitNot( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd))) + ).as('result') + ) + .execute(); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x02)) + }); + }); + + it('supports Bit_left_shift', async () => { + const results = await randomCol + .pipeline() + .limit(1) + .select( + bitLeftShift( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + .execute(); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x04)) + }); + }); + + it('supports Bit_right_shift', async () => { + const results = await randomCol + .pipeline() + .limit(1) + .select( + bitRightShift( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + .execute(); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x01)) + }); + }); + + it('supports Document_id', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(documentIdFunction(Field.of('__path__')).as('docId')) + .execute(); + expectResults(results, { + docId: 'book4' + }); + }); + + it('supports Substr', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(substr('title', 9, 2).as('of')) + .execute(); + expectResults(results, { + of: 'of' + }); + }); + + it('arrayConcat works', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('tags') + .arrayConcat(['newTag1', 'newTag2']) + .as('modifiedTags') + ) + .limit(1) + .execute(); + expectResults(results, { + modifiedTags: [ + 'comedy', + 'space', + 'adventure', + 'newTag1', + 'newTag2' + ] + }); + }); + + it('testToLowercase', async () => { + const results = await randomCol + .pipeline() + .select(Field.of('title').toLower().as('lowercaseTitle')) + .limit(1) + .execute(); + expectResults(results, { + lowercaseTitle: "the hitchhiker's guide to the galaxy" + }); + }); + + it('testToUppercase', async () => { + const results = await randomCol + .pipeline() + .select(Field.of('author').toUpper().as('uppercaseAuthor')) + .limit(1) + .execute(); + expectResults(results, { uppercaseAuthor: 'DOUGLAS ADAMS' }); + }); + + it('testTrim', async () => { + const results = await randomCol + .pipeline() + .addFields( + Constant.of(" The Hitchhiker's Guide to the Galaxy ").as( + 'spacedTitle' + ) + ) + .select( + Field.of('spacedTitle').trim().as('trimmedTitle'), + Field.of('spacedTitle') + ) + .limit(1) + .execute(); + expectResults(results, { + spacedTitle: " The Hitchhiker's Guide to the Galaxy ", + trimmedTitle: "The Hitchhiker's Guide to the Galaxy" + }); + }); + }); + + it('supports Rand', async () => { + const results = await randomCol + .pipeline() + .limit(10) + .select(rand().as('result')) + .execute(); + expect(results.length).to.equal(10); + results.forEach(d => { + expect(d.get('result')).to.be.lt(1); + expect(d.get('result')).to.be.gte(0); + }); + }); + + it('supports array', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select(array([1, 2, 3, 4]).as('metadata')) + .execute(); + expect(result.length).to.equal(1); + expectResults(result, { + metadata: [1, 2, 3, 4] + }); + }); + + it('evaluates expression in array', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + array([1, 2, Field.of('genre'), multiply('rating', 10)]).as( + 'metadata' + ) + ) + .execute(); + expect(result.length).to.equal(1); + expectResults(result, { + metadata: [1, 2, 'Fantasy', 47] + }); + }); + + it('supports arrayOffset', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(3) + .select(arrayOffset('tags', 0).as('firstTag')) + .execute(); + expectResults( + results, + { + firstTag: 'adventure' + }, + { + firstTag: 'politics' + }, + { + firstTag: 'classic' + } + ); + }); + + // TODO: current_context tests with are failing because of b/395937453 + it('supports currentContext', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(currentContext().as('currentContext')) + .execute(); + expectResults(results, { + currentContext: 'TODO' + }); + }); + + it('supports isError', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(isError(arrayOffset('title', 0)).as('firstTag')) + .execute(); + expectResults(results, { + firstTag: true + }); + }); + + it('supports ifError', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select( + ifError(arrayOffset('title', 0), Constant.of('was error')).as( + 'firstTag' + ) + ) + .execute(); + expectResults(results, { + firstTag: 'was error' + }); + }); + + it('supports isAbsent', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(isAbsent('foo').as('firstTag')) + .execute(); + expectResults(results, { + firstTag: true + }); + }); + + it('supports isNull', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(isNull('remarks').as('remarksIsNull')) + .execute(); + expectResults(results, { + remarksIsNull: true + }); + }); + + it('supports isNotNull', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(isNotNull('title').as('titleIsNotNull')) + .execute(); + expectResults(results, { + titleIsNotNull: true + }); + }); + + it('supports isNotNan', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(isNotNan('cost').as('costIsNotNan')) + .execute(); + expectResults(results, { + costIsNotNan: false + }); + }); + + it('supports map', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + map({ + foo: 'bar' + }).as('metadata') + ) + .execute(); + + expect(result.length).to.equal(1); + expectResults(result, { + metadata: { + foo: 'bar' + } + }); + }); + + it('evaluates expression in map', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + map({ + genre: Field.of('genre'), + rating: Field.of('rating').multiply(10) + }).as('metadata') + ) + .execute(); + + expect(result.length).to.equal(1); + expectResults(result, { + metadata: { + genre: 'Fantasy', + rating: 47 + } + }); + }); + + it('supports mapRemove', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(mapRemove('awards', 'hugo').as('awards')) + .execute(); + expectResults(results, { + awards: { nebula: false } + }); + }); + + it('supports mapMerge', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(mapMerge('awards', { fakeAward: true }).as('awards')) + .execute(); + expectResults(results, { + awards: { nebula: false, hugo: false, fakeAward: true } + }); + }); + + it('supports manhattanDistance', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Constant.vector([1, 1]).as('embedding')) + .addFields(manhattanDistance('embedding', [3, 3]).as('distance')) + .execute(); + expectResults(results, { + distance: 4, + embedding: vector([1, 1]) + }); + }); }); describe('pagination', () => { + /** + * Adds several books to the test collection. These + * additional books support pagination test scenarios + * that would otherwise not be possible with the original + * set of books. + * @param collection + */ async function addBooks( collection: CollectionReference ): Promise { From dbe6821f5725582aab57fec8be71f2da840a3c00 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 13 Feb 2025 15:06:07 -0700 Subject: [PATCH 23/75] Fix typo and formatting in pipeline.test.ts --- .../test/integration/api/pipeline.test.ts | 1696 ++++++++--------- 1 file changed, 841 insertions(+), 855 deletions(-) diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 2b07351427d..4bdbbf8146a 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -907,1040 +907,1026 @@ apiDescribe.only('Pipelines', persistence => { ); }); }); - it('logical max works', async () => { - const results = await randomCol - .pipeline() - .select( - 'title', - logicalMaximum(Constant.of(1960), Field.of('published')).as( - 'published-safe' - ) + it('logical max works', async () => { + const results = await randomCol + .pipeline() + .select( + 'title', + logicalMaximum(Constant.of(1960), Field.of('published')).as( + 'published-safe' ) - .sort(Field.of('title').ascending()) - .limit(3) - .execute(); - expectResults( - results, - { title: '1984', 'published-safe': 1960 }, - { title: 'Crime and Punishment', 'published-safe': 1960 }, - { title: 'Dune', 'published-safe': 1965 } - ); - }); + ) + .sort(Field.of('title').ascending()) + .limit(3) + .execute(); + expectResults( + results, + { title: '1984', 'published-safe': 1960 }, + { title: 'Crime and Punishment', 'published-safe': 1960 }, + { title: 'Dune', 'published-safe': 1965 } + ); + }); - it('cond works', async () => { - const results = await randomCol - .pipeline() - .select( - 'title', - cond( - lt(Field.of('published'), 1960), - Constant.of(1960), - Field.of('published') - ).as('published-safe') + it('cond works', async () => { + const results = await randomCol + .pipeline() + .select( + 'title', + cond( + lt(Field.of('published'), 1960), + Constant.of(1960), + Field.of('published') + ).as('published-safe') + ) + .sort(Field.of('title').ascending()) + .limit(3) + .execute(); + expectResults( + results, + { title: '1984', 'published-safe': 1960 }, + { title: 'Crime and Punishment', 'published-safe': 1960 }, + { title: 'Dune', 'published-safe': 1965 } + ); + }); + + it('eqAny works', async () => { + const results = await randomCol + .pipeline() + .where(eqAny('published', [1979, 1999, 1967])) + .select('title') + .execute(); + expectResults( + results, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'One Hundred Years of Solitude' } + ); + }); + + it('notEqAny works', async () => { + const results = await randomCol + .pipeline() + .where( + notEqAny( + 'published', + [1965, 1925, 1949, 1960, 1866, 1985, 1954, 1967, 1979] ) - .sort(Field.of('title').ascending()) - .limit(3) - .execute(); - expectResults( - results, - { title: '1984', 'published-safe': 1960 }, - { title: 'Crime and Punishment', 'published-safe': 1960 }, - { title: 'Dune', 'published-safe': 1965 } - ); - }); + ) + .select('title') + .execute(); + expectResults(results, { title: 'Pride and Prejudice' }); + }); - it('eqAny works', async () => { - const results = await randomCol - .pipeline() - .where(eqAny('published', [1979, 1999, 1967])) - .select('title') - .execute(); - expectResults( - results, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'One Hundred Years of Solitude' } - ); + it('arrayContains works', async () => { + const results = await randomCol + .pipeline() + .where(arrayContains('tags', 'comedy')) + .select('title') + .execute(); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy" }); + }); - it('notEqAny works', async () => { - const results = await randomCol - .pipeline() - .where( - notEqAny( - 'published', - [1965, 1925, 1949, 1960, 1866, 1985, 1954, 1967, 1979] - ) - ) - .select('title') - .execute(); - expectResults(results, { title: 'Pride and Prejudice' }); + it('arrayContainsAny works', async () => { + const results = await randomCol + .pipeline() + .where(arrayContainsAny('tags', ['comedy', 'classic'])) + .select('title') + .execute(); + expectResults( + results, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'Pride and Prejudice' } + ); + }); + + it('arrayContainsAll works', async () => { + const results = await randomCol + .pipeline() + .where(Field.of('tags').arrayContainsAll('adventure', 'magic')) + .select('title') + .execute(); + expectResults(results, { title: 'The Lord of the Rings' }); + }); + + it('arrayLength works', async () => { + const results = await randomCol + .pipeline() + .select(Field.of('tags').arrayLength().as('tagsCount')) + .where(eq('tagsCount', 3)) + .execute(); + expect(results.length).to.equal(10); + }); + + it('testStrConcat', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('author') + .strConcat(' - ', Field.of('title')) + .as('bookInfo') + ) + .limit(1) + .execute(); + expectResults(results, { + bookInfo: "Douglas Adams - The Hitchhiker's Guide to the Galaxy" }); + }); - it('arrayContains works', async () => { - const results = await randomCol - .pipeline() - .where(arrayContains('tags', 'comedy')) - .select('title') - .execute(); - expectResults(results, { + it('testStartsWith', async () => { + const results = await randomCol + .pipeline() + .where(startsWith('title', 'The')) + .select('title') + .sort(Field.of('title').ascending()) + .execute(); + expectResults( + results, + { title: 'The Great Gatsby' }, + { title: "The Handmaid's Tale" }, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'The Lord of the Rings' } + ); + }); + + it('testEndsWith', async () => { + const results = await randomCol + .pipeline() + .where(endsWith('title', 'y')) + .select('title') + .sort(Field.of('title').descending()) + .execute(); + expectResults( + results, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'The Great Gatsby' } + ); + }); + + it('testLength', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('title').charLength().as('titleLength'), + Field.of('title') + ) + .where(gt('titleLength', 20)) + .sort(Field.of('title').ascending()) + .execute(); + + expectResults( + results, + + { + titleLength: 29, + title: 'One Hundred Years of Solitude' + }, + { + titleLength: 36, title: "The Hitchhiker's Guide to the Galaxy" - }); - }); + }, + { + titleLength: 21, + title: 'The Lord of the Rings' + }, + { + titleLength: 21, + title: 'To Kill a Mockingbird' + } + ); + }); - it('arrayContainsAny works', async () => { - const results = await randomCol - .pipeline() - .where(arrayContainsAny('tags', ['comedy', 'classic'])) - .select('title') - .execute(); - expectResults( - results, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'Pride and Prejudice' } - ); + it('testLike', async () => { + const results = await randomCol + .pipeline() + .where(like('title', '%Guide%')) + .select('title') + .execute(); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy" }); + }); - it('arrayContainsAll works', async () => { - const results = await randomCol - .pipeline() - .where(Field.of('tags').arrayContainsAll('adventure', 'magic')) - .select('title') - .execute(); - expectResults(results, { title: 'The Lord of the Rings' }); - }); + it('testRegexContains', async () => { + const results = await randomCol + .pipeline() + .where(regexContains('title', '(?i)(the|of)')) + .execute(); + expect(results.length).to.equal(5); + }); - it('arrayLength works', async () => { - const results = await randomCol - .pipeline() - .select(Field.of('tags').arrayLength().as('tagsCount')) - .where(eq('tagsCount', 3)) - .execute(); - expect(results.length).to.equal(10); + it('testRegexMatches', async () => { + const results = await randomCol + .pipeline() + .where(regexMatch('title', '.*(?i)(the|of).*')) + .execute(); + expect(results.length).to.equal(5); + }); + + it('testArithmeticOperations', async () => { + const results = await randomCol + .pipeline() + .select( + add(Field.of('rating'), 1).as('ratingPlusOne'), + subtract(Field.of('published'), 1900).as('yearsSince1900'), + Field.of('rating').multiply(10).as('ratingTimesTen'), + Field.of('rating').divide(2).as('ratingDividedByTwo') + ) + .limit(1) + .execute(); + expectResults(results, { + ratingPlusOne: 5.2, + yearsSince1900: 79, + ratingTimesTen: 42, + ratingDividedByTwo: 2.1 }); + }); - it('testStrConcat', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('author') - .strConcat(' - ', Field.of('title')) - .as('bookInfo') + it('testComparisonOperators', async () => { + const results = await randomCol + .pipeline() + .where( + andFunction( + gt('rating', 4.2), + lte(Field.of('rating'), 4.5), + neq('genre', 'Science Fiction') ) - .limit(1) - .execute(); - expectResults(results, { - bookInfo: "Douglas Adams - The Hitchhiker's Guide to the Galaxy" - }); - }); + ) + .select('rating', 'title') + .sort(Field.of('title').ascending()) + .execute(); + expectResults( + results, + { rating: 4.3, title: 'Crime and Punishment' }, + { + rating: 4.3, + title: 'One Hundred Years of Solitude' + }, + { rating: 4.5, title: 'Pride and Prejudice' } + ); + }); - it('testStartsWith', async () => { - const results = await randomCol - .pipeline() - .where(startsWith('title', 'The')) - .select('title') - .sort(Field.of('title').ascending()) - .execute(); - expectResults( - results, - { title: 'The Great Gatsby' }, - { title: "The Handmaid's Tale" }, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'The Lord of the Rings' } - ); - }); + it('testLogicalOperators', async () => { + const results = await randomCol + .pipeline() + .where( + orFunction( + andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')), + lt('published', 1900) + ) + ) + .select('title') + .sort(Field.of('title').ascending()) + .execute(); + expectResults( + results, + { title: 'Crime and Punishment' }, + { title: 'Dune' }, + { title: 'Pride and Prejudice' } + ); + }); - it('testEndsWith', async () => { - const results = await randomCol - .pipeline() - .where(endsWith('title', 'y')) - .select('title') - .sort(Field.of('title').descending()) - .execute(); - expectResults( - results, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'The Great Gatsby' } - ); - }); + it('testChecks', async () => { + const results = await randomCol + .pipeline() + .where(not(Field.of('rating').isNaN())) + .select( + Field.of('rating').eq(null).as('ratingIsNull'), + not(Field.of('rating').isNaN()).as('ratingIsNotNaN') + ) + .limit(1) + .execute(); + expectResults(results, { ratingIsNull: false, ratingIsNotNaN: true }); + }); - it('testLength', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('title').charLength().as('titleLength'), - Field.of('title') - ) - .where(gt('titleLength', 20)) - .sort(Field.of('title').ascending()) - .execute(); + it('testMapGet', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('published').descending()) + .select( + Field.of('awards').mapGet('hugo').as('hugoAward'), + Field.of('awards').mapGet('others').as('others'), + Field.of('title') + ) + .where(eq('hugoAward', true)) + .execute(); + expectResults( + results, + { + hugoAward: true, + title: "The Hitchhiker's Guide to the Galaxy", + others: { unknown: { year: 1980 } } + }, + { hugoAward: true, hugoAward2: true, title: 'Dune', others: null } + ); + }); - expectResults( - results, + it('testDistanceFunctions', async () => { + const sourceVector = [0.1, 0.1]; + const targetVector = [0.5, 0.8]; + const results = await randomCol + .pipeline() + .select( + cosineDistance(Constant.vector(sourceVector), targetVector).as( + 'cosineDistance' + ), + dotProduct(Constant.vector(sourceVector), targetVector).as( + 'dotProductDistance' + ), + euclideanDistance(Constant.vector(sourceVector), targetVector).as( + 'euclideanDistance' + ) + ) + .limit(1) + .execute(); - { - titleLength: 29, - title: 'One Hundred Years of Solitude' - }, - { - titleLength: 36, - title: "The Hitchhiker's Guide to the Galaxy" - }, - { - titleLength: 21, - title: 'The Lord of the Rings' - }, - { - titleLength: 21, - title: 'To Kill a Mockingbird' - } - ); + expectResults(results, { + cosineDistance: 0.02560880430538015, + dotProductDistance: 0.13, + euclideanDistance: 0.806225774829855 }); + }); - it('testLike', async () => { - const results = await randomCol - .pipeline() - .where(like('title', '%Guide%')) - .select('title') - .execute(); - expectResults(results, { - title: "The Hitchhiker's Guide to the Galaxy" - }); - }); + it('testNestedFields', async () => { + const results = await randomCol + .pipeline() + .where(eq('awards.hugo', true)) + .select('title', 'awards.hugo') + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + 'awards.hugo': true + }, + { title: 'Dune', 'awards.hugo': true } + ); + }); - it('testRegexContains', async () => { - const results = await randomCol - .pipeline() - .where(regexContains('title', '(?i)(the|of)')) - .execute(); - expect(results.length).to.equal(5); - }); + it('test mapGet with field name including . notation', async () => { + const results = await randomCol + .pipeline() + .where(eq('awards.hugo', true)) + .select( + 'title', + Field.of('nestedField.level.1'), + mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') + ) + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + 'nestedField.level.`1`': null, + nested: true + }, + { title: 'Dune', 'nestedField.level.`1`': null, nested: null } + ); + }); - it('testRegexMatches', async () => { - const results = await randomCol - .pipeline() - .where(regexMatch('title', '.*(?i)(the|of).*')) - .execute(); - expect(results.length).to.equal(5); + it('supports countIf', async () => { + const results = await randomCol + .pipeline() + .aggregate(countif(Field.of('rating').gt(4.3)).as('count')) + .execute(); + expectResults(results, { + count: 3 }); + }); - it('testArithmeticOperations', async () => { + describe('genericFunction', () => { + it('add selectable', async () => { const results = await randomCol .pipeline() + .sort(descending('rating')) + .limit(1) .select( - add(Field.of('rating'), 1).as('ratingPlusOne'), - subtract(Field.of('published'), 1900).as('yearsSince1900'), - Field.of('rating').multiply(10).as('ratingTimesTen'), - Field.of('rating').divide(2).as('ratingDividedByTwo') + genericFunction('add', [Field.of('rating'), Constant.of(1)]).as( + 'rating' + ) ) - .limit(1) .execute(); expectResults(results, { - ratingPlusOne: 5.2, - yearsSince1900: 79, - ratingTimesTen: 42, - ratingDividedByTwo: 2.1 + rating: 5.7 }); }); - it('testComparisonOperators', async () => { + it('and (variadic) selectable', async () => { const results = await randomCol .pipeline() .where( - andFunction( - gt('rating', 4.2), - lte(Field.of('rating'), 4.5), - neq('genre', 'Science Fiction') - ) + genericFunction('and', [ + Field.of('rating').gt(0), + Field.of('title').charLength().lt(5), + Field.of('tags').arrayContains('propaganda') + ]) ) - .select('rating', 'title') - .sort(Field.of('title').ascending()) + .select('title') .execute(); - expectResults( - results, - { rating: 4.3, title: 'Crime and Punishment' }, - { - rating: 4.3, - title: 'One Hundred Years of Solitude' - }, - { rating: 4.5, title: 'Pride and Prejudice' } - ); + expectResults(results, { + title: '1984' + }); }); - it('testLogicalOperators', async () => { + it('array contains any', async () => { const results = await randomCol .pipeline() .where( - orFunction( - andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')), - lt('published', 1900) - ) + genericFunction('array_contains_any', [ + Field.of('tags'), + ['politics'] + ]) ) .select('title') - .sort(Field.of('title').ascending()) .execute(); - expectResults( - results, - { title: 'Crime and Punishment' }, - { title: 'Dune' }, - { title: 'Pride and Prejudice' } - ); + expectResults(results, { + title: 'Dune' + }); }); - it('testChecks', async () => { + it('countif aggregate', async () => { const results = await randomCol .pipeline() - .where(not(Field.of('rating').isNaN())) - .select( - Field.of('rating').eq(null).as('ratingIsNull'), - not(Field.of('rating').isNaN()).as('ratingIsNotNaN') + .aggregate( + genericFunction('countif', [Field.of('rating').gte(4.5)]).as( + 'countOfBest' + ) ) - .limit(1) .execute(); - expectResults(results, { ratingIsNull: false, ratingIsNotNaN: true }); + expectResults(results, { + countOfBest: 3 + }); }); - it('testMapGet', async () => { + it('sort by char_len', async () => { const results = await randomCol .pipeline() - .sort(Field.of('published').descending()) - .select( - Field.of('awards').mapGet('hugo').as('hugoAward'), - Field.of('awards').mapGet('others').as('others'), - Field.of('title') + .sort( + genericFunction('char_length', [Field.of('title')]).ascending(), + descending('__name__') ) - .where(eq('hugoAward', true)) + .limit(3) + .select('title') .execute(); expectResults( results, { - hugoAward: true, - title: "The Hitchhiker's Guide to the Galaxy", - others: { unknown: { year: 1980 } } + title: '1984' + }, + { + title: 'Dune' }, - { hugoAward: true, hugoAward2: true, title: 'Dune', others: null } + { + title: 'The Great Gatsby' + } ); }); + }); - it('testDistanceFunctions', async () => { - const sourceVector = [0.1, 0.1]; - const targetVector = [0.5, 0.8]; + describe.skip('not implemented in backend', () => { + it('supports Bit_and', async () => { const results = await randomCol .pipeline() - .select( - cosineDistance(Constant.vector(sourceVector), targetVector).as( - 'cosineDistance' - ), - dotProduct(Constant.vector(sourceVector), targetVector).as( - 'dotProductDistance' - ), - euclideanDistance(Constant.vector(sourceVector), targetVector).as( - 'euclideanDistance' - ) - ) .limit(1) + .select(bitAnd(Constant.of(5), 12).as('result')) .execute(); - expectResults(results, { - cosineDistance: 0.02560880430538015, - dotProductDistance: 0.13, - euclideanDistance: 0.806225774829855 + result: 4 }); }); - it('testNestedFields', async () => { + it('supports Bit_or', async () => { const results = await randomCol .pipeline() - .where(eq('awards.hugo', true)) - .select('title', 'awards.hugo') + .limit(1) + .select(bitOr(Constant.of(5), 12).as('result')) .execute(); - expectResults( - results, - { - title: "The Hitchhiker's Guide to the Galaxy", - 'awards.hugo': true - }, - { title: 'Dune', 'awards.hugo': true } - ); + expectResults(results, { + result: 13 + }); }); - it('test mapGet with field name including . notation', async () => { + it('supports Bit_xor', async () => { const results = await randomCol .pipeline() - .where(eq('awards.hugo', true)) - .select( - 'title', - Field.of('nestedField.level.1'), - mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') - ) + .limit(1) + .select(bitXor(Constant.of(5), 12).as('result')) .execute(); - expectResults( - results, - { - title: "The Hitchhiker's Guide to the Galaxy", - 'nestedField.level.`1`': null, - nested: true - }, - { title: 'Dune', 'nestedField.level.`1`': null, nested: null } - ); + expectResults(results, { + result: 9 + }); }); - it('supports countIf', async () => { + it('supports Bit_not', async () => { const results = await randomCol .pipeline() - .aggregate(countif(Field.of('rating').gt(4.3)).as('count')) + .limit(1) + .select( + bitNot(Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd)))).as( + 'result' + ) + ) .execute(); expectResults(results, { - count: 3 - }); - }); - - describe('genericFunction', () => { - it('add selectable', async () => { - const results = await randomCol - .pipeline() - .sort(descending('rating')) - .limit(1) - .select( - genericFunction('add', [Field.of('rating'), Constant.of(1)]).as( - 'rating' - ) - ) - .execute(); - expectResults(results, { - rating: 5.7 - }); - }); - - it('and (variadic) selectable', async () => { - const results = await randomCol - .pipeline() - .where( - genericFunction('and', [ - Field.of('rating').gt(0), - Field.of('title').charLength().lt(5), - Field.of('tags').arrayContains('propaganda') - ]) - ) - .select('title') - .execute(); - expectResults(results, { - title: '1984' - }); - }); - - it('array contains any', async () => { - const results = await randomCol - .pipeline() - .where( - genericFunction('array_contains_any', [ - Field.of('tags'), - ['politics'] - ]) - ) - .select('title') - .execute(); - expectResults(results, { - title: 'Dune' - }); - }); - - it('countif aggregate', async () => { - const results = await randomCol - .pipeline() - .aggregate( - genericFunction('countif', [Field.of('rating').gte(4.5)]).as( - 'countOfBest' - ) - ) - .execute(); - expectResults(results, { - countOfBest: 3 - }); - }); - - it('sort by char_len', async () => { - const results = await randomCol - .pipeline() - .sort( - genericFunction('char_length', [Field.of('title')]).ascending(), - descending('__name__') - ) - .limit(3) - .select('title') - .execute(); - expectResults( - results, - { - title: '1984' - }, - { - title: 'Dune' - }, - { - title: 'The Great Gatsby' - } - ); - }); - }); - - describe.skip('not implemented in backend', () => { - it('supports Bit_and', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select(bitAnd(Constant.of(5), 12).as('result')) - .execute(); - expectResults(results, { - result: 4 - }); - }); - - it('supports Bit_or', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select(bitOr(Constant.of(5), 12).as('result')) - .execute(); - expectResults(results, { - result: 13 - }); - }); - - it('supports Bit_xor', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select(bitXor(Constant.of(5), 12).as('result')) - .execute(); - expectResults(results, { - result: 9 - }); - }); - - it('supports Bit_not', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select( - bitNot( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd))) - ).as('result') - ) - .execute(); - expectResults(results, { - result: Bytes.fromUint8Array(Uint8Array.of(0x02)) - }); - }); - - it('supports Bit_left_shift', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select( - bitLeftShift( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), - 2 - ).as('result') - ) - .execute(); - expectResults(results, { - result: Bytes.fromUint8Array(Uint8Array.of(0x04)) - }); - }); - - it('supports Bit_right_shift', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select( - bitRightShift( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), - 2 - ).as('result') - ) - .execute(); - expectResults(results, { - result: Bytes.fromUint8Array(Uint8Array.of(0x01)) - }); - }); - - it('supports Document_id', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(documentIdFunction(Field.of('__path__')).as('docId')) - .execute(); - expectResults(results, { - docId: 'book4' - }); - }); - - it('supports Substr', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(substr('title', 9, 2).as('of')) - .execute(); - expectResults(results, { - of: 'of' - }); - }); - - it('arrayConcat works', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('tags') - .arrayConcat(['newTag1', 'newTag2']) - .as('modifiedTags') - ) - .limit(1) - .execute(); - expectResults(results, { - modifiedTags: [ - 'comedy', - 'space', - 'adventure', - 'newTag1', - 'newTag2' - ] - }); - }); - - it('testToLowercase', async () => { - const results = await randomCol - .pipeline() - .select(Field.of('title').toLower().as('lowercaseTitle')) - .limit(1) - .execute(); - expectResults(results, { - lowercaseTitle: "the hitchhiker's guide to the galaxy" - }); - }); - - it('testToUppercase', async () => { - const results = await randomCol - .pipeline() - .select(Field.of('author').toUpper().as('uppercaseAuthor')) - .limit(1) - .execute(); - expectResults(results, { uppercaseAuthor: 'DOUGLAS ADAMS' }); - }); - - it('testTrim', async () => { - const results = await randomCol - .pipeline() - .addFields( - Constant.of(" The Hitchhiker's Guide to the Galaxy ").as( - 'spacedTitle' - ) - ) - .select( - Field.of('spacedTitle').trim().as('trimmedTitle'), - Field.of('spacedTitle') - ) - .limit(1) - .execute(); - expectResults(results, { - spacedTitle: " The Hitchhiker's Guide to the Galaxy ", - trimmedTitle: "The Hitchhiker's Guide to the Galaxy" - }); + result: Bytes.fromUint8Array(Uint8Array.of(0x02)) }); }); - it('supports Rand', async () => { + it('supports Bit_left_shift', async () => { const results = await randomCol .pipeline() - .limit(10) - .select(rand().as('result')) + .limit(1) + .select( + bitLeftShift( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) .execute(); - expect(results.length).to.equal(10); - results.forEach(d => { - expect(d.get('result')).to.be.lt(1); - expect(d.get('result')).to.be.gte(0); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x04)) }); }); - it('supports array', async () => { - const result = await firestore + it('supports Bit_right_shift', async () => { + const results = await randomCol .pipeline() - .collection(randomCol.path) - .sort(Field.of('rating').descending()) .limit(1) - .select(array([1, 2, 3, 4]).as('metadata')) + .select( + bitRightShift( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) .execute(); - expect(result.length).to.equal(1); - expectResults(result, { - metadata: [1, 2, 3, 4] + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x01)) }); }); - it('evaluates expression in array', async () => { - const result = await firestore + it('supports Document_id', async () => { + const results = await randomCol .pipeline() - .collection(randomCol.path) .sort(Field.of('rating').descending()) .limit(1) - .select( - array([1, 2, Field.of('genre'), multiply('rating', 10)]).as( - 'metadata' - ) - ) + .select(documentIdFunction(Field.of('__path__')).as('docId')) .execute(); - expect(result.length).to.equal(1); - expectResults(result, { - metadata: [1, 2, 'Fantasy', 47] + expectResults(results, { + docId: 'book4' }); }); - it('supports arrayOffset', async () => { + it('supports Substr', async () => { const results = await randomCol .pipeline() .sort(Field.of('rating').descending()) - .limit(3) - .select(arrayOffset('tags', 0).as('firstTag')) + .limit(1) + .select(substr('title', 9, 2).as('of')) .execute(); - expectResults( - results, - { - firstTag: 'adventure' - }, - { - firstTag: 'politics' - }, - { - firstTag: 'classic' - } - ); + expectResults(results, { + of: 'of' + }); }); - // TODO: current_context tests with are failing because of b/395937453 - it('supports currentContext', async () => { + it('arrayConcat works', async () => { const results = await randomCol .pipeline() - .sort(Field.of('rating').descending()) + .select( + Field.of('tags') + .arrayConcat(['newTag1', 'newTag2']) + .as('modifiedTags') + ) .limit(1) - .select(currentContext().as('currentContext')) .execute(); expectResults(results, { - currentContext: 'TODO' + modifiedTags: ['comedy', 'space', 'adventure', 'newTag1', 'newTag2'] }); }); - it('supports isError', async () => { + it('testToLowercase', async () => { const results = await randomCol .pipeline() - .sort(Field.of('rating').descending()) + .select(Field.of('title').toLower().as('lowercaseTitle')) .limit(1) - .select(isError(arrayOffset('title', 0)).as('firstTag')) .execute(); expectResults(results, { - firstTag: true + lowercaseTitle: "the hitchhiker's guide to the galaxy" }); }); - it('supports ifError', async () => { + it('testToUppercase', async () => { const results = await randomCol .pipeline() - .sort(Field.of('rating').descending()) + .select(Field.of('author').toUpper().as('uppercaseAuthor')) .limit(1) - .select( - ifError(arrayOffset('title', 0), Constant.of('was error')).as( - 'firstTag' + .execute(); + expectResults(results, { uppercaseAuthor: 'DOUGLAS ADAMS' }); + }); + + it('testTrim', async () => { + const results = await randomCol + .pipeline() + .addFields( + Constant.of(" The Hitchhiker's Guide to the Galaxy ").as( + 'spacedTitle' ) ) + .select( + Field.of('spacedTitle').trim().as('trimmedTitle'), + Field.of('spacedTitle') + ) + .limit(1) .execute(); expectResults(results, { - firstTag: 'was error' + spacedTitle: " The Hitchhiker's Guide to the Galaxy ", + trimmedTitle: "The Hitchhiker's Guide to the Galaxy" }); }); + }); + + it('supports Rand', async () => { + const results = await randomCol + .pipeline() + .limit(10) + .select(rand().as('result')) + .execute(); + expect(results.length).to.equal(10); + results.forEach(d => { + expect(d.get('result')).to.be.lt(1); + expect(d.get('result')).to.be.gte(0); + }); + }); + + it('supports array', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select(array([1, 2, 3, 4]).as('metadata')) + .execute(); + expect(result.length).to.equal(1); + expectResults(result, { + metadata: [1, 2, 3, 4] + }); + }); + + it('evaluates expression in array', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + array([1, 2, Field.of('genre'), multiply('rating', 10)]).as( + 'metadata' + ) + ) + .execute(); + expect(result.length).to.equal(1); + expectResults(result, { + metadata: [1, 2, 'Fantasy', 47] + }); + }); + + it('supports arrayOffset', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(3) + .select(arrayOffset('tags', 0).as('firstTag')) + .execute(); + expectResults( + results, + { + firstTag: 'adventure' + }, + { + firstTag: 'politics' + }, + { + firstTag: 'classic' + } + ); + }); + + // TODO: current_context tests with are failing because of b/395937453 + it('supports currentContext', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(currentContext().as('currentContext')) + .execute(); + expectResults(results, { + currentContext: 'TODO' + }); + }); + + it('supports isError', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(isError(arrayOffset('title', 0)).as('firstTag')) + .execute(); + expectResults(results, { + firstTag: true + }); + }); - it('supports isAbsent', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(isAbsent('foo').as('firstTag')) - .execute(); - expectResults(results, { - firstTag: true - }); + it('supports ifError', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select( + ifError(arrayOffset('title', 0), Constant.of('was error')).as( + 'firstTag' + ) + ) + .execute(); + expectResults(results, { + firstTag: 'was error' }); + }); - it('supports isNull', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(isNull('remarks').as('remarksIsNull')) - .execute(); - expectResults(results, { - remarksIsNull: true - }); + it('supports isAbsent', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(isAbsent('foo').as('firstTag')) + .execute(); + expectResults(results, { + firstTag: true }); + }); - it('supports isNotNull', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(isNotNull('title').as('titleIsNotNull')) - .execute(); - expectResults(results, { - titleIsNotNull: true - }); + it('supports isNull', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(isNull('remarks').as('remarksIsNull')) + .execute(); + expectResults(results, { + remarksIsNull: true }); + }); - it('supports isNotNan', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(isNotNan('cost').as('costIsNotNan')) - .execute(); - expectResults(results, { - costIsNotNan: false - }); + it('supports isNotNull', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(isNotNull('title').as('titleIsNotNull')) + .execute(); + expectResults(results, { + titleIsNotNull: true }); + }); - it('supports map', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('rating').descending()) - .limit(1) - .select( - map({ - foo: 'bar' - }).as('metadata') - ) - .execute(); + it('supports isNotNan', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(isNotNan('cost').as('costIsNotNan')) + .execute(); + expectResults(results, { + costIsNotNan: false + }); + }); - expect(result.length).to.equal(1); - expectResults(result, { - metadata: { + it('supports map', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + map({ foo: 'bar' - } - }); + }).as('metadata') + ) + .execute(); + + expect(result.length).to.equal(1); + expectResults(result, { + metadata: { + foo: 'bar' + } }); + }); - it('evaluates expression in map', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('rating').descending()) - .limit(1) - .select( - map({ - genre: Field.of('genre'), - rating: Field.of('rating').multiply(10) - }).as('metadata') - ) - .execute(); + it('evaluates expression in map', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + map({ + genre: Field.of('genre'), + rating: Field.of('rating').multiply(10) + }).as('metadata') + ) + .execute(); - expect(result.length).to.equal(1); - expectResults(result, { - metadata: { - genre: 'Fantasy', - rating: 47 - } - }); + expect(result.length).to.equal(1); + expectResults(result, { + metadata: { + genre: 'Fantasy', + rating: 47 + } }); + }); - it('supports mapRemove', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(mapRemove('awards', 'hugo').as('awards')) - .execute(); - expectResults(results, { - awards: { nebula: false } - }); + it('supports mapRemove', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(mapRemove('awards', 'hugo').as('awards')) + .execute(); + expectResults(results, { + awards: { nebula: false } }); + }); - it('supports mapMerge', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(mapMerge('awards', { fakeAward: true }).as('awards')) - .execute(); - expectResults(results, { - awards: { nebula: false, hugo: false, fakeAward: true } - }); + it('supports mapMerge', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(mapMerge('awards', { fakeAward: true }).as('awards')) + .execute(); + expectResults(results, { + awards: { nebula: false, hugo: false, fakeAward: true } }); + }); - it('supports manhattanDistance', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Constant.vector([1, 1]).as('embedding')) - .addFields(manhattanDistance('embedding', [3, 3]).as('distance')) - .execute(); - expectResults(results, { - distance: 4, - embedding: vector([1, 1]) - }); + it('supports manhattanDistance', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Constant.vector([1, 1]).as('embedding')) + .addFields(manhattanDistance('embedding', [3, 3]).as('distance')) + .execute(); + expectResults(results, { + distance: 4, + embedding: vector([1, 1]) }); }); + }); - describe('pagination', () => { - /** - * Adds several books to the test collection. These - * additional books support pagination test scenarios - * that would otherwise not be possible with the original - * set of books. - * @param collection - */ - async function addBooks( - collection: CollectionReference - ): Promise { - await setDoc(doc(randomCol, 'book11'), { - title: 'Jonathan Strange & Mr Norrell', - author: 'Susanna Clarke', - genre: 'Fantasy', - published: 2004, - rating: 4.6, - tags: [ - 'historical fantasy', - 'magic', - 'alternate history', - 'england' - ], - awards: { hugo: false, nebula: false } - }); - await setDoc(doc(randomCol, 'book12'), { - title: 'The Master and Margarita', - author: 'Mikhail Bulgakov', - genre: 'Satire', - published: 1967, // Though written much earlier - rating: 4.6, - tags: [ - 'russian literature', - 'supernatural', - 'philosophy', - 'dark comedy' - ], - awards: {} - }); - await setDoc(doc(randomCol, 'book13'), { - title: 'A Long Way to a Small, Angry Planet', - author: 'Becky Chambers', - genre: 'Science Fiction', - published: 2014, - rating: 4.6, - tags: [ - 'space opera', - 'found family', - 'character-driven', - 'optimistic' - ], - awards: { hugo: false, nebula: false, kitschies: true } - }); - } - - it('supports pagination with filters', async () => { - await addBooks(randomCol); - const pageSize = 2; - const pipeline = randomCol - .pipeline() - .select('title', 'rating', '__name__') - .sort( - Field.of('rating').descending(), - Field.of('__name__').ascending() - ); + describe('pagination', () => { + /** + * Adds several books to the test collection. These + * additional books support pagination test scenarios + * that would otherwise not be possible with the original + * set of books. + * @param collection + */ + async function addBooks(collection: CollectionReference): Promise { + await setDoc(doc(randomCol, 'book11'), { + title: 'Jonathan Strange & Mr Norrell', + author: 'Susanna Clarke', + genre: 'Fantasy', + published: 2004, + rating: 4.6, + tags: ['historical fantasy', 'magic', 'alternate history', 'england'], + awards: { hugo: false, nebula: false } + }); + await setDoc(doc(randomCol, 'book12'), { + title: 'The Master and Margarita', + author: 'Mikhail Bulgakov', + genre: 'Satire', + published: 1967, // Though written much earlier + rating: 4.6, + tags: [ + 'russian literature', + 'supernatural', + 'philosophy', + 'dark comedy' + ], + awards: {} + }); + await setDoc(doc(randomCol, 'book13'), { + title: 'A Long Way to a Small, Angry Planet', + author: 'Becky Chambers', + genre: 'Science Fiction', + published: 2014, + rating: 4.6, + tags: [ + 'space opera', + 'found family', + 'character-driven', + 'optimistic' + ], + awards: { hugo: false, nebula: false, kitschies: true } + }); + } - let results = await pipeline.limit(pageSize).execute(); - expectResults( - results, - { title: 'The Lord of the Rings', rating: 4.7 }, - { title: 'Jonathan Strange & Mr Norrell', rating: 4.6 } + it('supports pagination with filters', async () => { + await addBooks(randomCol); + const pageSize = 2; + const pipeline = randomCol + .pipeline() + .select('title', 'rating', '__name__') + .sort( + Field.of('rating').descending(), + Field.of('__name__').ascending() ); - const lastDoc = results[results.length - 1]; + let results = await pipeline.limit(pageSize).execute(); + expectResults( + results, + { title: 'The Lord of the Rings', rating: 4.7 }, + { title: 'Jonathan Strange & Mr Norrell', rating: 4.6 } + ); - results = await pipeline - .where( - orFunction( - andFunction( - Field.of('rating').eq(lastDoc.get('rating')), - Field.of('__path__').gt(lastDoc.ref?.id) - ), - Field.of('rating').lt(lastDoc.get('rating')) - ) + const lastDoc = results[results.length - 1]; + + results = await pipeline + .where( + orFunction( + andFunction( + Field.of('rating').eq(lastDoc.get('rating')), + Field.of('__path__').gt(lastDoc.ref?.id) + ), + Field.of('rating').lt(lastDoc.get('rating')) ) - .limit(pageSize) - .execute(); - expectResults( - results, - { title: 'Pride and Prejudice', rating: 4.5 }, - { title: 'Crime and Punishment', rating: 4.3 } - ); - }); + ) + .limit(pageSize) + .execute(); + expectResults( + results, + { title: 'Pride and Prejudice', rating: 4.5 }, + { title: 'Crime and Punishment', rating: 4.3 } + ); + }); - it('supports pagination with offsets', async () => { - await addBooks(randomCol); + it('supports pagination with offsets', async () => { + await addBooks(randomCol); - const secondFilterField = '__path__'; + const secondFilterField = '__path__'; - const pipeline = randomCol - .pipeline() - .select('title', 'rating', secondFilterField) - .sort( - Field.of('rating').descending(), - Field.of(secondFilterField).ascending() - ); + const pipeline = randomCol + .pipeline() + .select('title', 'rating', secondFilterField) + .sort( + Field.of('rating').descending(), + Field.of(secondFilterField).ascending() + ); - const pageSize = 2; - let currPage = 0; + const pageSize = 2; + let currPage = 0; - let results = await pipeline - .offset(currPage++ * pageSize) - .limit(pageSize) - .execute(); + let results = await pipeline + .offset(currPage++ * pageSize) + .limit(pageSize) + .execute(); - expectResults( - results, - { - title: 'The Lord of the Rings', - rating: 4.7 - }, - { title: 'Dune', rating: 4.6 } - ); + expectResults( + results, + { + title: 'The Lord of the Rings', + rating: 4.7 + }, + { title: 'Dune', rating: 4.6 } + ); - results = await pipeline - .offset(currPage++ * pageSize) - .limit(pageSize) - .execute(); - expectResults( - results, - { - title: 'Jonathan Strange & Mr Norrell', - rating: 4.6 - }, - { title: 'The Master and Margarita', rating: 4.6 } - ); + results = await pipeline + .offset(currPage++ * pageSize) + .limit(pageSize) + .execute(); + expectResults( + results, + { + title: 'Jonathan Strange & Mr Norrell', + rating: 4.6 + }, + { title: 'The Master and Margarita', rating: 4.6 } + ); - results = await pipeline - .offset(currPage++ * pageSize) - .limit(pageSize) - .execute(); - expectResults( - results, - { - title: 'A Long Way to a Small, Angry Planet', - rating: 4.6 - }, - { - title: 'Pride and Prejudice', - rating: 4.5 - } - ); - }); + results = await pipeline + .offset(currPage++ * pageSize) + .limit(pageSize) + .execute(); + expectResults( + results, + { + title: 'A Long Way to a Small, Angry Planet', + rating: 4.6 + }, + { + title: 'Pride and Prejudice', + rating: 4.5 + } + ); }); }); From 35a361d3d14cba5991768e3da2aedd67a97dbde7 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 13 Feb 2025 15:37:00 -0700 Subject: [PATCH 24/75] Implement support for genericStage and genericFunction --- .../firestore/src/lite-api/expressions.ts | 68 +++++++++++++++++-- packages/firestore/src/lite-api/pipeline.ts | 20 +++++- packages/firestore/src/lite-api/stage.ts | 8 ++- 3 files changed, 85 insertions(+), 11 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index e416fdbbc50..e19ed6f9d96 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -2175,6 +2175,29 @@ export class Constant extends Expr { } } +/** + * Internal only + * @internal + * @private + */ +export class MapValue extends Expr { + constructor(private plainObject: Map) { + super(); + } + + exprType: ExprType = 'Constant'; + + _readUserData(dataReader: UserDataReader): void { + this.plainObject.forEach(expr => { + expr._readUserData(dataReader); + }); + } + + _toProto(serializer: JsonProtoSerializer): ProtoValue { + return toMapValue(serializer, this.plainObject); + } +} + /** * @beta * @@ -2214,6 +2237,17 @@ export class FirestoreFunction extends Expr { } } +/** + * @beta + */ +export class GenericFunction + extends FirestoreFunction + implements FilterCondition, Accumulator +{ + accumulator: true = true; + filterable: true = true; +} + /** * @beta */ @@ -4098,6 +4132,28 @@ export function map(elements: Record): MapFunction { return new MapFunction(result); } +/** + * Internal use only + * Converts a plainObject to a mapValue in the proto representation, + * rather than a functionValue+map that is the result of the map(...) function. + * This behaves different than Constant.of(plainObject) because it + * traverses the input object, converts values in the object to expressions, + * and calls _readUserData on each of these expressions. + * @private + * @internal + * @param plainObject + */ +export function _mapValue(plainObject: Record): MapValue { + const result: Map = new Map(); + for (const key in plainObject) { + if (Object.prototype.hasOwnProperty.call(plainObject, key)) { + const value = plainObject[key]; + result.set(key, valueToDefaultExpr(value)); + } + } + return new MapValue(result); +} + export function array(elements: any[]): ArrayFunction { return new ArrayFunction( elements.map(element => valueToDefaultExpr(element)) @@ -7499,15 +7555,15 @@ export function timestampSub( * genericFunction("sum", [Field.of("price")]); * ``` * - * @param name The name of the user defined function. + * @param functionName The name of the user defined function. * @param params The arguments to pass to the function. - * @return A new {@code Function} representing the function call. + * @return A new {@code GenericFucntion} representing the function call. */ export function genericFunction( - name: string, - params: Expr[] -): FirestoreFunction { - return new FirestoreFunction(name, params); + functionName: string, + params: any[] +): GenericFunction { + return new GenericFunction(functionName, params.map(valueToDefaultExpr)); } /** diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index 3663c7a88d5..c2fc83c0d19 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -34,6 +34,7 @@ import { isPlainObject } from '../util/input_validation'; import { getDatastore } from './components'; import { Firestore } from './database'; import { + _mapValue, Accumulator, AccumulatorTarget, Constant, @@ -672,12 +673,27 @@ export class Pipeline implements ProtoSerializable { */ genericStage(name: string, params: any[]): Pipeline { const copy = this.stages.map(s => s); - params.forEach(param => { + + // Convert input values to Expressions. + // We treat objects as mapValues and arrays as arrayValues, + // this is unlike the default conversion for objects and arrays + // passed to an expression. + const expressionParams = params.map((value: any) => { + if (value instanceof Expr) { + return value; + } else if (isPlainObject(value)) { + return _mapValue(value); + } else { + return Constant.of(value); + } + }); + + expressionParams.forEach(param => { if (isReadableUserData(param)) { param._readUserData(this.userDataReader); } }); - copy.push(new GenericStage(name, params)); + copy.push(new GenericStage(name, expressionParams)); return this.newPipeline( this._db, this.userDataReader, diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index 886daf98a8d..a30148ebc78 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -384,14 +384,16 @@ export class Sort implements Stage { * @beta */ export class GenericStage implements Stage { - constructor(public name: string, params: unknown[]) {} + constructor(public name: string, private params: Expr[]) {} /** * @internal * @private */ _toProto(serializer: JsonProtoSerializer): ProtoStage { - // TODO support generic stage - return {}; + return { + name: this.name, + args: this.params.map(o => o._toProto(serializer)) + }; } } From da71f9a382b4e4a8768f7a7ab9e5ee8a91af35b7 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 19 Feb 2025 15:55:48 -0700 Subject: [PATCH 25/75] Implement new function expressions as methods on the Expr class. --- .../firestore/src/lite-api/expressions.ts | 1492 ++++++++++++----- .../test/integration/api/pipeline.test.ts | 611 ++++--- 2 files changed, 1521 insertions(+), 582 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index e19ed6f9d96..42e4ec9f8bf 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -83,16 +83,18 @@ function valueToDefaultExpr(value: any): Expr { /** * Converts a value to an Expr, Returning either a Constant, MapFunction, * ArrayFunction, or the input itself (if it's already an expression). + * If the input is a string, it is assumed to be a field name, and a + * Field.of(value) is returned. * * @private * @internal * @param value */ -function fieldOfOrExpr(value: string | Expr): Expr { +function fieldOfOrExpr(value: any): Expr { if (isString(value)) { return Field.of(value); } else { - return value; + return valueToDefaultExpr(value); } } @@ -261,180 +263,6 @@ export abstract class Expr implements ProtoSerializable, UserData { return new Mod(this, valueToDefaultExpr(other)); } - // /** - // * Creates an expression that applies a bitwise AND operation between this expression and another expression. - // * - // * ```typescript - // * // Calculate the bitwise AND of 'field1' and 'field2'. - // * Field.of("field1").bitAnd(Field.of("field2")); - // * ``` - // * - // * @param other The right operand expression. - // * @return A new {@code Expr} representing the bitwise AND operation. - // */ - // bitAnd(other: Expr): BitAnd; - // - // /** - // * Creates an expression that applies a bitwise AND operation between this expression and a constant value. - // * - // * ```typescript - // * // Calculate the bitwise AND of 'field1' and 0xFF. - // * Field.of("field1").bitAnd(0xFF); - // * ``` - // * - // * @param other The right operand constant. - // * @return A new {@code Expr} representing the bitwise AND operation. - // */ - // bitAnd(other: any): BitAnd; - // bitAnd(other: any): BitAnd { - // if (other instanceof Expr) { - // return new BitAnd(this, other); - // } - // return new BitAnd(this, Constant.of(other)); - // } - // - // /** - // * Creates an expression that applies a bitwise OR operation between this expression and another expression. - // * - // * ```typescript - // * // Calculate the bitwise OR of 'field1' and 'field2'. - // * Field.of("field1").bitOr(Field.of("field2")); - // * ``` - // * - // * @param other The right operand expression. - // * @return A new {@code Expr} representing the bitwise OR operation. - // */ - // bitOr(other: Expr): BitOr; - // - // /** - // * Creates an expression that applies a bitwise OR operation between this expression and a constant value. - // * - // * ```typescript - // * // Calculate the bitwise OR of 'field1' and 0xFF. - // * Field.of("field1").bitOr(0xFF); - // * ``` - // * - // * @param other The right operand constant. - // * @return A new {@code Expr} representing the bitwise OR operation. - // */ - // bitOr(other: any): BitOr; - // bitOr(other: any): BitOr { - // if (other instanceof Expr) { - // return new BitOr(this, other); - // } - // return new BitOr(this, Constant.of(other)); - // } - // - // /** - // * Creates an expression that applies a bitwise XOR operation between this expression and another expression. - // * - // * ```typescript - // * // Calculate the bitwise XOR of 'field1' and 'field2'. - // * Field.of("field1").bitXor(Field.of("field2")); - // * ``` - // * - // * @param other The right operand expression. - // * @return A new {@code Expr} representing the bitwise XOR operation. - // */ - // bitXor(other: Expr): BitXor; - // - // /** - // * Creates an expression that applies a bitwise XOR operation between this expression and a constant value. - // * - // * ```typescript - // * // Calculate the bitwise XOR of 'field1' and 0xFF. - // * Field.of("field1").bitXor(0xFF); - // * ``` - // * - // * @param other The right operand constant. - // * @return A new {@code Expr} representing the bitwise XOR operation. - // */ - // bitXor(other: any): BitXor; - // bitXor(other: any): BitXor { - // if (other instanceof Expr) { - // return new BitXor(this, other); - // } - // return new BitXor(this, Constant.of(other)); - // } - // - // /** - // * Creates an expression that applies a bitwise NOT operation to this expression. - // * - // * ```typescript - // * // Calculate the bitwise NOT of 'field1'. - // * Field.of("field1").bitNot(); - // * ``` - // * - // * @return A new {@code Expr} representing the bitwise NOT operation. - // */ - // bitNot(): BitNot { - // return new BitNot(this); - // } - // - // /** - // * Creates an expression that applies a bitwise left shift operation between this expression and another expression. - // * - // * ```typescript - // * // Calculate the bitwise left shift of 'field1' by 'field2' bits. - // * Field.of("field1").bitLeftShift(Field.of("field2")); - // * ``` - // * - // * @param other The right operand expression representing the number of bits to shift. - // * @return A new {@code Expr} representing the bitwise left shift operation. - // */ - // bitLeftShift(other: Expr): BitLeftShift; - // - // /** - // * Creates an expression that applies a bitwise left shift operation between this expression and a constant value. - // * - // * ```typescript - // * // Calculate the bitwise left shift of 'field1' by 2 bits. - // * Field.of("field1").bitLeftShift(2); - // * ``` - // * - // * @param other The right operand constant representing the number of bits to shift. - // * @return A new {@code Expr} representing the bitwise left shift operation. - // */ - // bitLeftShift(other: number): BitLeftShift; - // bitLeftShift(other: Expr | number): BitLeftShift { - // if (typeof other === 'number') { - // return new BitLeftShift(this, Constant.of(other)); - // } - // return new BitLeftShift(this, other as Expr); - // } - // - // /** - // * Creates an expression that applies a bitwise right shift operation between this expression and another expression. - // * - // * ```typescript - // * // Calculate the bitwise right shift of 'field1' by 'field2' bits. - // * Field.of("field1").bitRightShift(Field.of("field2")); - // * ``` - // * - // * @param other The right operand expression representing the number of bits to shift. - // * @return A new {@code Expr} representing the bitwise right shift operation. - // */ - // bitRightShift(other: Expr): BitRightShift; - // - // /** - // * Creates an expression that applies a bitwise right shift operation between this expression and a constant value. - // * - // * ```typescript - // * // Calculate the bitwise right shift of 'field1' by 2 bits. - // * Field.of("field1").bitRightShift(2); - // * ``` - // * - // * @param other The right operand constant representing the number of bits to shift. - // * @return A new {@code Expr} representing the bitwise right shift operation. - // */ - // bitRightShift(other: number): BitRightShift; - // bitRightShift(other: Expr | number): BitRightShift { - // if (typeof other === 'number') { - // return new BitRightShift(this, Constant.of(other)); - // } - // return new BitRightShift(this, other as Expr); - // } - /** * Creates an expression that checks if this expression is equal to another expression. * @@ -834,6 +662,20 @@ export abstract class Expr implements ProtoSerializable, UserData { return new IsNan(this); } + /** + * Creates an expression that checks if this expression evaluates to 'Null'. + * + * ```typescript + * // Check if the result of a calculation is NaN + * Field.of("value").isNull(); + * ``` + * + * @return A new `Expr` representing the 'isNull' check. + */ + isNull(): IsNull { + return new IsNull(this); + } + /** * Creates an expression that checks if a field exists in the document. * @@ -1311,6 +1153,21 @@ export abstract class Expr implements ProtoSerializable, UserData { return new Maximum(this, false); } + /** + * Creates an aggregation that finds the count of input documents satisfying + * the conditional expression. + * + * ```typescript + * // Find the count of documents with a score greater than 90 + * Field.of("score").gt(90).countIf().as("highestScore"); + * ``` + * + * @return A new `Accumulator` representing the 'countIf' aggregation. + */ + countif(): Countif { + return new Countif(this); + } + /** * Creates an expression that returns the larger value between this expression and another expression, based on Firestore's value type ordering. * @@ -1717,6 +1574,467 @@ export abstract class Expr implements ProtoSerializable, UserData { ); } + /** + * @beta + * + * Creates an expression that applies a bitwise AND operation between this expression and a constant. + * + * ```typescript + * // Calculate the bitwise AND of 'field1' and 0xFF. + * Field.of("field1").bitAnd(0xFF); + * ``` + * + * @param otherBits A constant representing bits. + * @return A new {@code Expr} representing the bitwise AND operation. + */ + bitAnd(otherBits: number | Bytes): BitAnd; + /** + * @beta + * + * Creates an expression that applies a bitwise AND operation between two expressions. + * + * ```typescript + * // Calculate the bitwise AND of 'field1' and 'field2'. + * Field.of("field1").bitAnd(Field.of("field2")); + * ``` + * + * @param bitsExpression An expression that returns bits when evaluated. + * @return A new {@code Expr} representing the bitwise AND operation. + */ + bitAnd(bitsExpression: Expr): BitAnd; + bitAnd(bitsOrExpression: number | Expr | Bytes): BitAnd { + return new BitAnd(this, valueToDefaultExpr(bitsOrExpression)); + } + + /** + * @beta + * + * Creates an expression that applies a bitwise OR operation between this expression and a constant. + * + * ```typescript + * // Calculate the bitwise OR of 'field1' and 0xFF. + * Field.of("field1").bitOr(0xFF); + * ``` + * + * @param otherBits A constant representing bits. + * @return A new {@code Expr} representing the bitwise OR operation. + */ + bitOr(otherBits: number | Bytes): BitOr; + /** + * @beta + * + * Creates an expression that applies a bitwise OR operation between two expressions. + * + * ```typescript + * // Calculate the bitwise OR of 'field1' and 'field2'. + * Field.of("field1").bitOr(Field.of("field2")); + * ``` + * + * @param bitsExpression An expression that returns bits when evaluated. + * @return A new {@code Expr} representing the bitwise OR operation. + */ + bitOr(bitsExpression: Expr): BitOr; + bitOr(bitsOrExpression: number | Expr | Bytes): BitOr { + return new BitOr(this, valueToDefaultExpr(bitsOrExpression)); + } + + /** + * @beta + * + * Creates an expression that applies a bitwise XOR operation between this expression and a constant. + * + * ```typescript + * // Calculate the bitwise XOR of 'field1' and 0xFF. + * Field.of("field1").bitXor(0xFF); + * ``` + * + * @param otherBits A constant representing bits. + * @return A new {@code Expr} representing the bitwise XOR operation. + */ + bitXor(otherBits: number | Bytes): BitXor; + /** + * @beta + * + * Creates an expression that applies a bitwise XOR operation between two expressions. + * + * ```typescript + * // Calculate the bitwise XOR of 'field1' and 'field2'. + * Field.of("field1").bitXor(Field.of("field2")); + * ``` + * + * @param bitsExpression An expression that returns bits when evaluated. + * @return A new {@code Expr} representing the bitwise XOR operation. + */ + bitXor(bitsExpression: Expr): BitXor; + bitXor(bitsOrExpression: number | Expr | Bytes): BitXor { + return new BitXor(this, valueToDefaultExpr(bitsOrExpression)); + } + + /** + * @beta + * + * Creates an expression that applies a bitwise NOT operation to this expression. + * + * ```typescript + * // Calculate the bitwise NOT of 'field1'. + * Field.of("field1").bitNot(); + * ``` + * + * @return A new {@code Expr} representing the bitwise NOT operation. + */ + bitNot(): BitNot { + return new BitNot(this); + } + + /** + * @beta + * + * Creates an expression that applies a bitwise left shift operation to this expression. + * + * ```typescript + * // Calculate the bitwise left shift of 'field1' by 2 bits. + * Field.of("field1").bitLeftShift(2); + * ``` + * + * @param y The operand constant representing the number of bits to shift. + * @return A new {@code Expr} representing the bitwise left shift operation. + */ + bitLeftShift(y: number): BitLeftShift; + /** + * @beta + * + * Creates an expression that applies a bitwise left shift operation to this expression. + * + * ```typescript + * // Calculate the bitwise left shift of 'field1' by 'field2' bits. + * Field.of("field1").bitLeftShift(Field.of("field2")); + * ``` + * + * @param numberExpr The operand expression representing the number of bits to shift. + * @return A new {@code Expr} representing the bitwise left shift operation. + */ + bitLeftShift(numberExpr: Expr): BitLeftShift; + bitLeftShift(numberExpr: number | Expr): BitLeftShift { + return new BitLeftShift(this, valueToDefaultExpr(numberExpr)); + } + + /** + * @beta + * + * Creates an expression that applies a bitwise right shift operation to this expression. + * + * ```typescript + * // Calculate the bitwise right shift of 'field1' by 2 bits. + * Field.of("field1").bitRightShift(2); + * ``` + * + * @param right The operand constant representing the number of bits to shift. + * @return A new {@code Expr} representing the bitwise right shift operation. + */ + bitRightShift(y: number): BitRightShift; + /** + * @beta + * + * Creates an expression that applies a bitwise right shift operation to this expression. + * + * ```typescript + * // Calculate the bitwise right shift of 'field1' by 'field2' bits. + * Field.of("field1").bitRightShift(Field.of("field2")); + * ``` + * + * @param numberExpr The operand expression representing the number of bits to shift. + * @return A new {@code Expr} representing the bitwise right shift operation. + */ + bitRightShift(numberExpr: Expr): BitRightShift; + bitRightShift(numberExpr: number | Expr): BitRightShift { + return new BitRightShift(this, valueToDefaultExpr(numberExpr)); + } + + /** + * @beta + * + * Creates an expression that returns the document ID from a path. + * + * ```typescript + * // Get the document ID from a path. + * Field.of("__path__").documentId(); + * ``` + * + * @return A new {@code Expr} representing the documentId operation. + */ + documentId(): DocumentId { + return new DocumentId(this); + } + + /** + * @beta + * + * Creates an expression that returns a substring of the results of this expression. + * + * @param position Index of the first character of the substring. + * @param length Length of the substring. + */ + substr(position: number, length: number): Substr; + + /** + * @beta + * + * Creates an expression that returns a substring of the results of this expression. + * + * @param position An expression returning the index of the first character of the substring. + * @param length An expression returning the length of the substring. + */ + substr(position: Expr, length: Expr): Substr; + substr(position: Expr | number, length: Expr | number): Substr { + const positionExpr = valueToDefaultExpr(position); + const lengthExpr = valueToDefaultExpr(length); + return new Substr(this, positionExpr, lengthExpr); + } + + /** + * @beta + * Creates an expression that indexes into an array from the beginning or end + * and returns the element. If the offset exceeds the array length, an error is + * returned. A negative offset, starts from the end. + * + * ```typescript + * // Return the value in the 'tags' field array at index `1`. + * Field.of('tags').arrayOffset(1); + * ``` + * + * @param offset The index of the element to return. + * @return A new Expr representing the 'arrayOffset' operation. + */ + arrayOffset(offset: number): ArrayOffset; + + /** + * @beta + * Creates an expression that indexes into an array from the beginning or end + * and returns the element. If the offset exceeds the array length, an error is + * returned. A negative offset, starts from the end. + * + * ```typescript + * // Return the value in the tags field array at index specified by field + * // 'favoriteTag'. + * Field.of('tags').arrayOffset(Field.of('favoriteTag')); + * ``` + * + * @param offsetExpr An Expr evaluating to the index of the element to return. + * @return A new Expr representing the 'arrayOffset' operation. + */ + arrayOffset(offsetExpr: Expr): ArrayOffset; + arrayOffset(offset: Expr | number): ArrayOffset { + return new ArrayOffset(fieldOfOrExpr(array), valueToDefaultExpr(offset)); + } + + /** + * @beta + * + * Creates an expression that checks if a given expression produces an error. + * + * ```typescript + * // Check if the result of a calculation is an error + * Field.of("title").arrayContains(1).isError(); + * ``` + * + * @return A new {@code Expr} representing the 'isError' check. + */ + isError(): IsError { + return new IsError(this); + } + + /** + * @beta + * + * Creates an expression that returns the result of the `catchExpr` argument + * if there is an error, else return the result of this expression. + * + * ```typescript + * // Returns the first item in the title field arrays, or returns + * // the entire title field if the array is empty or the field is another type. + * Field.of("title").arrayOffset(0).ifError(Field.of("title")); + * ``` + * + * @param catchExpr The catch expression that will be evaluated and + * returned if this expression produces an error. + * @return A new {@code Expr} representing the 'ifError' operation. + */ + ifError(catchExpr: Expr): IfError; + + /** + * @beta + * + * Creates an expression that returns the `catch` argument if there is an + * error, else return the result of this expression. + * + * ```typescript + * // Returns the first item in the title field arrays, or returns + * // "Default Title" + * Field.of("title").arrayOffset(0).ifError("Default Title"); + * ``` + * + * @param catchValue The value that will be returned if this expression + * produces an error. + * @return A new {@code Expr} representing the 'ifError' operation. + */ + ifError(catchValue: any): IfError; + ifError(catchValue: any): IfError { + return new IfError(this, valueToDefaultExpr(catchValue)); + } + + /** + * @beta + * + * Creates an expression that returns `true` if the result of this expression + * is absent. Otherwise, returns `false` even if the value is `null`. + * + * ```typescript + * // Check if the field `value` is absent. + * Field.of("value").isAbsent(); + * ``` + * + * @return A new {@code Expr} representing the 'isAbsent' check. + */ + isAbsent(): IsAbsent { + return new IsAbsent(this); + } + + /** + * @beta + * + * Creates an expression that checks if tbe result of an expression is not null. + * + * ```typescript + * // Check if the value of the 'name' field is not null + * Field.of("name").isNotNull(); + * ``` + * + * @return A new {@code Expr} representing the 'isNotNull' check. + */ + isNotNull(): IsNotNull { + return new IsNotNull(this); + } + + /** + * @beta + * + * Creates an expression that checks if the results of this expression is NOT 'NaN' (Not a Number). + * + * ```typescript + * // Check if the result of a calculation is NOT NaN + * Field.of("value").divide(0).isNotNan(); + * ``` + * + * @return A new {@code Expr} representing the 'isNaN' check. + */ + isNotNan(): IsNotNan { + return new IsNotNan(this); + } + + /** + * @beta + * + * Creates an expression that removes a key from the map produced by evaluating this expression. + * + * ``` + * // Removes the key 'baz' from the input map. + * map({foo: 'bar', baz: true}).mapRemove('baz'); + * ``` + * + * @param key The name of the key to remove from the input map. + */ + mapRemove(key: string): MapRemove; + /** + * @beta + * + * Creates an expression that removes a key from the map produced by evaluating this expression. + * + * ``` + * // Removes the key 'baz' from the input map. + * map({foo: 'bar', baz: true}).mapRemove(Constant.of('baz')); + * ``` + * + * @param keyExpr An expression that produces the name of the key to remove from the input map. + */ + mapRemove(keyExpr: Expr): MapRemove; + mapRemove(stringExpr: Expr | string): MapRemove { + return new MapRemove(this, valueToDefaultExpr(stringExpr)); + } + + /** + * @beta + * + * Creates an expression that merges multiple map values. + * + * ``` + * // Merges the map in the settings field with, a map literal, and a map in + * // that is conditionally returned by another expression + * Field.of('settings').mapMerge({ enabled: true }, cond(Field.of('isAdmin'), { admin: true}, {}) + * ``` + * + * @param secondMap A required second map to merge. Represented as a literal or + * an expression that returns a map. + * @param otherMaps Optional additional maps to merge. Each map is represented + * as a literal or an expression that returns a map. + */ + mapMerge( + secondMap: Record | Expr, + ...otherMaps: Array | Expr> + ): MapMerge { + const secondMapExpr = valueToDefaultExpr(secondMap); + const otherMapExprs = otherMaps.map(valueToDefaultExpr); + return new MapMerge([this, secondMapExpr, ...otherMapExprs]); + } + + /** + * @beta + * + * Calculates the Manhattan distance between the result of this expression and another VectorValue. + * + * ```typescript + * // Calculate the Manhattan distance between the 'location' field and a target location + * Field.of("location").manhattanDistance(new VectorValue([37.7749, -122.4194])); + * ``` + * + * @param other The other vector (as a VectorValue) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ + manhattanDistance(other: VectorValue): ManhattanDistance; + + /** + * @beta + * + * Calculates the Manhattan distance between the result of this expression and a double array. + * + * ```typescript + * // Calculate the Manhattan distance between the 'location' field and a target location + * Field.of("location").manhattanDistance([37.7749, -122.4194]); + * ``` + * + * @param other The other vector (as an array of doubles) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ + manhattanDistance(other: number[]): ManhattanDistance; + + /** + * @beta + * + * Calculates the Manhattan distance between two vector expressions. + * + * ```typescript + * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' + * Field.of("pointA").manhattanDistance(Field.of("pointB")); + * ``` + * + * @param other The other vector (represented as an Expr) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ + manhattanDistance(other: Expr): ManhattanDistance; + manhattanDistance(other: Expr | number[] | VectorValue): ManhattanDistance { + const expr2 = other instanceof Expr ? other : Constant.vector(other); + return new ManhattanDistance(this, expr2); + } + /** * Creates an {@link Ordering} that sorts documents in ascending order based on this expression. * @@ -1853,6 +2171,7 @@ export class ExprWithAlias extends Selectable { */ class ListOfExprs extends Expr { exprType: ExprType = 'ListOfExprs'; + constructor(private exprs: Expr[]) { super(); } @@ -2209,6 +2528,7 @@ export class MapValue extends Expr { */ export class FirestoreFunction extends Expr { exprType: ExprType = 'Function'; + constructor(private name: string, private params: Expr[]) { super(); } @@ -2305,75 +2625,6 @@ export class ArrayFunction extends FirestoreFunction { } } -// /** -// * @beta -// */ -// export class BitAnd extends FirestoreFunction { -// constructor( -// private left: Expr, -// private right: Expr -// ) { -// super('bit_and', [left, right]); -// } -// } -// -// /** -// * @beta -// */ -// export class BitOr extends FirestoreFunction { -// constructor( -// private left: Expr, -// private right: Expr -// ) { -// super('bit_or', [left, right]); -// } -// } -// -// /** -// * @beta -// */ -// export class BitXor extends FirestoreFunction { -// constructor( -// private left: Expr, -// private right: Expr -// ) { -// super('bit_xor', [left, right]); -// } -// } -// -// /** -// * @beta -// */ -// export class BitNot extends FirestoreFunction { -// constructor(private operand: Expr) { -// super('bit_not', [operand]); -// } -// } -// -// /** -// * @beta -// */ -// export class BitLeftShift extends FirestoreFunction { -// constructor( -// private left: Expr, -// private right: Expr -// ) { -// super('bit_left_shift', [left, right]); -// } -// } -// -// /** -// * @beta -// */ -// export class BitRightShift extends FirestoreFunction { -// constructor( -// private left: Expr, -// private right: Expr -// ) { -// super('bit_right_shift', [left, right]); -// } -// } - /** * @beta */ @@ -2381,6 +2632,7 @@ export class Eq extends FirestoreFunction implements FilterCondition { constructor(private left: Expr, private right: Expr) { super('eq', [left, right]); } + filterable = true as const; } @@ -2391,6 +2643,7 @@ export class Neq extends FirestoreFunction implements FilterCondition { constructor(private left: Expr, private right: Expr) { super('neq', [left, right]); } + filterable = true as const; } @@ -2401,6 +2654,7 @@ export class Lt extends FirestoreFunction implements FilterCondition { constructor(private left: Expr, private right: Expr) { super('lt', [left, right]); } + filterable = true as const; } @@ -2411,6 +2665,7 @@ export class Lte extends FirestoreFunction implements FilterCondition { constructor(private left: Expr, private right: Expr) { super('lte', [left, right]); } + filterable = true as const; } @@ -2421,6 +2676,7 @@ export class Gt extends FirestoreFunction implements FilterCondition { constructor(private left: Expr, private right: Expr) { super('gt', [left, right]); } + filterable = true as const; } @@ -2431,6 +2687,7 @@ export class Gte extends FirestoreFunction implements FilterCondition { constructor(private left: Expr, private right: Expr) { super('gte', [left, right]); } + filterable = true as const; } @@ -2462,6 +2719,7 @@ export class ArrayContains constructor(private array: Expr, private element: Expr) { super('array_contains', [array, element]); } + filterable = true as const; } @@ -2475,6 +2733,7 @@ export class ArrayContainsAll constructor(private array: Expr, private values: Expr[]) { super('array_contains_all', [array, new ListOfExprs(values)]); } + filterable = true as const; } @@ -2488,6 +2747,7 @@ export class ArrayContainsAny constructor(private array: Expr, private values: Expr[]) { super('array_contains_any', [array, new ListOfExprs(values)]); } + filterable = true as const; } @@ -2516,6 +2776,7 @@ export class EqAny extends FirestoreFunction implements FilterCondition { constructor(private left: Expr, private others: Expr[]) { super('eq_any', [left, new ListOfExprs(others)]); } + filterable = true as const; } @@ -2526,6 +2787,7 @@ export class NotEqAny extends FirestoreFunction implements FilterCondition { constructor(private left: Expr, private others: Expr[]) { super('not_eq_any', [left, new ListOfExprs(others)]); } + filterable = true as const; } @@ -2536,6 +2798,7 @@ export class IsNan extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr) { super('is_nan', [expr]); } + filterable = true as const; } @@ -2546,6 +2809,7 @@ export class Exists extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr) { super('exists', [expr]); } + filterable = true as const; } @@ -2556,6 +2820,7 @@ export class Not extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr) { super('not', [expr]); } + filterable = true as const; } @@ -2577,6 +2842,7 @@ export class Or extends FirestoreFunction implements FilterCondition { constructor(private conditions: FilterCondition[]) { super('or', conditions); } + filterable = true as const; } @@ -2587,6 +2853,7 @@ export class Xor extends FirestoreFunction implements FilterCondition { constructor(private conditions: FilterCondition[]) { super('xor', conditions); } + filterable = true as const; } @@ -2601,6 +2868,7 @@ export class Cond extends FirestoreFunction { ) { super('cond', [condition, thenExpr, elseExpr]); } + filterable = true as const; } @@ -2674,6 +2942,7 @@ export class Like extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr, private pattern: Expr) { super('like', [expr, pattern]); } + filterable = true as const; } @@ -2687,6 +2956,7 @@ export class RegexContains constructor(private expr: Expr, private pattern: Expr) { super('regex_contains', [expr, pattern]); } + filterable = true as const; } @@ -2697,6 +2967,7 @@ export class RegexMatch extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr, private pattern: Expr) { super('regex_match', [expr, pattern]); } + filterable = true as const; } @@ -2707,6 +2978,7 @@ export class StrContains extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr, private substring: Expr) { super('str_contains', [expr, substring]); } + filterable = true as const; } @@ -2717,6 +2989,7 @@ export class StartsWith extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr, private prefix: Expr) { super('starts_with', [expr, prefix]); } + filterable = true as const; } @@ -2727,6 +3000,7 @@ export class EndsWith extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr, private suffix: Expr) { super('ends_with', [expr, suffix]); } + filterable = true as const; } @@ -2780,6 +3054,7 @@ export class MapGet extends FirestoreFunction { */ export class Count extends FirestoreFunction implements Accumulator { accumulator = true as const; + constructor(private value: Expr | undefined, private distinct: boolean) { super('count', value === undefined ? [] : [value]); } @@ -2790,6 +3065,7 @@ export class Count extends FirestoreFunction implements Accumulator { */ export class Sum extends FirestoreFunction implements Accumulator { accumulator = true as const; + constructor(private value: Expr, private distinct: boolean) { super('sum', [value]); } @@ -2800,6 +3076,7 @@ export class Sum extends FirestoreFunction implements Accumulator { */ export class Avg extends FirestoreFunction implements Accumulator { accumulator = true as const; + constructor(private value: Expr, private distinct: boolean) { super('avg', [value]); } @@ -2810,6 +3087,7 @@ export class Avg extends FirestoreFunction implements Accumulator { */ export class Minimum extends FirestoreFunction implements Accumulator { accumulator = true as const; + constructor(private value: Expr, private distinct: boolean) { super('minimum', [value]); } @@ -2820,6 +3098,7 @@ export class Minimum extends FirestoreFunction implements Accumulator { */ export class Maximum extends FirestoreFunction implements Accumulator { accumulator = true as const; + constructor(private value: Expr, private distinct: boolean) { super('maximum', [value]); } @@ -2948,6 +3227,7 @@ export class Countif extends FirestoreFunction implements Accumulator { constructor(private booleanExpr: Expr) { super('countif', [booleanExpr]); } + accumulator = true as const; } @@ -2958,13 +3238,13 @@ export class Countif extends FirestoreFunction implements Accumulator { * * ```typescript * // Count the number of documents where 'is_active' field equals true - * countif(Field.of("is_active")).as("numActiveDocuments"); + * countif(Field.of("is_active").eq(true)).as("numActiveDocuments"); * ``` * * @param booleanExpr - The boolean expression to evaluate on each input. * @returns A new `Accumulator` representing the 'countif' aggregation. */ -export function countif(booleanExpr: Expr): Countif { +export function countif(booleanExpr: FilterCondition): Countif { return new Countif(booleanExpr); } @@ -2977,6 +3257,13 @@ export class Rand extends FirestoreFunction { } } +/** + * @beta + * Creates an expression that return a pseudo-random value of type double in the + * range of [0, 1), inclusive of 0 and exclusive of 1. + * + * @returns A new `Expr` representing the 'rand' function. + */ export function rand(): Rand { return new Rand(); } @@ -2990,24 +3277,74 @@ export class BitAnd extends FirestoreFunction { } } +/** + * @beta + * + * Creates an expression that applies a bitwise AND operation between a field and a constant. + * + * ```typescript + * // Calculate the bitwise AND of 'field1' and 0xFF. + * bitAnd("field1", 0xFF); + * ``` + * + * @param field The left operand field name. + * @param otherBits A constant representing bits. + * @return A new {@code Expr} representing the bitwise AND operation. + */ export function bitAnd(field: string, otherBits: number | Bytes): BitAnd; +/** + * @beta + * + * Creates an expression that applies a bitwise AND operation between a field and an expression. + * + * ```typescript + * // Calculate the bitwise AND of 'field1' and 'field2'. + * bitAnd("field1", Field.of("field2")); + * ``` + * + * @param field The left operand field name. + * @param bitsExpression An expression that returns bits when evaluated. + * @return A new {@code Expr} representing the bitwise AND operation. + */ export function bitAnd(field: string, bitsExpression: Expr): BitAnd; +/** + * @beta + * + * Creates an expression that applies a bitwise AND operation between an expression and a constant. + * + * ```typescript + * // Calculate the bitwise AND of 'field1' and 0xFF. + * bitAnd(Field.of("field1"), 0xFF); + * ``` + * + * @param bitsExpression An expression returning bits. + * @param otherBits A constant representing bits. + * @return A new {@code Expr} representing the bitwise AND operation. + */ export function bitAnd(bitsExpression: Expr, otherBits: number | Bytes): BitAnd; +/** + * @beta + * + * Creates an expression that applies a bitwise AND operation between two expressions. + * + * ```typescript + * // Calculate the bitwise AND of 'field1' and 'field2'. + * bitAnd(Field.of("field1"), Field.of("field2")); + * ``` + * + * @param bitsExpression An expression that returns bits when evaluated. + * @param otherBitsExpression An expression that returns bits when evaluated. + * @return A new {@code Expr} representing the bitwise AND operation. + */ export function bitAnd(bitsExpression: Expr, otherBitsExpression: Expr): BitAnd; export function bitAnd( fieldOrExpression: string | Expr, bitsOrExpression: number | Expr | Bytes ): BitAnd { - const left = - fieldOrExpression instanceof Expr - ? fieldOrExpression - : Field.of(fieldOrExpression); - // @ts-ignore - const right = - bitsOrExpression instanceof Expr - ? bitsOrExpression - : Constant.of(bitsOrExpression); - return new BitAnd(left, right); + return new BitAnd( + fieldOfOrExpr(fieldOrExpression), + valueToDefaultExpr(bitsOrExpression) + ); } /** @@ -3019,24 +3356,74 @@ export class BitOr extends FirestoreFunction { } } +/** + * @beta + * + * Creates an expression that applies a bitwise OR operation between a field and a constant. + * + * ```typescript + * // Calculate the bitwise OR of 'field1' and 0xFF. + * bitOr("field1", 0xFF); + * ``` + * + * @param field The left operand field name. + * @param otherBits A constant representing bits. + * @return A new {@code Expr} representing the bitwise OR operation. + */ export function bitOr(field: string, otherBits: number | Bytes): BitOr; +/** + * @beta + * + * Creates an expression that applies a bitwise OR operation between a field and an expression. + * + * ```typescript + * // Calculate the bitwise OR of 'field1' and 'field2'. + * bitOr("field1", Field.of("field2")); + * ``` + * + * @param field The left operand field name. + * @param bitsExpression An expression that returns bits when evaluated. + * @return A new {@code Expr} representing the bitwise OR operation. + */ export function bitOr(field: string, bitsExpression: Expr): BitOr; +/** + * @beta + * + * Creates an expression that applies a bitwise OR operation between an expression and a constant. + * + * ```typescript + * // Calculate the bitwise OR of 'field1' and 0xFF. + * bitOr(Field.of("field1"), 0xFF); + * ``` + * + * @param bitsExpression An expression returning bits. + * @param otherBits A constant representing bits. + * @return A new {@code Expr} representing the bitwise OR operation. + */ export function bitOr(bitsExpression: Expr, otherBits: number | Bytes): BitOr; +/** + * @beta + * + * Creates an expression that applies a bitwise OR operation between two expressions. + * + * ```typescript + * // Calculate the bitwise OR of 'field1' and 'field2'. + * bitOr(Field.of("field1"), Field.of("field2")); + * ``` + * + * @param bitsExpression An expression that returns bits when evaluated. + * @param otherBitsExpression An expression that returns bits when evaluated. + * @return A new {@code Expr} representing the bitwise OR operation. + */ export function bitOr(bitsExpression: Expr, otherBitsExpression: Expr): BitOr; export function bitOr( fieldOrExpression: string | Expr, bitsOrExpression: number | Expr | Bytes ): BitOr { - const left = - fieldOrExpression instanceof Expr - ? fieldOrExpression - : Field.of(fieldOrExpression); - // @ts-ignore - const right = - bitsOrExpression instanceof Expr - ? bitsOrExpression - : Constant.of(bitsOrExpression); - return new BitOr(left, right); + return new BitOr( + fieldOfOrExpr(fieldOrExpression), + valueToDefaultExpr(bitsOrExpression) + ); } /** @@ -3048,24 +3435,74 @@ export class BitXor extends FirestoreFunction { } } +/** + * @beta + * + * Creates an expression that applies a bitwise XOR operation between a field and a constant. + * + * ```typescript + * // Calculate the bitwise XOR of 'field1' and 0xFF. + * bitXor("field1", 0xFF); + * ``` + * + * @param field The left operand field name. + * @param otherBits A constant representing bits. + * @return A new {@code Expr} representing the bitwise XOR operation. + */ export function bitXor(field: string, otherBits: number | Bytes): BitXor; +/** + * @beta + * + * Creates an expression that applies a bitwise XOR operation between a field and an expression. + * + * ```typescript + * // Calculate the bitwise XOR of 'field1' and 'field2'. + * bitXor("field1", Field.of("field2")); + * ``` + * + * @param field The left operand field name. + * @param bitsExpression An expression that returns bits when evaluated. + * @return A new {@code Expr} representing the bitwise XOR operation. + */ export function bitXor(field: string, bitsExpression: Expr): BitXor; +/** + * @beta + * + * Creates an expression that applies a bitwise XOR operation between an expression and a constant. + * + * ```typescript + * // Calculate the bitwise XOR of 'field1' and 0xFF. + * bitXor(Field.of("field1"), 0xFF); + * ``` + * + * @param bitsExpression An expression returning bits. + * @param otherBits A constant representing bits. + * @return A new {@code Expr} representing the bitwise XOR operation. + */ export function bitXor(bitsExpression: Expr, otherBits: number | Bytes): BitXor; +/** + * @beta + * + * Creates an expression that applies a bitwise XOR operation between two expressions. + * + * ```typescript + * // Calculate the bitwise XOR of 'field1' and 'field2'. + * bitXor(Field.of("field1"), Field.of("field2")); + * ``` + * + * @param bitsExpression An expression that returns bits when evaluated. + * @param otherBitsExpression An expression that returns bits when evaluated. + * @return A new {@code Expr} representing the bitwise XOR operation. + */ export function bitXor(bitsExpression: Expr, otherBitsExpression: Expr): BitXor; export function bitXor( fieldOrExpression: string | Expr, bitsOrExpression: number | Expr | Bytes ): BitXor { - const left = - fieldOrExpression instanceof Expr - ? fieldOrExpression - : Field.of(fieldOrExpression); - // @ts-ignore - const right = - bitsOrExpression instanceof Expr - ? bitsOrExpression - : Constant.of(bitsOrExpression); - return new BitXor(left, right); + return new BitXor( + fieldOfOrExpr(fieldOrExpression), + valueToDefaultExpr(bitsOrExpression) + ); } /** @@ -3076,11 +3513,37 @@ export class BitNot extends FirestoreFunction { super('bit_not', [value]); } } + +/** + * @beta + * + * Creates an expression that applies a bitwise NOT operation to a field. + * + * ```typescript + * // Calculate the bitwise NOT of 'field1'. + * bitNot("field1"); + * ``` + * + * @param field The operand field name. + * @return A new {@code Expr} representing the bitwise NOT operation. + */ export function bitNot(field: string): BitNot; -export function bitNot(bitsValue: number | Bytes): BitNot; +/** + * @beta + * + * Creates an expression that applies a bitwise NOT operation to an expression. + * + * ```typescript + * // Calculate the bitwise NOT of 'field1'. + * bitNot(Field.of("field1")); + * ``` + * + * @param bitsValueExpression An expression that returns bits when evaluated. + * @return A new {@code Expr} representing the bitwise NOT operation. + */ export function bitNot(bitsValueExpression: Expr): BitNot; -export function bitNot(bits: string | number | Bytes | Expr): BitNot { - return new BitNot(isString(bits) ? Field.of(bits) : valueToDefaultExpr(bits)); +export function bitNot(bits: string | Expr): BitNot { + return new BitNot(fieldOfOrExpr(bits)); } /** @@ -3092,21 +3555,72 @@ export class BitLeftShift extends FirestoreFunction { } } -export function bitLeftShift(field: string, y: number): BitRightShift; -export function bitLeftShift(field: string, numberExpr: Expr): BitRightShift; -export function bitLeftShift(xValue: number | Bytes, y: number): BitRightShift; -export function bitLeftShift( - xValue: number | Bytes, - numberExpr: Expr -): BitRightShift; -export function bitLeftShift(xValue: Expr, y: number): BitRightShift; -export function bitLeftShift(xValue: Expr, numberExpr: Expr): BitRightShift; +/** + * @beta + * + * Creates an expression that applies a bitwise left shift operation between a field and a constant. + * + * ```typescript + * // Calculate the bitwise left shift of 'field1' by 2 bits. + * bitLeftShift("field1", 2); + * ``` + * + * @param field The left operand field name. + * @param y The right operand constant representing the number of bits to shift. + * @return A new {@code Expr} representing the bitwise left shift operation. + */ +export function bitLeftShift(field: string, y: number): BitLeftShift; +/** + * @beta + * + * Creates an expression that applies a bitwise left shift operation between a field and an expression. + * + * ```typescript + * // Calculate the bitwise left shift of 'field1' by 'field2' bits. + * bitLeftShift("field1", Field.of("field2")); + * ``` + * + * @param field The left operand field name. + * @param numberExpr The right operand expression representing the number of bits to shift. + * @return A new {@code Expr} representing the bitwise left shift operation. + */ +export function bitLeftShift(field: string, numberExpr: Expr): BitLeftShift; +/** + * @beta + * + * Creates an expression that applies a bitwise left shift operation between an expression and a constant. + * + * ```typescript + * // Calculate the bitwise left shift of 'field1' by 2 bits. + * bitLeftShift(Field.of("field1"), 2); + * ``` + * + * @param xValue An expression returning bits. + * @param y The right operand constant representing the number of bits to shift. + * @return A new {@code Expr} representing the bitwise left shift operation. + */ +export function bitLeftShift(xValue: Expr, y: number): BitLeftShift; +/** + * @beta + * + * Creates an expression that applies a bitwise left shift operation between two expressions. + * + * ```typescript + * // Calculate the bitwise left shift of 'field1' by 'field2' bits. + * bitLeftShift(Field.of("field1"), Field.of("field2")); + * ``` + * + * @param xValue An expression returning bits. + * @param right The right operand expression representing the number of bits to shift. + * @return A new {@code Expr} representing the bitwise left shift operation. + */ +export function bitLeftShift(xValue: Expr, numberExpr: Expr): BitLeftShift; export function bitLeftShift( - xValue: string | number | Bytes, + xValue: string | Expr, numberExpr: number | Expr -): BitRightShift { +): BitLeftShift { return new BitLeftShift( - isString(xValue) ? Field.of(xValue) : valueToDefaultExpr(xValue), + fieldOfOrExpr(xValue), valueToDefaultExpr(numberExpr) ); } @@ -3120,21 +3634,72 @@ export class BitRightShift extends FirestoreFunction { } } +/** + * @beta + * + * Creates an expression that applies a bitwise right shift operation between a field and a constant. + * + * ```typescript + * // Calculate the bitwise right shift of 'field1' by 2 bits. + * bitRightShift("field1", 2); + * ``` + * + * @param left The left operand field name. + * @param right The right operand constant representing the number of bits to shift. + * @return A new {@code Expr} representing the bitwise right shift operation. + */ export function bitRightShift(field: string, y: number): BitRightShift; +/** + * @beta + * + * Creates an expression that applies a bitwise right shift operation between a field and an expression. + * + * ```typescript + * // Calculate the bitwise right shift of 'field1' by 'field2' bits. + * bitRightShift("field1", Field.of("field2")); + * ``` + * + * @param field The left operand field name. + * @param numberExpr The right operand expression representing the number of bits to shift. + * @return A new {@code Expr} representing the bitwise right shift operation. + */ export function bitRightShift(field: string, numberExpr: Expr): BitRightShift; -export function bitRightShift(xValue: number | Bytes, y: number): BitRightShift; -export function bitRightShift( - xValue: number | Bytes, - numberExpr: Expr -): BitRightShift; +/** + * @beta + * + * Creates an expression that applies a bitwise right shift operation between an expression and a constant. + * + * ```typescript + * // Calculate the bitwise right shift of 'field1' by 2 bits. + * bitRightShift(Field.of("field1"), 2); + * ``` + * + * @param xValue An expression returning bits. + * @param y The right operand constant representing the number of bits to shift. + * @return A new {@code Expr} representing the bitwise right shift operation. + */ export function bitRightShift(xValue: Expr, y: number): BitRightShift; +/** + * @beta + * + * Creates an expression that applies a bitwise right shift operation between two expressions. + * + * ```typescript + * // Calculate the bitwise right shift of 'field1' by 'field2' bits. + * bitRightShift(Field.of("field1"), Field.of("field2")); + * ``` + * + * @param xValue An expression returning bits. + * @param right The right operand expression representing the number of bits to shift. + * @return A new {@code Expr} representing the bitwise right shift operation. + */ export function bitRightShift(xValue: Expr, numberExpr: Expr): BitRightShift; export function bitRightShift( - xValue: string | number | Bytes | Expr, + xValue: string | Expr, numberExpr: number | Expr ): BitRightShift { return new BitRightShift( - isString(xValue) ? Field.of(xValue) : valueToDefaultExpr(xValue), + fieldOfOrExpr(xValue), valueToDefaultExpr(numberExpr) ); } @@ -3150,61 +3715,71 @@ export class ArrayOffset extends FirestoreFunction { /** * @beta - * - * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * 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. * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN(Field.of("value").divide(0)); + * // Return the value in the tags field array at index 1. + * arrayOffset('tags', 1); * ``` * - * @param value The expression to check. - * @return A new {@code Expr} representing the 'isNaN' check. + * @param arrayField The name of the array field. + * @param offset The index of the element to return. + * @return A new Expr representing the 'arrayOffset' operation. */ export function arrayOffset(arrayField: string, offset: number): ArrayOffset; /** * @beta - * - * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * 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. * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN(Field.of("value").divide(0)); + * // Return the value in the tags field array at index specified by field + * // 'favoriteTag'. + * arrayOffset('tags', Field.of('favoriteTag')); * ``` * - * @param value The expression to check. - * @return A new {@code Expr} representing the 'isNaN' check. + * @param arrayField The name of the array field. + * @param offsetExpr An Expr evaluating to the index of the element to return. + * @return A new Expr representing the 'arrayOffset' operation. */ export function arrayOffset(arrayField: string, offsetExpr: Expr): ArrayOffset; /** * @beta - * - * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * 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. * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN(Field.of("value").divide(0)); + * // Return the value in the tags field array at index 1. + * arrayOffset(Field.of('tags'), 1); * ``` * - * @param value The expression to check. - * @return A new {@code Expr} representing the 'isNaN' check. + * @param arrayExpression An Expr evaluating to an array. + * @param offset The index of the element to return. + * @return A new Expr representing the 'arrayOffset' operation. */ export function arrayOffset(arrayExpression: Expr, offset: number): ArrayOffset; /** * @beta - * - * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * 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. * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN(Field.of("value").divide(0)); + * // Return the value in the tags field array at index specified by field + * // 'favoriteTag'. + * arrayOffset(Field.of('tags'), Field.of('favoriteTag')); * ``` * - * @param value The expression to check. - * @return A new {@code Expr} representing the 'isNaN' check. + * @param arrayExpression An Expr evaluating to an array. + * @param offsetExpr An Expr evaluating to the index of the element to return. + * @return A new Expr representing the 'arrayOffset' operation. */ export function arrayOffset( arrayExpression: Expr, @@ -3226,6 +3801,12 @@ export class CurrentContext extends FirestoreFunction { } } +/** + * @beta + * Creates an Expr that returns a map of all values in the current expression context. + * + * @return A new {@code Expr} representing the 'current_context' function. + */ export function currentContext(): CurrentContext { return new CurrentContext(); } @@ -3237,21 +3818,22 @@ export class IsError extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr) { super('is_error', [expr]); } + filterable = true as const; } /** * @beta * - * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * Creates an expression that checks if a given expression produces an error. * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN(Field.of("value").divide(0)); + * // Check if the result of a calculation is an error + * isError(Field.of("title").arrayContains(1)); * ``` * * @param value The expression to check. - * @return A new {@code Expr} representing the 'isNaN' check. + * @return A new {@code Expr} representing the 'isError' check. */ export function isError(value: Expr): IsError { return new IsError(value); @@ -3269,30 +3851,38 @@ export class IfError extends FirestoreFunction { /** * @beta * - * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * Creates an expression that returns the `catch` argument if there is an + * error, else return the result of the `try` argument evaluation. * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN(Field.of("value").divide(0)); + * // Returns the first item in the title field arrays, or returns + * // the entire title field if the array is empty or the field is another type. + * ifError(Field.of("title").arrayOffset(0), Field.of("title")); * ``` * - * @param value The expression to check. - * @return A new {@code Expr} representing the 'isNaN' check. + * @param tryExpr The try expression. + * @param catchExpr The catch expression that will be evaluated and + * returned if the tryExpr produces an error. + * @return A new {@code Expr} representing the 'ifError' operation. */ export function ifError(tryExpr: Expr, catchExpr: Expr): IfError; /** * @beta * - * Creates an expression that checks if a field's value evaluates to 'NaN' (Not a Number). + * Creates an expression that returns the `catch` argument if there is an + * error, else return the result of the `try` argument evaluation. * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN("value"); + * // Returns the first item in the title field arrays, or returns + * // "Default Title" + * ifError(Field.of("title").arrayOffset(0), "Default Title"); * ``` * - * @param value The name of the field to check. - * @return A new {@code Expr} representing the 'isNaN' check. + * @param tryExpr The try expression. + * @param catchValue The value that will be returned if the tryExpr produces an + * error. + * @return A new {@code Expr} representing the 'ifError' operation. */ export function ifError(tryExpr: Expr, catchValue: any): IfError; export function ifError(tryExpr: Expr, catchValue: any): IfError { @@ -3306,38 +3896,41 @@ export class IsAbsent extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr) { super('is_absent', [expr]); } + filterable = true as const; } /** * @beta * - * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * Creates an expression that returns `true` if a value is absent. Otherwise, + * returns `false` even if the value is `null`. * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN(Field.of("value").divide(0)); + * // Check if the field `value` is absent. + * isAbsent(Field.of("value")); * ``` * * @param value The expression to check. - * @return A new {@code Expr} representing the 'isNaN' check. + * @return A new {@code Expr} representing the 'isAbsent' check. */ export function isAbsent(value: Expr): IsAbsent; /** * @beta * - * Creates an expression that checks if a field's value evaluates to 'NaN' (Not a Number). + * Creates an expression that returns `true` if a field is absent. Otherwise, + * returns `false` even if the field value is `null`. * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN("value"); + * // Check if the field `value` is absent. + * isAbsent("value"); * ``` * - * @param value The name of the field to check. - * @return A new {@code Expr} representing the 'isNaN' check. + * @param field The field to check. + * @return A new {@code Expr} representing the 'isAbsent' check. */ -export function isAbsent(value: string): IsAbsent; +export function isAbsent(field: string): IsAbsent; export function isAbsent(value: Expr | string): IsAbsent { return new IsAbsent(fieldOfOrExpr(value)); } @@ -3349,6 +3942,7 @@ export class IsNull extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr) { super('is_null', [expr]); } + filterable = true as const; } @@ -3392,17 +3986,18 @@ export class IsNotNull extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr) { super('is_not_null', [expr]); } + filterable = true as const; } /** * @beta * - * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * Creates an expression that checks if tbe result of an expression is not null. * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN(Field.of("value").divide(0)); + * // Check if the value of the 'name' field is not null + * isNotNull(Field.of("name")); * ``` * * @param value The expression to check. @@ -3413,11 +4008,11 @@ export function isNotNull(value: Expr): IsNotNull; /** * @beta * - * Creates an expression that checks if a field's value evaluates to 'NaN' (Not a Number). + * Creates an expression that checks if tbe value of a field is not null. * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN("value"); + * // Check if the value of the 'name' field is not null + * isNotNull("name"); * ``` * * @param value The name of the field to check. @@ -3435,36 +4030,37 @@ export class IsNotNan extends FirestoreFunction implements FilterCondition { constructor(private expr: Expr) { super('is_not_nan', [expr]); } + filterable = true as const; } /** * @beta * - * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * Creates an expression that checks if the results of this expression is NOT 'NaN' (Not a Number). * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN(Field.of("value").divide(0)); + * // Check if the result of a calculation is NOT NaN + * isNotNaN(Field.of("value").divide(0)); * ``` * * @param value The expression to check. - * @return A new {@code Expr} representing the 'isNaN' check. + * @return A new {@code Expr} representing the 'isNotNaN' check. */ export function isNotNan(value: Expr): IsNotNan; /** * @beta * - * Creates an expression that checks if a field's value evaluates to 'NaN' (Not a Number). + * Creates an expression that checks if the results of this expression is NOT 'NaN' (Not a Number). * * ```typescript - * // Check if the result of a calculation is NaN - * isNaN("value"); + * // Check if the value of a field is NOT NaN + * isNotNaN("value"); * ``` * * @param value The name of the field to check. - * @return A new {@code Expr} representing the 'isNaN' check. + * @return A new {@code Expr} representing the 'isNotNaN' check. */ export function isNotNan(value: string): IsNotNan; export function isNotNan(value: Expr | string): IsNotNan { @@ -3479,14 +4075,62 @@ export class MapRemove extends FirestoreFunction { super('map_remove', [map, nameExpr]); } } - -export function mapRemove(mapField: string, name: string): MapRemove; - -export function mapRemove(mapExpr: Expr, name: string): MapRemove; - -export function mapRemove(mapField: string, stringExpr: Expr): MapRemove; - -export function mapRemove(mapExpr: Expr, stringExpr: Expr): MapRemove; +/** + * @beta + * + * Creates an expression that removes a key from the map at the specified field name. + * + * ``` + * // Removes the key 'city' field from the map in the address field of the input document. + * mapRemove('address', 'city'); + * ``` + * + * @param mapField The name of a field containing a map value. + * @param key The name of the key to remove from the input map. + */ +export function mapRemove(mapField: string, key: string): MapRemove; +/** + * @beta + * + * Creates an expression that removes a key from the map produced by evaluating an expression. + * + * ``` + * // Removes the key 'baz' from the input map. + * mapRemove(map({foo: 'bar', baz: true}), 'baz'); + * ``` + * + * @param mapExpr An expression return a map value. + * @param key The name of the key to remove from the input map. + */ +export function mapRemove(mapExpr: Expr, key: string): MapRemove; +/** + * @beta + * + * Creates an expression that removes a key from the map at the specified field name. + * + * ``` + * // Removes the key 'city' field from the map in the address field of the input document. + * mapRemove('address', Constant.of('city')); + * ``` + * + * @param mapField The name of a field containing a map value. + * @param keyExpr An expression that produces the name of the key to remove from the input map. + */ +export function mapRemove(mapField: string, keyExpr: Expr): MapRemove; +/** + * @beta + * + * Creates an expression that removes a key from the map produced by evaluating an expression. + * + * ``` + * // Removes the key 'baz' from the input map. + * mapRemove(map({foo: 'bar', baz: true}), Constant.of('baz')); + * ``` + * + * @param mapExpr An expression return a map value. + * @param keyExpr An expression that produces the name of the key to remove from the input map. + */ +export function mapRemove(mapExpr: Expr, keyExpr: Expr): MapRemove; export function mapRemove( mapExpr: Expr | string, @@ -3504,12 +4148,46 @@ export class MapMerge extends FirestoreFunction { } } +/** + * @beta + * + * Creates an expression that merges multiple map values. + * + * ``` + * // Merges the map in the settings field with, a map literal, and a map in + * // that is conditionally returned by another expression + * mapMerge('settings', { enabled: true }, cond(Field.of('isAdmin'), { admin: true}, {}) + * ``` + * + * @param mapField Name of a field containing a map value that will be merged. + * @param secondMap A required second map to merge. Represented as a literal or + * an expression that returns a map. + * @param otherMaps Optional additional maps to merge. Each map is represented + * as a literal or an expression that returns a map. + */ export function mapMerge( mapField: string, secondMap: Record | Expr, ...otherMaps: Array | Expr> ): MapMerge; +/** + * @beta + * + * Creates an expression that merges multiple map values. + * + * ``` + * // Merges the map in the settings field with, a map literal, and a map in + * // that is conditionally returned by another expression + * mapMerge(Field.of('settings'), { enabled: true }, cond(Field.of('isAdmin'), { admin: true}, {}) + * ``` + * + * @param firstMap An expression or literal map map value that will be merged. + * @param secondMap A required second map to merge. Represented as a literal or + * an expression that returns a map. + * @param otherMaps Optional additional maps to merge. Each map is represented + * as a literal or an expression that returns a map. + */ export function mapMerge( firstMap: Record | Expr, secondMap: Record | Expr, @@ -3579,10 +4257,34 @@ export class DocumentId extends FirestoreFunction { } } +/** + * @beta + * + * Creates an expression that returns the document ID from a path. + * + * ```typescript + * // Get the document ID from a path. + * documentId(myDocumentReference); + * ``` + * + * @return A new {@code Expr} representing the documentId operation. + */ export function documentIdFunction( documentPath: string | DocumentReference ): DocumentId; +/** + * @beta + * + * Creates an expression that returns the document ID from a path. + * + * ```typescript + * // Get the document ID from a path. + * documentId(Field.of("__path__")); + * ``` + * + * @return A new {@code Expr} representing the documentId operation. + */ export function documentIdFunction(documentPathExpr: Expr): DocumentId; export function documentIdFunction( @@ -3621,17 +4323,49 @@ export class Substr extends FirestoreFunction { } } +/** + * @beta + * + * Creates an expression that returns a substring of a string or byte array. + * + * @param field The name of a field containing a string or byte array to compute the substring from. + * @param position Index of the first character of the substring. + * @param length Length of the substring. + */ export function substr(field: string, position: number, length: number): Substr; -export function substr( - stringExpr: Expr, - position: number, - length: number -): Substr; +/** + * @beta + * + * Creates an expression that returns a substring of a string or byte array. + * + * @param input An expression returning a string or byte array to compute the substring from. + * @param position Index of the first character of the substring. + * @param length Length of the substring. + */ +export function substr(input: Expr, position: number, length: number): Substr; +/** + * @beta + * + * Creates an expression that returns a substring of a string or byte array. + * + * @param field The name of a field containing a string or byte array to compute the substring from. + * @param position An expression that returns the index of the first character of the substring. + * @param length An expression that returns the length of the substring. + */ export function substr(field: string, position: Expr, length: Expr): Substr; -export function substr(stringExpr: Expr, position: Expr, length: Expr): Substr; +/** + * @beta + * + * Creates an expression that returns a substring of a string or byte array. + * + * @param input An expression returning a string or byte array to compute the substring from. + * @param position An expression that returns the index of the first character of the substring. + * @param length An expression that returns the length of the substring. + */ +export function substr(input: Expr, position: Expr, length: Expr): Substr; export function substr( field: Expr | string, @@ -3663,12 +4397,12 @@ export class ManhattanDistance extends FirestoreFunction { * manhattanDistance("location", [37.7749, -122.4194]); * ``` * - * @param expr The name of the field containing the first vector. + * @param field The name of the field containing the first vector. * @param other The other vector (as an array of doubles) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ export function manhattanDistance( - expr: string, + field: string, other: number[] ): ManhattanDistance; @@ -3762,10 +4496,10 @@ export function manhattanDistance( */ export function manhattanDistance(expr: Expr, other: Expr): ManhattanDistance; export function manhattanDistance( - expr: Expr | string, + fieldOrExpr: Expr | string, other: Expr | number[] | VectorValue ): ManhattanDistance { - const expr1 = fieldOfOrExpr(expr); + const expr1 = fieldOfOrExpr(fieldOrExpr); const expr2 = other instanceof Expr ? other : Constant.vector(other); return new ManhattanDistance(expr1, expr2); } diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 4bdbbf8146a..134a2de7680 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -68,7 +68,6 @@ import { cond, eqAny, logicalMaximum, - logicalMinimum, notEqAny, query, where, @@ -361,6 +360,15 @@ apiDescribe.only('Pipelines', persistence => { .collection(randomCol.path) .sort(Field.of('rating').descending()) .limit(1) + .select( + 'title', + 'author', + 'genre', + 'rating', + 'published', + 'tags', + 'awards' + ) .addFields( array([ 1, @@ -907,6 +915,7 @@ apiDescribe.only('Pipelines', persistence => { ); }); }); + it('logical max works', async () => { const results = await randomCol .pipeline() @@ -1191,7 +1200,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .where(not(Field.of('rating').isNaN())) .select( - Field.of('rating').eq(null).as('ratingIsNull'), + Field.of('rating').isNull().as('ratingIsNull'), not(Field.of('rating').isNaN()).as('ratingIsNotNaN') ) .limit(1) @@ -1217,7 +1226,7 @@ apiDescribe.only('Pipelines', persistence => { title: "The Hitchhiker's Guide to the Galaxy", others: { unknown: { year: 1980 } } }, - { hugoAward: true, hugoAward2: true, title: 'Dune', others: null } + { hugoAward: true, title: 'Dune', others: null } ); }); @@ -1284,14 +1293,21 @@ apiDescribe.only('Pipelines', persistence => { ); }); - it('supports countIf', async () => { - const results = await randomCol + it('supports countif', async () => { + let results = await randomCol .pipeline() .aggregate(countif(Field.of('rating').gt(4.3)).as('count')) .execute(); - expectResults(results, { + const expectedResults = { count: 3 - }); + }; + expectResults(results, expectedResults); + + results = await randomCol + .pipeline() + .aggregate(Field.of('rating').gt(4.3).countif().as('count')) + .execute(); + expectResults(results, expectedResults); }); describe('genericFunction', () => { @@ -1393,290 +1409,430 @@ apiDescribe.only('Pipelines', persistence => { expectResults(results, { result: 4 }); - }); + it('supports Bit_and', async () => { + const results = await randomCol + .pipeline() + .limit(1) + .select(Constant.of(5).bitAnd(12).as('result')) + .execute(); + expectResults(results, { + result: 4 + }); + }); - it('supports Bit_or', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select(bitOr(Constant.of(5), 12).as('result')) - .execute(); - expectResults(results, { - result: 13 + it('supports Bit_or', async () => { + let results = await randomCol + .pipeline() + .limit(1) + .select(bitOr(Constant.of(5), 12).as('result')) + .execute(); + expectResults(results, { + result: 13 + }); + results = await randomCol + .pipeline() + .limit(1) + .select(Constant.of(5).bitOr(12).as('result')) + .execute(); + expectResults(results, { + result: 13 + }); }); - }); - it('supports Bit_xor', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select(bitXor(Constant.of(5), 12).as('result')) - .execute(); - expectResults(results, { - result: 9 + it('supports Bit_xor', async () => { + let results = await randomCol + .pipeline() + .limit(1) + .select(bitXor(Constant.of(5), 12).as('result')) + .execute(); + expectResults(results, { + result: 9 + }); + results = await randomCol + .pipeline() + .limit(1) + .select(Constant.of(5).bitXor(12).as('result')) + .execute(); + expectResults(results, { + result: 9 + }); }); - }); - it('supports Bit_not', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select( - bitNot(Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd)))).as( - 'result' + it('supports Bit_not', async () => { + let results = await randomCol + .pipeline() + .limit(1) + .select( + bitNot( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd))) + ).as('result') ) - ) - .execute(); - expectResults(results, { - result: Bytes.fromUint8Array(Uint8Array.of(0x02)) + .execute(); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x02)) + }); + results = await randomCol + .pipeline() + .limit(1) + .select( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd))) + .bitNot() + .as('result') + ) + .execute(); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x02)) + }); }); - }); - it('supports Bit_left_shift', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select( - bitLeftShift( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), - 2 - ).as('result') - ) - .execute(); - expectResults(results, { - result: Bytes.fromUint8Array(Uint8Array.of(0x04)) + it('supports Bit_left_shift', async () => { + let results = await randomCol + .pipeline() + .limit(1) + .select( + bitLeftShift( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + .execute(); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x04)) + }); + results = await randomCol + .pipeline() + .limit(1) + .select( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))) + .bitLeftShift(2) + .as('result') + ) + .execute(); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x04)) + }); }); - }); - it('supports Bit_right_shift', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select( - bitRightShift( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), - 2 - ).as('result') - ) - .execute(); - expectResults(results, { - result: Bytes.fromUint8Array(Uint8Array.of(0x01)) + it('supports Bit_right_shift', async () => { + let results = await randomCol + .pipeline() + .limit(1) + .select( + bitRightShift( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + .execute(); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x01)) + }); + results = await randomCol + .pipeline() + .limit(1) + .select( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))) + .bitRightShift(2) + .as('result') + ) + .execute(); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x01)) + }); }); - }); - it('supports Document_id', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(documentIdFunction(Field.of('__path__')).as('docId')) - .execute(); - expectResults(results, { - docId: 'book4' + it('supports Document_id', async () => { + let results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(documentIdFunction(Field.of('__path__')).as('docId')) + .execute(); + expectResults(results, { + docId: 'book4' + }); + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('__path__').documentId().as('docId')) + .execute(); + expectResults(results, { + docId: 'book4' + }); + }); + + it('supports Substr', async () => { + let results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(substr('title', 9, 2).as('of')) + .execute(); + expectResults(results, { + of: 'of' + }); + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('title').substr(9, 2).as('of')) + .execute(); + expectResults(results, { + of: 'of' + }); + }); + + it('arrayConcat works', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('tags') + .arrayConcat(['newTag1', 'newTag2']) + .as('modifiedTags') + ) + .limit(1) + .execute(); + expectResults(results, { + modifiedTags: [ + 'comedy', + 'space', + 'adventure', + 'newTag1', + 'newTag2' + ] + }); + }); + + it('testToLowercase', async () => { + const results = await randomCol + .pipeline() + .select(Field.of('title').toLower().as('lowercaseTitle')) + .limit(1) + .execute(); + expectResults(results, { + lowercaseTitle: "the hitchhiker's guide to the galaxy" + }); + }); + + it('testToUppercase', async () => { + const results = await randomCol + .pipeline() + .select(Field.of('author').toUpper().as('uppercaseAuthor')) + .limit(1) + .execute(); + expectResults(results, { uppercaseAuthor: 'DOUGLAS ADAMS' }); + }); + + it('testTrim', async () => { + const results = await randomCol + .pipeline() + .addFields( + Constant.of(" The Hitchhiker's Guide to the Galaxy ").as( + 'spacedTitle' + ) + ) + .select( + Field.of('spacedTitle').trim().as('trimmedTitle'), + Field.of('spacedTitle') + ) + .limit(1) + .execute(); + expectResults(results, { + spacedTitle: " The Hitchhiker's Guide to the Galaxy ", + trimmedTitle: "The Hitchhiker's Guide to the Galaxy" + }); }); }); - it('supports Substr', async () => { + it('supports Rand', async () => { const results = await randomCol .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(substr('title', 9, 2).as('of')) + .limit(10) + .select(rand().as('result')) .execute(); - expectResults(results, { - of: 'of' + expect(results.length).to.equal(10); + results.forEach(d => { + expect(d.get('result')).to.be.lt(1); + expect(d.get('result')).to.be.gte(0); }); }); - it('arrayConcat works', async () => { - const results = await randomCol + it('supports array', async () => { + const result = await firestore .pipeline() - .select( - Field.of('tags') - .arrayConcat(['newTag1', 'newTag2']) - .as('modifiedTags') - ) + .collection(randomCol.path) + .sort(Field.of('rating').descending()) .limit(1) + .select(array([1, 2, 3, 4]).as('metadata')) .execute(); - expectResults(results, { - modifiedTags: ['comedy', 'space', 'adventure', 'newTag1', 'newTag2'] + expect(result.length).to.equal(1); + expectResults(result, { + metadata: [1, 2, 3, 4] }); }); - it('testToLowercase', async () => { - const results = await randomCol + it('evaluates expression in array', async () => { + const result = await firestore .pipeline() - .select(Field.of('title').toLower().as('lowercaseTitle')) + .collection(randomCol.path) + .sort(Field.of('rating').descending()) .limit(1) + .select( + array([1, 2, Field.of('genre'), multiply('rating', 10)]).as( + 'metadata' + ) + ) .execute(); - expectResults(results, { - lowercaseTitle: "the hitchhiker's guide to the galaxy" + expect(result.length).to.equal(1); + expectResults(result, { + metadata: [1, 2, 'Fantasy', 47] }); }); - it('testToUppercase', async () => { - const results = await randomCol + it('supports arrayOffset', async () => { + let results = await randomCol .pipeline() - .select(Field.of('author').toUpper().as('uppercaseAuthor')) - .limit(1) + .sort(Field.of('rating').descending()) + .limit(3) + .select(arrayOffset('tags', 0).as('firstTag')) .execute(); - expectResults(results, { uppercaseAuthor: 'DOUGLAS ADAMS' }); - }); + const expectedResults = [ + { + firstTag: 'adventure' + }, + { + firstTag: 'politics' + }, + { + firstTag: 'classic' + } + ]; + expectResults(results, ...expectedResults); - it('testTrim', async () => { - const results = await randomCol + results = await randomCol .pipeline() - .addFields( - Constant.of(" The Hitchhiker's Guide to the Galaxy ").as( - 'spacedTitle' - ) - ) - .select( - Field.of('spacedTitle').trim().as('trimmedTitle'), - Field.of('spacedTitle') - ) - .limit(1) + .sort(Field.of('rating').descending()) + .limit(3) + .select(Field.of('tags').arrayOffset(0).as('firstTag')) .execute(); - expectResults(results, { - spacedTitle: " The Hitchhiker's Guide to the Galaxy ", - trimmedTitle: "The Hitchhiker's Guide to the Galaxy" - }); + expectResults(results, ...expectedResults); }); }); - it('supports Rand', async () => { + // TODO: current_context tests with are failing because of b/395937453 + it.skip('supports currentContext', async () => { const results = await randomCol .pipeline() - .limit(10) - .select(rand().as('result')) - .execute(); - expect(results.length).to.equal(10); - results.forEach(d => { - expect(d.get('result')).to.be.lt(1); - expect(d.get('result')).to.be.gte(0); - }); - }); - - it('supports array', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) .sort(Field.of('rating').descending()) .limit(1) - .select(array([1, 2, 3, 4]).as('metadata')) + .select(currentContext().as('currentContext')) .execute(); - expect(result.length).to.equal(1); - expectResults(result, { - metadata: [1, 2, 3, 4] + expectResults(results, { + currentContext: 'TODO' }); }); - it('evaluates expression in array', async () => { - const result = await firestore + it('supports isError', async () => { + let results = await randomCol .pipeline() - .collection(randomCol.path) .sort(Field.of('rating').descending()) .limit(1) - .select( - array([1, 2, Field.of('genre'), multiply('rating', 10)]).as( - 'metadata' - ) - ) - .execute(); - expect(result.length).to.equal(1); - expectResults(result, { - metadata: [1, 2, 'Fantasy', 47] - }); - }); - - it('supports arrayOffset', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(3) - .select(arrayOffset('tags', 0).as('firstTag')) + .select(isError(arrayOffset('title', 0)).as('firstTag')) .execute(); - expectResults( - results, - { - firstTag: 'adventure' - }, + const expectedResults = [ { - firstTag: 'politics' - }, - { - firstTag: 'classic' + firstTag: true } - ); - }); + ]; + expectResults(results, ...expectedResults); - // TODO: current_context tests with are failing because of b/395937453 - it('supports currentContext', async () => { - const results = await randomCol + results = await randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) - .select(currentContext().as('currentContext')) + .select(arrayOffset('title', 0).isError().as('firstTag')) .execute(); - expectResults(results, { - currentContext: 'TODO' - }); + expectResults(results, ...expectedResults); }); - it('supports isError', async () => { - const results = await randomCol + it('supports ifError', async () => { + let results = await randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) - .select(isError(arrayOffset('title', 0)).as('firstTag')) + .select( + ifError(arrayOffset('title', 0), Constant.of('was error')).as( + 'firstTag' + ) + ) .execute(); - expectResults(results, { - firstTag: true - }); - }); + const expectedResults = [ + { + firstTag: 'was error' + } + ]; + expectResults(results, ...expectedResults); - it('supports ifError', async () => { - const results = await randomCol + results = await randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select( - ifError(arrayOffset('title', 0), Constant.of('was error')).as( - 'firstTag' - ) + arrayOffset('title', 0) + .ifError(Constant.of('was error')) + .as('firstTag') ) .execute(); - expectResults(results, { - firstTag: 'was error' - }); + expectResults(results, ...expectedResults); }); it('supports isAbsent', async () => { - const results = await randomCol + let results = await randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(isAbsent('foo').as('firstTag')) .execute(); - expectResults(results, { - firstTag: true - }); + const expectedResults = [ + { + firstTag: true + } + ]; + expectResults(results, ...expectedResults); + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('foo').isAbsent().as('firstTag')) + .execute(); + expectResults(results, ...expectedResults); }); it('supports isNull', async () => { - const results = await randomCol + let results = await randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(isNull('remarks').as('remarksIsNull')) .execute(); - expectResults(results, { - remarksIsNull: true - }); + const expectedResults = [ + { + remarksIsNull: true + } + ]; + expectResults(results, ...expectedResults); + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('remarks').isNull().as('remarksIsNull')) + .execute(); + expectResults(results, ...expectedResults); }); it('supports isNotNull', async () => { - const results = await randomCol + let results = await randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) @@ -1685,10 +1841,19 @@ apiDescribe.only('Pipelines', persistence => { expectResults(results, { titleIsNotNull: true }); + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('title').isNotNull().as('titleIsNotNull')) + .execute(); + expectResults(results, { + titleIsNotNull: true + }); }); it('supports isNotNan', async () => { - const results = await randomCol + let results = await randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) @@ -1697,6 +1862,15 @@ apiDescribe.only('Pipelines', persistence => { expectResults(results, { costIsNotNan: false }); + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('cost').isNotNan().as('costIsNotNan')) + .execute(); + expectResults(results, { + costIsNotNan: false + }); }); it('supports map', async () => { @@ -1744,7 +1918,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('supports mapRemove', async () => { - const results = await randomCol + let results = await randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) @@ -1753,10 +1927,19 @@ apiDescribe.only('Pipelines', persistence => { expectResults(results, { awards: { nebula: false } }); + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('awards').mapRemove('hugo').as('awards')) + .execute(); + expectResults(results, { + awards: { nebula: false } + }); }); it('supports mapMerge', async () => { - const results = await randomCol + let results = await randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) @@ -1765,10 +1948,19 @@ apiDescribe.only('Pipelines', persistence => { expectResults(results, { awards: { nebula: false, hugo: false, fakeAward: true } }); + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('awards').mapMerge({ fakeAward: true }).as('awards')) + .execute(); + expectResults(results, { + awards: { nebula: false, hugo: false, fakeAward: true } + }); }); it('supports manhattanDistance', async () => { - const results = await randomCol + let results = await randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) @@ -1779,6 +1971,19 @@ apiDescribe.only('Pipelines', persistence => { distance: 4, embedding: vector([1, 1]) }); + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Constant.vector([1, 1]).as('embedding')) + .addFields( + Field.of('embedding').manhattanDistance([3, 3]).as('distance') + ) + .execute(); + expectResults(results, { + distance: 4, + embedding: vector([1, 1]) + }); }); }); From e820ee55b4174a55fcd005410acd327bd865d91b Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 19 Feb 2025 16:58:29 -0700 Subject: [PATCH 26/75] Pipeline test reorganization --- .../test/integration/api/pipeline.test.ts | 3842 +++++++---------- .../integration/api/query_to_pipeline.test.ts | 554 +++ 2 files changed, 2158 insertions(+), 2238 deletions(-) create mode 100644 packages/firestore/test/integration/api/query_to_pipeline.test.ts diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 134a2de7680..b9130323ac7 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -23,6 +23,7 @@ import { array, descending, genericFunction, + isNan, map } from '../../../src/lite-api/expressions'; import { GeoPoint } from '../../../src/lite-api/geo_point'; @@ -56,7 +57,6 @@ import { lte, mapGet, neq, - not, orFunction, PipelineResult, regexContains, @@ -69,22 +69,7 @@ import { eqAny, logicalMaximum, notEqAny, - query, - where, - FieldPath, - orderBy, - limit, - limitToLast, - startAt, - startAfter, - endAt, - endBefore, - collectionGroup, collection, - and, - documentId, - addDoc, - getDoc, multiply, countif, bitAnd, @@ -108,11 +93,7 @@ import { substr, manhattanDistance } from '../util/firebase_export'; -import { - apiDescribe, - PERSISTENCE_MODE_UNSPECIFIED, - withTestCollection -} from '../util/helpers'; +import { apiDescribe, withTestCollection } from '../util/helpers'; use(chaiAsPromised); @@ -121,2559 +102,1944 @@ setLogLevel('debug'); apiDescribe.only('Pipelines', persistence => { addEqualityMatcher(); - describe('books tests', () => { - let firestore: Firestore; - let randomCol: CollectionReference; - - async function testCollectionWithDocs(docs: { - [id: string]: DocumentData; - }): Promise> { - for (const id in docs) { - if (docs.hasOwnProperty(id)) { - const ref = doc(randomCol, id); - await setDoc(ref, docs[id]); - } + let firestore: Firestore; + let randomCol: CollectionReference; + + async function testCollectionWithDocs(docs: { + [id: string]: DocumentData; + }): Promise> { + for (const id in docs) { + if (docs.hasOwnProperty(id)) { + const ref = doc(randomCol, id); + await setDoc(ref, docs[id]); } - return randomCol; } - - function expectResults( - result: Array>, - ...docs: string[] - ): void; - function expectResults( - result: Array>, - ...data: DocumentData[] - ): void; - - function expectResults( - result: Array>, - ...data: DocumentData[] | string[] - ): void { - expect(result.length).to.equal(data.length); - - if (data.length > 0) { - if (typeof data[0] === 'string') { - const actualIds = result.map(result => result.ref?.id); - expect(actualIds).to.deep.equal(data); - } else { - result.forEach(r => { - expect(r.data()).to.deep.equal(data.shift()); - }); - } + return randomCol; + } + + function expectResults( + result: Array>, + ...docs: string[] + ): void; + function expectResults( + result: Array>, + ...data: DocumentData[] + ): void; + + function expectResults( + result: Array>, + ...data: DocumentData[] | string[] + ): void { + expect(result.length).to.equal(data.length); + + if (data.length > 0) { + if (typeof data[0] === 'string') { + const actualIds = result.map(result => result.ref?.id); + expect(actualIds).to.deep.equal(data); + } else { + result.forEach(r => { + expect(r.data()).to.deep.equal(data.shift()); + }); } } - - async function setupBookDocs(): Promise> { - const bookDocs: { [id: string]: DocumentData } = { - book1: { - title: "The Hitchhiker's Guide to the Galaxy", - author: 'Douglas Adams', - genre: 'Science Fiction', - published: 1979, - rating: 4.2, - tags: ['comedy', 'space', 'adventure'], - awards: { - hugo: true, - nebula: false, - others: { unknown: { year: 1980 } } - }, - nestedField: { 'level.1': { 'level.2': true } } - }, - book2: { - title: 'Pride and Prejudice', - author: 'Jane Austen', - genre: 'Romance', - published: 1813, - rating: 4.5, - tags: ['classic', 'social commentary', 'love'], - awards: { none: true } - }, - book3: { - title: 'One Hundred Years of Solitude', - author: 'Gabriel García Márquez', - genre: 'Magical Realism', - published: 1967, - rating: 4.3, - tags: ['family', 'history', 'fantasy'], - awards: { nobel: true, nebula: false } - }, - book4: { - title: 'The Lord of the Rings', - author: 'J.R.R. Tolkien', - genre: 'Fantasy', - published: 1954, - rating: 4.7, - tags: ['adventure', 'magic', 'epic'], - awards: { hugo: false, nebula: false }, - remarks: null, - cost: NaN - }, - book5: { - title: "The Handmaid's Tale", - author: 'Margaret Atwood', - genre: 'Dystopian', - published: 1985, - rating: 4.1, - tags: ['feminism', 'totalitarianism', 'resistance'], - awards: { 'arthur c. clarke': true, 'booker prize': false } - }, - book6: { - title: 'Crime and Punishment', - author: 'Fyodor Dostoevsky', - genre: 'Psychological Thriller', - published: 1866, - rating: 4.3, - tags: ['philosophy', 'crime', 'redemption'], - awards: { none: true } - }, - book7: { - title: 'To Kill a Mockingbird', - author: 'Harper Lee', - genre: 'Southern Gothic', - published: 1960, - rating: 4.2, - tags: ['racism', 'injustice', 'coming-of-age'], - awards: { pulitzer: true } + } + + async function setupBookDocs(): Promise> { + const bookDocs: { [id: string]: DocumentData } = { + book1: { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } }, - book8: { - title: '1984', - author: 'George Orwell', - genre: 'Dystopian', - published: 1949, - rating: 4.2, - tags: ['surveillance', 'totalitarianism', 'propaganda'], - awards: { prometheus: true } - }, - book9: { - title: 'The Great Gatsby', - author: 'F. Scott Fitzgerald', - genre: 'Modernist', - published: 1925, - rating: 4.0, - tags: ['wealth', 'american dream', 'love'], - awards: { none: true } - }, - book10: { - title: 'Dune', - author: 'Frank Herbert', - genre: 'Science Fiction', - published: 1965, - rating: 4.6, - tags: ['politics', 'desert', 'ecology'], - awards: { hugo: true, nebula: true } - } - }; - return testCollectionWithDocs(bookDocs); - } - - let testDeferred: Deferred | undefined; - let withTestCollectionPromise: Promise | undefined; - - beforeEach(async () => { - const setupDeferred = new Deferred(); - testDeferred = new Deferred(); - withTestCollectionPromise = withTestCollection( - persistence, - {}, - async (collectionRef, firestoreInstance) => { - randomCol = collectionRef; - firestore = firestoreInstance; - await setupBookDocs(); - setupDeferred.resolve(); - - return testDeferred?.promise; - } - ); - - await setupDeferred.promise; - }); - - afterEach(async () => { - testDeferred?.resolve(); - await withTestCollectionPromise; - }); - - describe('fluent API', () => { - it('empty results as expected', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .limit(0) - .execute(); - expect(result.length).to.equal(0); - }); + nestedField: { 'level.1': { 'level.2': true } } + }, + book2: { + title: 'Pride and Prejudice', + author: 'Jane Austen', + genre: 'Romance', + published: 1813, + rating: 4.5, + tags: ['classic', 'social commentary', 'love'], + awards: { none: true } + }, + book3: { + title: 'One Hundred Years of Solitude', + author: 'Gabriel García Márquez', + genre: 'Magical Realism', + published: 1967, + rating: 4.3, + tags: ['family', 'history', 'fantasy'], + awards: { nobel: true, nebula: false } + }, + book4: { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + genre: 'Fantasy', + published: 1954, + rating: 4.7, + tags: ['adventure', 'magic', 'epic'], + awards: { hugo: false, nebula: false }, + remarks: null, + cost: NaN + }, + book5: { + title: "The Handmaid's Tale", + author: 'Margaret Atwood', + genre: 'Dystopian', + published: 1985, + rating: 4.1, + tags: ['feminism', 'totalitarianism', 'resistance'], + awards: { 'arthur c. clarke': true, 'booker prize': false } + }, + book6: { + title: 'Crime and Punishment', + author: 'Fyodor Dostoevsky', + genre: 'Psychological Thriller', + published: 1866, + rating: 4.3, + tags: ['philosophy', 'crime', 'redemption'], + awards: { none: true } + }, + book7: { + title: 'To Kill a Mockingbird', + author: 'Harper Lee', + genre: 'Southern Gothic', + published: 1960, + rating: 4.2, + tags: ['racism', 'injustice', 'coming-of-age'], + awards: { pulitzer: true } + }, + book8: { + title: '1984', + author: 'George Orwell', + genre: 'Dystopian', + published: 1949, + rating: 4.2, + tags: ['surveillance', 'totalitarianism', 'propaganda'], + awards: { prometheus: true } + }, + book9: { + title: 'The Great Gatsby', + author: 'F. Scott Fitzgerald', + genre: 'Modernist', + published: 1925, + rating: 4.0, + tags: ['wealth', 'american dream', 'love'], + awards: { none: true } + }, + book10: { + title: 'Dune', + author: 'Frank Herbert', + genre: 'Science Fiction', + published: 1965, + rating: 4.6, + tags: ['politics', 'desert', 'ecology'], + awards: { hugo: true, nebula: true } + } + }; + return testCollectionWithDocs(bookDocs); + } + + let testDeferred: Deferred | undefined; + let withTestCollectionPromise: Promise | undefined; + + beforeEach(async () => { + const setupDeferred = new Deferred(); + testDeferred = new Deferred(); + withTestCollectionPromise = withTestCollection( + persistence, + {}, + async (collectionRef, firestoreInstance) => { + randomCol = collectionRef; + firestore = firestoreInstance; + await setupBookDocs(); + setupDeferred.resolve(); + + return testDeferred?.promise; + } + ); - it('full results as expected', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .execute(); - expect(result.length).to.equal(10); - }); + await setupDeferred.promise; + }); - it('supports CollectionReference as source', async () => { - const result = await firestore - .pipeline() - .collection(randomCol) - .execute(); - expect(result.length).to.equal(10); - }); + afterEach(async () => { + testDeferred?.resolve(); + await withTestCollectionPromise; + }); - it('supports list of documents as source', async () => { - const collName = randomCol.id; + it('empty results as expected', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .limit(0) + .execute(); + expect(result.length).to.equal(0); + }); - const result = await firestore - .pipeline() - .documents([ - `${collName}/book1`, - doc(randomCol, 'book2'), - doc(randomCol, 'book3').path - ]) - .execute(); - expect(result.length).to.equal(3); - }); + it('full results as expected', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .execute(); + expect(result.length).to.equal(10); + }); - it('reject CollectionReference for another DB', async () => { - const db2 = getFirestore(firestore.app, 'notDefault'); + it('supports CollectionReference as source', async () => { + const result = await firestore.pipeline().collection(randomCol).execute(); + expect(result.length).to.equal(10); + }); - expect(() => { - firestore.pipeline().collection(collection(db2, 'foo')); - }).to.throw(/Invalid CollectionReference/); + it('supports list of documents as source', async () => { + const collName = randomCol.id; + + const result = await firestore + .pipeline() + .documents([ + `${collName}/book1`, + doc(randomCol, 'book2'), + doc(randomCol, 'book3').path + ]) + .execute(); + expect(result.length).to.equal(3); + }); - await terminate(db2); - }); + it('reject CollectionReference for another DB', async () => { + const db2 = getFirestore(firestore.app, 'notDefault'); - it('reject DocumentReference for another DB', async () => { - const db2 = getFirestore(firestore.app, 'notDefault'); + expect(() => { + firestore.pipeline().collection(collection(db2, 'foo')); + }).to.throw(/Invalid CollectionReference/); - expect(() => { - firestore.pipeline().documents([doc(db2, 'foo/bar')]); - }).to.throw(/Invalid DocumentReference/); + await terminate(db2); + }); - await terminate(db2); - }); + it('reject DocumentReference for another DB', async () => { + const db2 = getFirestore(firestore.app, 'notDefault'); - it('converts arrays and plain objects to functionValues if the customer intent is unspecified', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('rating').descending()) - .limit(1) - .select( - 'title', - 'author', - 'genre', - 'rating', - 'published', - 'tags', - 'awards' - ) - .addFields( - array([ - 1, - 2, - Field.of('genre'), - multiply('rating', 10), - [Field.of('title')], - { - published: Field.of('published') - } - ]).as('metadataArray'), - map({ - genre: Field.of('genre'), - rating: multiply('rating', 10), - nestedArray: [Field.of('title')], - nestedMap: { - published: Field.of('published') - } - }).as('metadata') - ) - .where( - andFunction( - eq('metadataArray', [ - 1, - 2, - Field.of('genre'), - multiply('rating', 10), - [Field.of('title')], - { - published: Field.of('published') - } - ]), - eq('metadata', { - genre: Field.of('genre'), - rating: multiply('rating', 10), - nestedArray: [Field.of('title')], - nestedMap: { - published: Field.of('published') - } - }) - ) - ) - .execute(); + expect(() => { + firestore.pipeline().documents([doc(db2, 'foo/bar')]); + }).to.throw(/Invalid DocumentReference/); - expect(result.length).to.equal(1); + await terminate(db2); + }); - expectResults(result, { - title: 'The Lord of the Rings', - author: 'J.R.R. Tolkien', - genre: 'Fantasy', - published: 1954, - rating: 4.7, - tags: ['adventure', 'magic', 'epic'], - awards: { hugo: false, nebula: false }, - metadataArray: [ + it('converts arrays and plain objects to functionValues if the customer intent is unspecified', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + 'title', + 'author', + 'genre', + 'rating', + 'published', + 'tags', + 'awards' + ) + .addFields( + array([ + 1, + 2, + Field.of('genre'), + multiply('rating', 10), + [Field.of('title')], + { + published: Field.of('published') + } + ]).as('metadataArray'), + map({ + genre: Field.of('genre'), + rating: multiply('rating', 10), + nestedArray: [Field.of('title')], + nestedMap: { + published: Field.of('published') + } + }).as('metadata') + ) + .where( + andFunction( + eq('metadataArray', [ 1, 2, - 'Fantasy', - 47, - ['The Lord of the Rings'], + Field.of('genre'), + multiply('rating', 10), + [Field.of('title')], { - published: 1954 + published: Field.of('published') } - ], - metadata: { - genre: 'Fantasy', - rating: 47, - nestedArray: ['The Lord of the Rings'], + ]), + eq('metadata', { + genre: Field.of('genre'), + rating: multiply('rating', 10), + nestedArray: [Field.of('title')], nestedMap: { - published: 1954 + published: Field.of('published') } - } - }); - }); + }) + ) + ) + .execute(); + + expect(result.length).to.equal(1); + + expectResults(result, { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + genre: 'Fantasy', + published: 1954, + rating: 4.7, + tags: ['adventure', 'magic', 'epic'], + awards: { hugo: false, nebula: false }, + metadataArray: [ + 1, + 2, + 'Fantasy', + 47, + ['The Lord of the Rings'], + { + published: 1954 + } + ], + metadata: { + genre: 'Fantasy', + rating: 47, + nestedArray: ['The Lord of the Rings'], + nestedMap: { + published: 1954 + } + } + }); + }); - it('accepts and returns all data types', async () => { - const refDate = new Date(); - const refTimestamp = Timestamp.now(); - const constants = [ - Constant.of(1).as('number'), - Constant.of('a string').as('string'), - Constant.of(true).as('boolean'), - Constant.of(null).as('null'), - Constant.of(new GeoPoint(0.1, 0.2)).as('geoPoint'), - Constant.of(refTimestamp).as('timestamp'), - Constant.of(refDate).as('date'), - Constant.of( - Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])) - ).as('bytes'), - Constant.of(doc(firestore, 'foo', 'bar')).as('documentReference'), - Constant.of(vector([1, 2, 3])).as('vectorValue'), - Constant.of({ - 'number': 1, - 'string': 'a string', - 'boolean': true, - 'null': null, - 'geoPoint': new GeoPoint(0.1, 0.2), - 'timestamp': refTimestamp, - 'date': refDate, - 'uint8Array': Bytes.fromUint8Array( - new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0]) - ), - 'documentReference': doc(firestore, 'foo', 'bar'), - 'vectorValue': vector([1, 2, 3]), - 'map': { - 'number': 2, - 'string': 'b string' - }, - 'array': [1, 'c string'] - }).as('map'), - Constant.of([ - 1, - 'a string', - true, - null, - new GeoPoint(0.1, 0.2), - refTimestamp, - refDate, - Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), - doc(firestore, 'foo', 'bar'), - vector([1, 2, 3]), - { - 'number': 2, - 'string': 'b string' - } - ]).as('array') - ]; + it('accepts and returns all data types', async () => { + const refDate = new Date(); + const refTimestamp = Timestamp.now(); + const constants = [ + Constant.of(1).as('number'), + Constant.of('a string').as('string'), + Constant.of(true).as('boolean'), + Constant.of(null).as('null'), + Constant.of(new GeoPoint(0.1, 0.2)).as('geoPoint'), + Constant.of(refTimestamp).as('timestamp'), + Constant.of(refDate).as('date'), + Constant.of( + Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])) + ).as('bytes'), + Constant.of(doc(firestore, 'foo', 'bar')).as('documentReference'), + Constant.of(vector([1, 2, 3])).as('vectorValue'), + Constant.of({ + 'number': 1, + 'string': 'a string', + 'boolean': true, + 'null': null, + 'geoPoint': new GeoPoint(0.1, 0.2), + 'timestamp': refTimestamp, + 'date': refDate, + 'uint8Array': Bytes.fromUint8Array( + new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0]) + ), + 'documentReference': doc(firestore, 'foo', 'bar'), + 'vectorValue': vector([1, 2, 3]), + 'map': { + 'number': 2, + 'string': 'b string' + }, + 'array': [1, 'c string'] + }).as('map'), + Constant.of([ + 1, + 'a string', + true, + null, + new GeoPoint(0.1, 0.2), + refTimestamp, + refDate, + Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), + doc(firestore, 'foo', 'bar'), + vector([1, 2, 3]), + { + 'number': 2, + 'string': 'b string' + } + ]).as('array') + ]; + + const results = await randomCol + .pipeline() + .limit(1) + .select(...constants) + .execute(); + + expectResults(results, { + 'number': 1, + 'string': 'a string', + 'boolean': true, + 'null': null, + 'geoPoint': new GeoPoint(0.1, 0.2), + 'timestamp': refTimestamp, + 'date': Timestamp.fromDate(refDate), + 'bytes': Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), + 'documentReference': doc(firestore, 'foo', 'bar'), + 'vectorValue': vector([1, 2, 3]), + 'map': { + 'number': 1, + 'string': 'a string', + 'boolean': true, + 'null': null, + 'geoPoint': new GeoPoint(0.1, 0.2), + 'timestamp': refTimestamp, + 'date': Timestamp.fromDate(refDate), + 'uint8Array': Bytes.fromUint8Array( + new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0]) + ), + 'documentReference': doc(firestore, 'foo', 'bar'), + 'vectorValue': vector([1, 2, 3]), + 'map': { + 'number': 2, + 'string': 'b string' + }, + 'array': [1, 'c string'] + }, + 'array': [ + 1, + 'a string', + true, + null, + new GeoPoint(0.1, 0.2), + refTimestamp, + Timestamp.fromDate(refDate), + Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), + doc(firestore, 'foo', 'bar'), + vector([1, 2, 3]), + { + 'number': 2, + 'string': 'b string' + } + ] + }); + }); - const results = await randomCol - .pipeline() - .limit(1) - .select(...constants) - .execute(); + it('supports internal serialization to proto', async () => { + const pipeline = firestore + .pipeline() + .collection('books') + .where(eq('awards.hugo', true)) + .select( + 'title', + Field.of('nestedField.level.1'), + mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') + ); - expectResults(results, { - 'number': 1, - 'string': 'a string', - 'boolean': true, - 'null': null, - 'geoPoint': new GeoPoint(0.1, 0.2), - 'timestamp': refTimestamp, - 'date': Timestamp.fromDate(refDate), - 'bytes': Bytes.fromUint8Array( - new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0]) - ), - 'documentReference': doc(firestore, 'foo', 'bar'), - 'vectorValue': vector([1, 2, 3]), - 'map': { - 'number': 1, - 'string': 'a string', - 'boolean': true, - 'null': null, - 'geoPoint': new GeoPoint(0.1, 0.2), - 'timestamp': refTimestamp, - 'date': Timestamp.fromDate(refDate), - 'uint8Array': Bytes.fromUint8Array( - new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0]) - ), - 'documentReference': doc(firestore, 'foo', 'bar'), - 'vectorValue': vector([1, 2, 3]), - 'map': { - 'number': 2, - 'string': 'b string' - }, - 'array': [1, 'c string'] - }, - 'array': [ - 1, - 'a string', - true, - null, - new GeoPoint(0.1, 0.2), - refTimestamp, - Timestamp.fromDate(refDate), - Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), - doc(firestore, 'foo', 'bar'), - vector([1, 2, 3]), - { - 'number': 2, - 'string': 'b string' - } - ] - }); - }); + const proto = _internalPipelineToExecutePipelineRequestProto(pipeline); + expect(proto).not.to.be.null; + }); - it('supports internal serialization to proto', async () => { - const pipeline = firestore + describe('stages', () => { + describe('aggregate stage', () => { + it('supports aggregate', async () => { + let result = await firestore .pipeline() - .collection('books') - .where(eq('awards.hugo', true)) - .select( - 'title', - Field.of('nestedField.level.1'), - mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') - ); + .collection(randomCol.path) + .aggregate(countAll().as('count')) + .execute(); + expectResults(result, { count: 10 }); - const proto = _internalPipelineToExecutePipelineRequestProto(pipeline); - expect(proto).not.to.be.null; + result = await randomCol + .pipeline() + .where(eq('genre', 'Science Fiction')) + .aggregate( + countAll().as('count'), + avgFunction('rating').as('avgRating'), + Field.of('rating').maximum().as('maxRating') + ) + .execute(); + expectResults(result, { count: 2, avgRating: 4.4, maxRating: 4.6 }); }); - describe('aggregate stage', () => { - it('supports aggregate', async () => { - let result = await firestore + it('rejects groups without accumulators', async () => { + await expect( + randomCol .pipeline() - .collection(randomCol.path) - .aggregate(countAll().as('count')) - .execute(); - expectResults(result, { count: 10 }); - - result = await randomCol - .pipeline() - .where(eq('genre', 'Science Fiction')) - .aggregate( - countAll().as('count'), - avgFunction('rating').as('avgRating'), - Field.of('rating').maximum().as('maxRating') - ) - .execute(); - expectResults(result, { count: 2, avgRating: 4.4, maxRating: 4.6 }); - }); - - it('rejects groups without accumulators', async () => { - await expect( - randomCol - .pipeline() - .where(lt('published', 1900)) - .aggregate({ - accumulators: [], - groups: ['genre'] - }) - .execute() - ).to.be.rejected; - }); - - it('returns group and accumulate results', async () => { - const results = await randomCol - .pipeline() - .where(lt(Field.of('published'), 1984)) + .where(lt('published', 1900)) .aggregate({ - accumulators: [avgFunction('rating').as('avgRating')], + accumulators: [], groups: ['genre'] }) - .where(gt('avgRating', 4.3)) - .sort(Field.of('avgRating').descending()) - .execute(); - expectResults( - results, - { avgRating: 4.7, genre: 'Fantasy' }, - { avgRating: 4.5, genre: 'Romance' }, - { avgRating: 4.4, genre: 'Science Fiction' } - ); - }); - - it('returns min and max accumulations', async () => { - const results = await randomCol - .pipeline() - .aggregate( - countAll().as('count'), - Field.of('rating').maximum().as('maxRating'), - Field.of('published').minimum().as('minPublished') - ) - .execute(); - expectResults(results, { - count: 10, - maxRating: 4.7, - minPublished: 1813 - }); - }); - }); - - describe('distinct stage', () => { - it('returns distinct values as expected', async () => { - const results = await randomCol - .pipeline() - .distinct('genre', 'author') - .sort(Field.of('genre').ascending(), Field.of('author').ascending()) - .execute(); - expectResults( - results, - { genre: 'Dystopian', author: 'George Orwell' }, - { genre: 'Dystopian', author: 'Margaret Atwood' }, - { genre: 'Fantasy', author: 'J.R.R. Tolkien' }, - { genre: 'Magical Realism', author: 'Gabriel García Márquez' }, - { genre: 'Modernist', author: 'F. Scott Fitzgerald' }, - { genre: 'Psychological Thriller', author: 'Fyodor Dostoevsky' }, - { genre: 'Romance', author: 'Jane Austen' }, - { genre: 'Science Fiction', author: 'Douglas Adams' }, - { genre: 'Science Fiction', author: 'Frank Herbert' }, - { genre: 'Southern Gothic', author: 'Harper Lee' } - ); - }); - }); - - describe('select stage', () => { - it('can select fields', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author') - .sort(Field.of('author').ascending()) - .execute(); - expectResults( - results, - { - title: "The Hitchhiker's Guide to the Galaxy", - author: 'Douglas Adams' - }, - { title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' }, - { title: 'Dune', author: 'Frank Herbert' }, - { title: 'Crime and Punishment', author: 'Fyodor Dostoevsky' }, - { - title: 'One Hundred Years of Solitude', - author: 'Gabriel García Márquez' - }, - { title: '1984', author: 'George Orwell' }, - { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, - { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' }, - { title: 'Pride and Prejudice', author: 'Jane Austen' }, - { title: "The Handmaid's Tale", author: 'Margaret Atwood' } - ); - }); + .execute() + ).to.be.rejected; }); - describe('addField stage', () => { - it('can add fields', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author') - .addFields(Constant.of('bar').as('foo')) - .sort(Field.of('author').ascending()) - .execute(); - expectResults( - results, - { - title: "The Hitchhiker's Guide to the Galaxy", - author: 'Douglas Adams', - foo: 'bar' - }, - { - title: 'The Great Gatsby', - author: 'F. Scott Fitzgerald', - foo: 'bar' - }, - { title: 'Dune', author: 'Frank Herbert', foo: 'bar' }, - { - title: 'Crime and Punishment', - author: 'Fyodor Dostoevsky', - foo: 'bar' - }, - { - title: 'One Hundred Years of Solitude', - author: 'Gabriel García Márquez', - foo: 'bar' - }, - { title: '1984', author: 'George Orwell', foo: 'bar' }, - { - title: 'To Kill a Mockingbird', - author: 'Harper Lee', - foo: 'bar' - }, - { - title: 'The Lord of the Rings', - author: 'J.R.R. Tolkien', - foo: 'bar' - }, - { title: 'Pride and Prejudice', author: 'Jane Austen', foo: 'bar' }, - { - title: "The Handmaid's Tale", - author: 'Margaret Atwood', - foo: 'bar' - } - ); - }); - }); - - describe('where stage', () => { - it('where with and', async () => { - const results = await randomCol - .pipeline() - .where( - andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')) - ) - .execute(); - expectResults(results, 'book10'); - }); - it('where with or', async () => { - const results = await randomCol - .pipeline() - .where(orFunction(eq('genre', 'Romance'), eq('genre', 'Dystopian'))) - .select('title') - .execute(); - expectResults( - results, - { title: 'Pride and Prejudice' }, - { title: "The Handmaid's Tale" }, - { title: '1984' } - ); - }); + it('returns group and accumulate results', async () => { + const results = await randomCol + .pipeline() + .where(lt(Field.of('published'), 1984)) + .aggregate({ + accumulators: [avgFunction('rating').as('avgRating')], + groups: ['genre'] + }) + .where(gt('avgRating', 4.3)) + .sort(Field.of('avgRating').descending()) + .execute(); + expectResults( + results, + { avgRating: 4.7, genre: 'Fantasy' }, + { avgRating: 4.5, genre: 'Romance' }, + { avgRating: 4.4, genre: 'Science Fiction' } + ); }); - describe('sort, offset, and limit stages', () => { - it('supports sort, offset, and limits', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('author').ascending()) - .offset(5) - .limit(3) - .select('title', 'author') - .execute(); - expectResults( - results, - { title: '1984', author: 'George Orwell' }, - { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, - { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' } - ); + it('returns min and max accumulations', async () => { + const results = await randomCol + .pipeline() + .aggregate( + countAll().as('count'), + Field.of('rating').maximum().as('maxRating'), + Field.of('published').minimum().as('minPublished') + ) + .execute(); + expectResults(results, { + count: 10, + maxRating: 4.7, + minPublished: 1813 }); }); - describe('generic stage', () => { - it('can select fields', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .genericStage('select', [ - { - title: Field.of('title'), - metadata: { - 'author': Field.of('author') - } - } - ]) - .sort(Field.of('author').ascending()) - .limit(1) - .execute(); - expectResults(results, { - title: "The Hitchhiker's Guide to the Galaxy", - metadata: { - author: 'Douglas Adams' - } - }); - }); - - it('can add fields', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('author').ascending()) - .limit(1) - .select('title', 'author') - .genericStage('add_fields', [ - { - display: Field.of('title').strConcat(' - ', Field.of('author')) - } - ]) - .execute(); - expectResults(results, { - title: "The Hitchhiker's Guide to the Galaxy", - author: 'Douglas Adams', - display: "The Hitchhiker's Guide to the Galaxy - Douglas Adams" - }); - }); - - it('can filter with where', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author') - .genericStage('where', [Field.of('author').eq('Douglas Adams')]) - .execute(); - expectResults(results, { - title: "The Hitchhiker's Guide to the Galaxy", - author: 'Douglas Adams' - }); - }); - - it('can limit, offset, and sort', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author') - .genericStage('sort', [ - { - direction: 'ascending', - expression: Field.of('author') - } - ]) - .genericStage('offset', [3]) - .genericStage('limit', [1]) - .execute(); - expectResults(results, { - author: 'Fyodor Dostoevsky', - title: 'Crime and Punishment' - }); - }); - - it('can perform aggregate query', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author', 'rating') - .genericStage('aggregate', [ - { averageRating: Field.of('rating').avg() }, - {} - ]) - .execute(); - expectResults(results, { - averageRating: 4.3100000000000005 - }); - }); + it('returns countif accumulation', async () => { + let results = await randomCol + .pipeline() + .aggregate(countif(Field.of('rating').gt(4.3)).as('count')) + .execute(); + const expectedResults = { + count: 3 + }; + expectResults(results, expectedResults); - it('can perform distinct query', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author', 'rating') - .genericStage('distinct', [{ rating: Field.of('rating') }]) - .sort(Field.of('rating').descending()) - .execute(); - expectResults( - results, - { - rating: 4.7 - }, - { - rating: 4.6 - }, - { - rating: 4.5 - }, - { - rating: 4.3 - }, - { - rating: 4.2 - }, - { - rating: 4.1 - }, - { - rating: 4.0 - } - ); - }); + results = await randomCol + .pipeline() + .aggregate(Field.of('rating').gt(4.3).countif().as('count')) + .execute(); + expectResults(results, expectedResults); }); + }); - it('logical max works', async () => { + describe('distinct stage', () => { + it('returns distinct values as expected', async () => { const results = await randomCol .pipeline() - .select( - 'title', - logicalMaximum(Constant.of(1960), Field.of('published')).as( - 'published-safe' - ) - ) - .sort(Field.of('title').ascending()) - .limit(3) + .distinct('genre', 'author') + .sort(Field.of('genre').ascending(), Field.of('author').ascending()) .execute(); expectResults( results, - { title: '1984', 'published-safe': 1960 }, - { title: 'Crime and Punishment', 'published-safe': 1960 }, - { title: 'Dune', 'published-safe': 1965 } + { genre: 'Dystopian', author: 'George Orwell' }, + { genre: 'Dystopian', author: 'Margaret Atwood' }, + { genre: 'Fantasy', author: 'J.R.R. Tolkien' }, + { genre: 'Magical Realism', author: 'Gabriel García Márquez' }, + { genre: 'Modernist', author: 'F. Scott Fitzgerald' }, + { genre: 'Psychological Thriller', author: 'Fyodor Dostoevsky' }, + { genre: 'Romance', author: 'Jane Austen' }, + { genre: 'Science Fiction', author: 'Douglas Adams' }, + { genre: 'Science Fiction', author: 'Frank Herbert' }, + { genre: 'Southern Gothic', author: 'Harper Lee' } ); }); + }); - it('cond works', async () => { - const results = await randomCol + describe('select stage', () => { + it('can select fields', async () => { + const results = await firestore .pipeline() - .select( - 'title', - cond( - lt(Field.of('published'), 1960), - Constant.of(1960), - Field.of('published') - ).as('published-safe') - ) - .sort(Field.of('title').ascending()) - .limit(3) + .collection(randomCol.path) + .select('title', 'author') + .sort(Field.of('author').ascending()) .execute(); expectResults( results, - { title: '1984', 'published-safe': 1960 }, - { title: 'Crime and Punishment', 'published-safe': 1960 }, - { title: 'Dune', 'published-safe': 1965 } + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams' + }, + { title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' }, + { title: 'Dune', author: 'Frank Herbert' }, + { title: 'Crime and Punishment', author: 'Fyodor Dostoevsky' }, + { + title: 'One Hundred Years of Solitude', + author: 'Gabriel García Márquez' + }, + { title: '1984', author: 'George Orwell' }, + { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, + { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' }, + { title: 'Pride and Prejudice', author: 'Jane Austen' }, + { title: "The Handmaid's Tale", author: 'Margaret Atwood' } ); }); + }); - it('eqAny works', async () => { - const results = await randomCol + describe('addField stage', () => { + it('can add fields', async () => { + const results = await firestore .pipeline() - .where(eqAny('published', [1979, 1999, 1967])) - .select('title') + .collection(randomCol.path) + .select('title', 'author') + .addFields(Constant.of('bar').as('foo')) + .sort(Field.of('author').ascending()) .execute(); expectResults( results, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'One Hundred Years of Solitude' } + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + foo: 'bar' + }, + { + title: 'The Great Gatsby', + author: 'F. Scott Fitzgerald', + foo: 'bar' + }, + { title: 'Dune', author: 'Frank Herbert', foo: 'bar' }, + { + title: 'Crime and Punishment', + author: 'Fyodor Dostoevsky', + foo: 'bar' + }, + { + title: 'One Hundred Years of Solitude', + author: 'Gabriel García Márquez', + foo: 'bar' + }, + { title: '1984', author: 'George Orwell', foo: 'bar' }, + { + title: 'To Kill a Mockingbird', + author: 'Harper Lee', + foo: 'bar' + }, + { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + foo: 'bar' + }, + { title: 'Pride and Prejudice', author: 'Jane Austen', foo: 'bar' }, + { + title: "The Handmaid's Tale", + author: 'Margaret Atwood', + foo: 'bar' + } ); }); + }); - it('notEqAny works', async () => { + describe('where stage', () => { + it('where with and', async () => { const results = await randomCol .pipeline() - .where( - notEqAny( - 'published', - [1965, 1925, 1949, 1960, 1866, 1985, 1954, 1967, 1979] - ) - ) - .select('title') + .where(andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction'))) .execute(); - expectResults(results, { title: 'Pride and Prejudice' }); + expectResults(results, 'book10'); }); - - it('arrayContains works', async () => { + it('where with or', async () => { const results = await randomCol .pipeline() - .where(arrayContains('tags', 'comedy')) + .where(orFunction(eq('genre', 'Romance'), eq('genre', 'Dystopian'))) .select('title') .execute(); - expectResults(results, { - title: "The Hitchhiker's Guide to the Galaxy" - }); + expectResults( + results, + { title: 'Pride and Prejudice' }, + { title: "The Handmaid's Tale" }, + { title: '1984' } + ); }); + }); - it('arrayContainsAny works', async () => { - const results = await randomCol + describe('sort, offset, and limit stages', () => { + it('supports sort, offset, and limits', async () => { + const results = await firestore .pipeline() - .where(arrayContainsAny('tags', ['comedy', 'classic'])) - .select('title') + .collection(randomCol.path) + .sort(Field.of('author').ascending()) + .offset(5) + .limit(3) + .select('title', 'author') .execute(); expectResults( results, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'Pride and Prejudice' } + { title: '1984', author: 'George Orwell' }, + { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, + { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' } ); }); + }); - it('arrayContainsAll works', async () => { - const results = await randomCol + describe('generic stage', () => { + it('can select fields', async () => { + const results = await firestore .pipeline() - .where(Field.of('tags').arrayContainsAll('adventure', 'magic')) - .select('title') + .collection(randomCol.path) + .genericStage('select', [ + { + title: Field.of('title'), + metadata: { + 'author': Field.of('author') + } + } + ]) + .sort(Field.of('author').ascending()) + .limit(1) .execute(); - expectResults(results, { title: 'The Lord of the Rings' }); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy", + metadata: { + author: 'Douglas Adams' + } + }); }); - it('arrayLength works', async () => { - const results = await randomCol + it('can add fields', async () => { + const results = await firestore .pipeline() - .select(Field.of('tags').arrayLength().as('tagsCount')) - .where(eq('tagsCount', 3)) + .collection(randomCol.path) + .sort(Field.of('author').ascending()) + .limit(1) + .select('title', 'author') + .genericStage('add_fields', [ + { + display: Field.of('title').strConcat(' - ', Field.of('author')) + } + ]) .execute(); - expect(results.length).to.equal(10); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + display: "The Hitchhiker's Guide to the Galaxy - Douglas Adams" + }); }); - it('testStrConcat', async () => { - const results = await randomCol + it('can filter with where', async () => { + const results = await firestore .pipeline() - .select( - Field.of('author') - .strConcat(' - ', Field.of('title')) - .as('bookInfo') - ) - .limit(1) + .collection(randomCol.path) + .select('title', 'author') + .genericStage('where', [Field.of('author').eq('Douglas Adams')]) .execute(); expectResults(results, { - bookInfo: "Douglas Adams - The Hitchhiker's Guide to the Galaxy" + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams' }); }); - it('testStartsWith', async () => { - const results = await randomCol + it('can limit, offset, and sort', async () => { + const results = await firestore .pipeline() - .where(startsWith('title', 'The')) - .select('title') - .sort(Field.of('title').ascending()) + .collection(randomCol.path) + .select('title', 'author') + .genericStage('sort', [ + { + direction: 'ascending', + expression: Field.of('author') + } + ]) + .genericStage('offset', [3]) + .genericStage('limit', [1]) .execute(); - expectResults( - results, - { title: 'The Great Gatsby' }, - { title: "The Handmaid's Tale" }, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'The Lord of the Rings' } - ); + expectResults(results, { + author: 'Fyodor Dostoevsky', + title: 'Crime and Punishment' + }); }); - it('testEndsWith', async () => { - const results = await randomCol + it('can perform aggregate query', async () => { + const results = await firestore .pipeline() - .where(endsWith('title', 'y')) - .select('title') - .sort(Field.of('title').descending()) + .collection(randomCol.path) + .select('title', 'author', 'rating') + .genericStage('aggregate', [ + { averageRating: Field.of('rating').avg() }, + {} + ]) .execute(); - expectResults( - results, - { title: "The Hitchhiker's Guide to the Galaxy" }, - { title: 'The Great Gatsby' } - ); + expectResults(results, { + averageRating: 4.3100000000000005 + }); }); - it('testLength', async () => { - const results = await randomCol + it('can perform distinct query', async () => { + const results = await firestore .pipeline() - .select( - Field.of('title').charLength().as('titleLength'), - Field.of('title') - ) - .where(gt('titleLength', 20)) - .sort(Field.of('title').ascending()) + .collection(randomCol.path) + .select('title', 'author', 'rating') + .genericStage('distinct', [{ rating: Field.of('rating') }]) + .sort(Field.of('rating').descending()) .execute(); - expectResults( results, - { - titleLength: 29, - title: 'One Hundred Years of Solitude' + rating: 4.7 + }, + { + rating: 4.6 + }, + { + rating: 4.5 + }, + { + rating: 4.3 }, { - titleLength: 36, - title: "The Hitchhiker's Guide to the Galaxy" + rating: 4.2 }, { - titleLength: 21, - title: 'The Lord of the Rings' + rating: 4.1 }, { - titleLength: 21, - title: 'To Kill a Mockingbird' + rating: 4.0 } ); }); + }); + }); - it('testLike', async () => { - const results = await randomCol - .pipeline() - .where(like('title', '%Guide%')) - .select('title') - .execute(); - expectResults(results, { - title: "The Hitchhiker's Guide to the Galaxy" - }); + describe('function expressions', () => { + it('logical max works', async () => { + const results = await randomCol + .pipeline() + .select( + 'title', + logicalMaximum(Constant.of(1960), Field.of('published')).as( + 'published-safe' + ) + ) + .sort(Field.of('title').ascending()) + .limit(3) + .execute(); + expectResults( + results, + { title: '1984', 'published-safe': 1960 }, + { title: 'Crime and Punishment', 'published-safe': 1960 }, + { title: 'Dune', 'published-safe': 1965 } + ); + }); + + it('cond works', async () => { + const results = await randomCol + .pipeline() + .select( + 'title', + cond( + lt(Field.of('published'), 1960), + Constant.of(1960), + Field.of('published') + ).as('published-safe') + ) + .sort(Field.of('title').ascending()) + .limit(3) + .execute(); + expectResults( + results, + { title: '1984', 'published-safe': 1960 }, + { title: 'Crime and Punishment', 'published-safe': 1960 }, + { title: 'Dune', 'published-safe': 1965 } + ); + }); + + it('eqAny works', async () => { + const results = await randomCol + .pipeline() + .where(eqAny('published', [1979, 1999, 1967])) + .select('title') + .execute(); + expectResults( + results, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'One Hundred Years of Solitude' } + ); + }); + + it('notEqAny works', async () => { + const results = await randomCol + .pipeline() + .where( + notEqAny( + 'published', + [1965, 1925, 1949, 1960, 1866, 1985, 1954, 1967, 1979] + ) + ) + .select('title') + .execute(); + expectResults(results, { title: 'Pride and Prejudice' }); + }); + + it('arrayContains works', async () => { + const results = await randomCol + .pipeline() + .where(arrayContains('tags', 'comedy')) + .select('title') + .execute(); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy" }); + }); - it('testRegexContains', async () => { - const results = await randomCol - .pipeline() - .where(regexContains('title', '(?i)(the|of)')) - .execute(); - expect(results.length).to.equal(5); + it('arrayContainsAny works', async () => { + const results = await randomCol + .pipeline() + .where(arrayContainsAny('tags', ['comedy', 'classic'])) + .select('title') + .execute(); + expectResults( + results, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'Pride and Prejudice' } + ); + }); + + it('arrayContainsAll works', async () => { + const results = await randomCol + .pipeline() + .where(Field.of('tags').arrayContainsAll('adventure', 'magic')) + .select('title') + .execute(); + expectResults(results, { title: 'The Lord of the Rings' }); + }); + + it('arrayLength works', async () => { + const results = await randomCol + .pipeline() + .select(Field.of('tags').arrayLength().as('tagsCount')) + .where(eq('tagsCount', 3)) + .execute(); + expect(results.length).to.equal(10); + }); + + it('testStrConcat', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('author').strConcat(' - ', Field.of('title')).as('bookInfo') + ) + .limit(1) + .execute(); + expectResults(results, { + bookInfo: "Douglas Adams - The Hitchhiker's Guide to the Galaxy" }); + }); - it('testRegexMatches', async () => { - const results = await randomCol - .pipeline() - .where(regexMatch('title', '.*(?i)(the|of).*')) - .execute(); - expect(results.length).to.equal(5); + it('testStartsWith', async () => { + const results = await randomCol + .pipeline() + .where(startsWith('title', 'The')) + .select('title') + .sort(Field.of('title').ascending()) + .execute(); + expectResults( + results, + { title: 'The Great Gatsby' }, + { title: "The Handmaid's Tale" }, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'The Lord of the Rings' } + ); + }); + + it('testEndsWith', async () => { + const results = await randomCol + .pipeline() + .where(endsWith('title', 'y')) + .select('title') + .sort(Field.of('title').descending()) + .execute(); + expectResults( + results, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'The Great Gatsby' } + ); + }); + + it('testLength', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('title').charLength().as('titleLength'), + Field.of('title') + ) + .where(gt('titleLength', 20)) + .sort(Field.of('title').ascending()) + .execute(); + + expectResults( + results, + + { + titleLength: 29, + title: 'One Hundred Years of Solitude' + }, + { + titleLength: 36, + title: "The Hitchhiker's Guide to the Galaxy" + }, + { + titleLength: 21, + title: 'The Lord of the Rings' + }, + { + titleLength: 21, + title: 'To Kill a Mockingbird' + } + ); + }); + + it('testLike', async () => { + const results = await randomCol + .pipeline() + .where(like('title', '%Guide%')) + .select('title') + .execute(); + expectResults(results, { + title: "The Hitchhiker's Guide to the Galaxy" }); + }); - it('testArithmeticOperations', async () => { - const results = await randomCol - .pipeline() - .select( - add(Field.of('rating'), 1).as('ratingPlusOne'), - subtract(Field.of('published'), 1900).as('yearsSince1900'), - Field.of('rating').multiply(10).as('ratingTimesTen'), - Field.of('rating').divide(2).as('ratingDividedByTwo') + it('testRegexContains', async () => { + const results = await randomCol + .pipeline() + .where(regexContains('title', '(?i)(the|of)')) + .execute(); + expect(results.length).to.equal(5); + }); + + it('testRegexMatches', async () => { + const results = await randomCol + .pipeline() + .where(regexMatch('title', '.*(?i)(the|of).*')) + .execute(); + expect(results.length).to.equal(5); + }); + + it('testArithmeticOperations', async () => { + const results = await randomCol + .pipeline() + .select( + add(Field.of('rating'), 1).as('ratingPlusOne'), + subtract(Field.of('published'), 1900).as('yearsSince1900'), + Field.of('rating').multiply(10).as('ratingTimesTen'), + Field.of('rating').divide(2).as('ratingDividedByTwo') + ) + .limit(1) + .execute(); + expectResults(results, { + ratingPlusOne: 5.2, + yearsSince1900: 79, + ratingTimesTen: 42, + ratingDividedByTwo: 2.1 + }); + }); + + it('testComparisonOperators', async () => { + const results = await randomCol + .pipeline() + .where( + andFunction( + gt('rating', 4.2), + lte(Field.of('rating'), 4.5), + neq('genre', 'Science Fiction') ) - .limit(1) - .execute(); - expectResults(results, { - ratingPlusOne: 5.2, - yearsSince1900: 79, - ratingTimesTen: 42, - ratingDividedByTwo: 2.1 - }); + ) + .select('rating', 'title') + .sort(Field.of('title').ascending()) + .execute(); + expectResults( + results, + { rating: 4.3, title: 'Crime and Punishment' }, + { + rating: 4.3, + title: 'One Hundred Years of Solitude' + }, + { rating: 4.5, title: 'Pride and Prejudice' } + ); + }); + + it('testLogicalOperators', async () => { + const results = await randomCol + .pipeline() + .where( + orFunction( + andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')), + lt('published', 1900) + ) + ) + .select('title') + .sort(Field.of('title').ascending()) + .execute(); + expectResults( + results, + { title: 'Crime and Punishment' }, + { title: 'Dune' }, + { title: 'Pride and Prejudice' } + ); + }); + + it('testChecks', async () => { + let results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select( + isNull('rating').as('ratingIsNull'), + isNan('rating').as('ratingIsNaN'), + isError(arrayOffset('title', 0)).as('isError'), + ifError(arrayOffset('title', 0), Constant.of('was error')).as( + 'ifError' + ), + isAbsent('foo').as('isAbsent'), + isNotNull('title').as('titleIsNotNull'), + isNotNan('cost').as('costIsNotNan') + ) + .execute(); + expectResults(results, { + ratingIsNull: false, + ratingIsNaN: false, + isError: true, + ifError: 'was error', + isAbsent: true, + titleIsNotNull: true, + costIsNotNan: false }); - it('testComparisonOperators', async () => { - const results = await randomCol - .pipeline() - .where( - andFunction( - gt('rating', 4.2), - lte(Field.of('rating'), 4.5), - neq('genre', 'Science Fiction') - ) + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select( + Field.of('rating').isNull().as('ratingIsNull'), + Field.of('rating').isNaN().as('ratingIsNaN'), + arrayOffset('title', 0).isError().as('isError'), + arrayOffset('title', 0) + .ifError(Constant.of('was error')) + .as('ifError'), + Field.of('foo').isAbsent().as('isAbsent'), + Field.of('title').isNotNull().as('titleIsNotNull'), + Field.of('cost').isNotNan().as('costIsNotNan') + ) + .execute(); + expectResults(results, { + ratingIsNull: false, + ratingIsNaN: false, + isError: true, + ifError: 'was error', + isAbsent: true, + titleIsNotNull: true, + costIsNotNan: false + }); + }); + + it('testMapGet', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('published').descending()) + .select( + Field.of('awards').mapGet('hugo').as('hugoAward'), + Field.of('awards').mapGet('others').as('others'), + Field.of('title') + ) + .where(eq('hugoAward', true)) + .execute(); + expectResults( + results, + { + hugoAward: true, + title: "The Hitchhiker's Guide to the Galaxy", + others: { unknown: { year: 1980 } } + }, + { hugoAward: true, title: 'Dune', others: null } + ); + }); + + it('testDistanceFunctions', async () => { + const sourceVector = [0.1, 0.1]; + const targetVector = [0.5, 0.8]; + let results = await randomCol + .pipeline() + .select( + cosineDistance(Constant.vector(sourceVector), targetVector).as( + 'cosineDistance' + ), + dotProduct(Constant.vector(sourceVector), targetVector).as( + 'dotProductDistance' + ), + euclideanDistance(Constant.vector(sourceVector), targetVector).as( + 'euclideanDistance' + ), + manhattanDistance(Constant.vector(sourceVector), targetVector).as( + 'manhattanDistance' ) - .select('rating', 'title') - .sort(Field.of('title').ascending()) - .execute(); - expectResults( - results, - { rating: 4.3, title: 'Crime and Punishment' }, - { - rating: 4.3, - title: 'One Hundred Years of Solitude' - }, - { rating: 4.5, title: 'Pride and Prejudice' } - ); + ) + .limit(1) + .execute(); + + expectResults(results, { + cosineDistance: 0.02560880430538015, + dotProductDistance: 0.13, + euclideanDistance: 0.806225774829855, + manhattanDistance: 1.1 }); - it('testLogicalOperators', async () => { + results = await randomCol + .pipeline() + .select( + Constant.vector(sourceVector) + .cosineDistance(targetVector) + .as('cosineDistance'), + Constant.vector(sourceVector) + .dotProduct(targetVector) + .as('dotProductDistance'), + Constant.vector(sourceVector) + .euclideanDistance(targetVector) + .as('euclideanDistance'), + Constant.vector(sourceVector) + .manhattanDistance(targetVector) + .as('manhattanDistance') + ) + .limit(1) + .execute(); + + expectResults(results, { + cosineDistance: 0.02560880430538015, + dotProductDistance: 0.13, + euclideanDistance: 0.806225774829855, + manhattanDistance: 1.1 + }); + }); + + it('testNestedFields', async () => { + const results = await randomCol + .pipeline() + .where(eq('awards.hugo', true)) + .select('title', 'awards.hugo') + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + 'awards.hugo': true + }, + { title: 'Dune', 'awards.hugo': true } + ); + }); + + it('test mapGet with field name including . notation', async () => { + const results = await randomCol + .pipeline() + .where(eq('awards.hugo', true)) + .select( + 'title', + Field.of('nestedField.level.1'), + mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') + ) + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + 'nestedField.level.`1`': null, + nested: true + }, + { title: 'Dune', 'nestedField.level.`1`': null, nested: null } + ); + }); + + describe('genericFunction', () => { + it('add selectable', async () => { const results = await randomCol .pipeline() - .where( - orFunction( - andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')), - lt('published', 1900) + .sort(descending('rating')) + .limit(1) + .select( + genericFunction('add', [Field.of('rating'), Constant.of(1)]).as( + 'rating' ) ) - .select('title') - .sort(Field.of('title').ascending()) .execute(); - expectResults( - results, - { title: 'Crime and Punishment' }, - { title: 'Dune' }, - { title: 'Pride and Prejudice' } - ); + expectResults(results, { + rating: 5.7 + }); }); - it('testChecks', async () => { + it('and (variadic) selectable', async () => { const results = await randomCol .pipeline() - .where(not(Field.of('rating').isNaN())) - .select( - Field.of('rating').isNull().as('ratingIsNull'), - not(Field.of('rating').isNaN()).as('ratingIsNotNaN') + .where( + genericFunction('and', [ + Field.of('rating').gt(0), + Field.of('title').charLength().lt(5), + Field.of('tags').arrayContains('propaganda') + ]) ) - .limit(1) + .select('title') .execute(); - expectResults(results, { ratingIsNull: false, ratingIsNotNaN: true }); + expectResults(results, { + title: '1984' + }); }); - it('testMapGet', async () => { + it('array contains any', async () => { const results = await randomCol .pipeline() - .sort(Field.of('published').descending()) - .select( - Field.of('awards').mapGet('hugo').as('hugoAward'), - Field.of('awards').mapGet('others').as('others'), - Field.of('title') + .where( + genericFunction('array_contains_any', [ + Field.of('tags'), + ['politics'] + ]) ) - .where(eq('hugoAward', true)) + .select('title') .execute(); - expectResults( - results, - { - hugoAward: true, - title: "The Hitchhiker's Guide to the Galaxy", - others: { unknown: { year: 1980 } } - }, - { hugoAward: true, title: 'Dune', others: null } - ); + expectResults(results, { + title: 'Dune' + }); }); - it('testDistanceFunctions', async () => { - const sourceVector = [0.1, 0.1]; - const targetVector = [0.5, 0.8]; + it('countif aggregate', async () => { const results = await randomCol .pipeline() - .select( - cosineDistance(Constant.vector(sourceVector), targetVector).as( - 'cosineDistance' - ), - dotProduct(Constant.vector(sourceVector), targetVector).as( - 'dotProductDistance' - ), - euclideanDistance(Constant.vector(sourceVector), targetVector).as( - 'euclideanDistance' + .aggregate( + genericFunction('countif', [Field.of('rating').gte(4.5)]).as( + 'countOfBest' ) ) - .limit(1) .execute(); - expectResults(results, { - cosineDistance: 0.02560880430538015, - dotProductDistance: 0.13, - euclideanDistance: 0.806225774829855 + countOfBest: 3 }); }); - it('testNestedFields', async () => { + it('sort by char_len', async () => { const results = await randomCol .pipeline() - .where(eq('awards.hugo', true)) - .select('title', 'awards.hugo') + .sort( + genericFunction('char_length', [Field.of('title')]).ascending(), + descending('__name__') + ) + .limit(3) + .select('title') .execute(); expectResults( results, { - title: "The Hitchhiker's Guide to the Galaxy", - 'awards.hugo': true + title: '1984' }, - { title: 'Dune', 'awards.hugo': true } - ); - }); - - it('test mapGet with field name including . notation', async () => { - const results = await randomCol - .pipeline() - .where(eq('awards.hugo', true)) - .select( - 'title', - Field.of('nestedField.level.1'), - mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') - ) - .execute(); - expectResults( - results, { - title: "The Hitchhiker's Guide to the Galaxy", - 'nestedField.level.`1`': null, - nested: true + title: 'Dune' }, - { title: 'Dune', 'nestedField.level.`1`': null, nested: null } + { + title: 'The Great Gatsby' + } ); }); + }); - it('supports countif', async () => { - let results = await randomCol - .pipeline() - .aggregate(countif(Field.of('rating').gt(4.3)).as('count')) - .execute(); - const expectedResults = { - count: 3 - }; - expectResults(results, expectedResults); - - results = await randomCol + describe.skip('not implemented in backend', () => { + it('supports Bit_and', async () => { + const results = await randomCol .pipeline() - .aggregate(Field.of('rating').gt(4.3).countif().as('count')) + .limit(1) + .select(bitAnd(Constant.of(5), 12).as('result')) .execute(); - expectResults(results, expectedResults); - }); - - describe('genericFunction', () => { - it('add selectable', async () => { + expectResults(results, { + result: 4 + }); + it('supports Bit_and', async () => { const results = await randomCol .pipeline() - .sort(descending('rating')) .limit(1) - .select( - genericFunction('add', [Field.of('rating'), Constant.of(1)]).as( - 'rating' - ) - ) + .select(Constant.of(5).bitAnd(12).as('result')) .execute(); expectResults(results, { - rating: 5.7 + result: 4 }); }); - it('and (variadic) selectable', async () => { - const results = await randomCol + it('supports Bit_or', async () => { + let results = await randomCol .pipeline() - .where( - genericFunction('and', [ - Field.of('rating').gt(0), - Field.of('title').charLength().lt(5), - Field.of('tags').arrayContains('propaganda') - ]) - ) - .select('title') + .limit(1) + .select(bitOr(Constant.of(5), 12).as('result')) .execute(); expectResults(results, { - title: '1984' + result: 13 + }); + results = await randomCol + .pipeline() + .limit(1) + .select(Constant.of(5).bitOr(12).as('result')) + .execute(); + expectResults(results, { + result: 13 }); }); - it('array contains any', async () => { - const results = await randomCol + it('supports Bit_xor', async () => { + let results = await randomCol .pipeline() - .where( - genericFunction('array_contains_any', [ - Field.of('tags'), - ['politics'] - ]) - ) - .select('title') + .limit(1) + .select(bitXor(Constant.of(5), 12).as('result')) .execute(); expectResults(results, { - title: 'Dune' + result: 9 + }); + results = await randomCol + .pipeline() + .limit(1) + .select(Constant.of(5).bitXor(12).as('result')) + .execute(); + expectResults(results, { + result: 9 }); }); - it('countif aggregate', async () => { - const results = await randomCol + it('supports Bit_not', async () => { + let results = await randomCol .pipeline() - .aggregate( - genericFunction('countif', [Field.of('rating').gte(4.5)]).as( - 'countOfBest' + .limit(1) + .select( + bitNot(Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd)))).as( + 'result' ) ) .execute(); expectResults(results, { - countOfBest: 3 + result: Bytes.fromUint8Array(Uint8Array.of(0x02)) }); - }); - - it('sort by char_len', async () => { - const results = await randomCol + results = await randomCol .pipeline() - .sort( - genericFunction('char_length', [Field.of('title')]).ascending(), - descending('__name__') + .limit(1) + .select( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd))) + .bitNot() + .as('result') ) - .limit(3) - .select('title') .execute(); - expectResults( - results, - { - title: '1984' - }, - { - title: 'Dune' - }, - { - title: 'The Great Gatsby' - } - ); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x02)) + }); }); - }); - describe.skip('not implemented in backend', () => { - it('supports Bit_and', async () => { - const results = await randomCol + it('supports Bit_left_shift', async () => { + let results = await randomCol .pipeline() .limit(1) - .select(bitAnd(Constant.of(5), 12).as('result')) + .select( + bitLeftShift( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) .execute(); expectResults(results, { - result: 4 - }); - it('supports Bit_and', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select(Constant.of(5).bitAnd(12).as('result')) - .execute(); - expectResults(results, { - result: 4 - }); - }); - - it('supports Bit_or', async () => { - let results = await randomCol - .pipeline() - .limit(1) - .select(bitOr(Constant.of(5), 12).as('result')) - .execute(); - expectResults(results, { - result: 13 - }); - results = await randomCol - .pipeline() - .limit(1) - .select(Constant.of(5).bitOr(12).as('result')) - .execute(); - expectResults(results, { - result: 13 - }); - }); - - it('supports Bit_xor', async () => { - let results = await randomCol - .pipeline() - .limit(1) - .select(bitXor(Constant.of(5), 12).as('result')) - .execute(); - expectResults(results, { - result: 9 - }); - results = await randomCol - .pipeline() - .limit(1) - .select(Constant.of(5).bitXor(12).as('result')) - .execute(); - expectResults(results, { - result: 9 - }); - }); - - it('supports Bit_not', async () => { - let results = await randomCol - .pipeline() - .limit(1) - .select( - bitNot( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd))) - ).as('result') - ) - .execute(); - expectResults(results, { - result: Bytes.fromUint8Array(Uint8Array.of(0x02)) - }); - results = await randomCol - .pipeline() - .limit(1) - .select( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd))) - .bitNot() - .as('result') - ) - .execute(); - expectResults(results, { - result: Bytes.fromUint8Array(Uint8Array.of(0x02)) - }); - }); - - it('supports Bit_left_shift', async () => { - let results = await randomCol - .pipeline() - .limit(1) - .select( - bitLeftShift( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), - 2 - ).as('result') - ) - .execute(); - expectResults(results, { - result: Bytes.fromUint8Array(Uint8Array.of(0x04)) - }); - results = await randomCol - .pipeline() - .limit(1) - .select( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))) - .bitLeftShift(2) - .as('result') - ) - .execute(); - expectResults(results, { - result: Bytes.fromUint8Array(Uint8Array.of(0x04)) - }); - }); - - it('supports Bit_right_shift', async () => { - let results = await randomCol - .pipeline() - .limit(1) - .select( - bitRightShift( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), - 2 - ).as('result') - ) - .execute(); - expectResults(results, { - result: Bytes.fromUint8Array(Uint8Array.of(0x01)) - }); - results = await randomCol - .pipeline() - .limit(1) - .select( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))) - .bitRightShift(2) - .as('result') - ) - .execute(); - expectResults(results, { - result: Bytes.fromUint8Array(Uint8Array.of(0x01)) - }); - }); - - it('supports Document_id', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(documentIdFunction(Field.of('__path__')).as('docId')) - .execute(); - expectResults(results, { - docId: 'book4' - }); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('__path__').documentId().as('docId')) - .execute(); - expectResults(results, { - docId: 'book4' - }); - }); - - it('supports Substr', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(substr('title', 9, 2).as('of')) - .execute(); - expectResults(results, { - of: 'of' - }); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('title').substr(9, 2).as('of')) - .execute(); - expectResults(results, { - of: 'of' - }); - }); - - it('arrayConcat works', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('tags') - .arrayConcat(['newTag1', 'newTag2']) - .as('modifiedTags') - ) - .limit(1) - .execute(); - expectResults(results, { - modifiedTags: [ - 'comedy', - 'space', - 'adventure', - 'newTag1', - 'newTag2' - ] - }); - }); - - it('testToLowercase', async () => { - const results = await randomCol - .pipeline() - .select(Field.of('title').toLower().as('lowercaseTitle')) - .limit(1) - .execute(); - expectResults(results, { - lowercaseTitle: "the hitchhiker's guide to the galaxy" - }); - }); - - it('testToUppercase', async () => { - const results = await randomCol - .pipeline() - .select(Field.of('author').toUpper().as('uppercaseAuthor')) - .limit(1) - .execute(); - expectResults(results, { uppercaseAuthor: 'DOUGLAS ADAMS' }); + result: Bytes.fromUint8Array(Uint8Array.of(0x04)) }); - - it('testTrim', async () => { - const results = await randomCol - .pipeline() - .addFields( - Constant.of(" The Hitchhiker's Guide to the Galaxy ").as( - 'spacedTitle' - ) - ) - .select( - Field.of('spacedTitle').trim().as('trimmedTitle'), - Field.of('spacedTitle') - ) - .limit(1) - .execute(); - expectResults(results, { - spacedTitle: " The Hitchhiker's Guide to the Galaxy ", - trimmedTitle: "The Hitchhiker's Guide to the Galaxy" - }); + results = await randomCol + .pipeline() + .limit(1) + .select( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))) + .bitLeftShift(2) + .as('result') + ) + .execute(); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x04)) }); }); - it('supports Rand', async () => { - const results = await randomCol + it('supports Bit_right_shift', async () => { + let results = await randomCol + .pipeline() + .limit(1) + .select( + bitRightShift( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + .execute(); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x01)) + }); + results = await randomCol .pipeline() - .limit(10) - .select(rand().as('result')) + .limit(1) + .select( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))) + .bitRightShift(2) + .as('result') + ) .execute(); - expect(results.length).to.equal(10); - results.forEach(d => { - expect(d.get('result')).to.be.lt(1); - expect(d.get('result')).to.be.gte(0); + expectResults(results, { + result: Bytes.fromUint8Array(Uint8Array.of(0x01)) }); }); - it('supports array', async () => { - const result = await firestore + it('supports Document_id', async () => { + let results = await randomCol .pipeline() - .collection(randomCol.path) .sort(Field.of('rating').descending()) .limit(1) - .select(array([1, 2, 3, 4]).as('metadata')) + .select(documentIdFunction(Field.of('__path__')).as('docId')) .execute(); - expect(result.length).to.equal(1); - expectResults(result, { - metadata: [1, 2, 3, 4] + expectResults(results, { + docId: 'book4' }); - }); - - it('evaluates expression in array', async () => { - const result = await firestore + results = await randomCol .pipeline() - .collection(randomCol.path) .sort(Field.of('rating').descending()) .limit(1) - .select( - array([1, 2, Field.of('genre'), multiply('rating', 10)]).as( - 'metadata' - ) - ) + .select(Field.of('__path__').documentId().as('docId')) .execute(); - expect(result.length).to.equal(1); - expectResults(result, { - metadata: [1, 2, 'Fantasy', 47] + expectResults(results, { + docId: 'book4' }); }); - it('supports arrayOffset', async () => { + it('supports Substr', async () => { let results = await randomCol .pipeline() .sort(Field.of('rating').descending()) - .limit(3) - .select(arrayOffset('tags', 0).as('firstTag')) + .limit(1) + .select(substr('title', 9, 2).as('of')) .execute(); - const expectedResults = [ - { - firstTag: 'adventure' - }, - { - firstTag: 'politics' - }, - { - firstTag: 'classic' - } - ]; - expectResults(results, ...expectedResults); - + expectResults(results, { + of: 'of' + }); results = await randomCol .pipeline() .sort(Field.of('rating').descending()) - .limit(3) - .select(Field.of('tags').arrayOffset(0).as('firstTag')) + .limit(1) + .select(Field.of('title').substr(9, 2).as('of')) .execute(); - expectResults(results, ...expectedResults); + expectResults(results, { + of: 'of' + }); }); - }); - // TODO: current_context tests with are failing because of b/395937453 - it.skip('supports currentContext', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(currentContext().as('currentContext')) - .execute(); - expectResults(results, { - currentContext: 'TODO' + it('arrayConcat works', async () => { + const results = await randomCol + .pipeline() + .select( + Field.of('tags') + .arrayConcat(['newTag1', 'newTag2']) + .as('modifiedTags') + ) + .limit(1) + .execute(); + expectResults(results, { + modifiedTags: ['comedy', 'space', 'adventure', 'newTag1', 'newTag2'] + }); }); - }); - it('supports isError', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(isError(arrayOffset('title', 0)).as('firstTag')) - .execute(); - const expectedResults = [ - { - firstTag: true - } - ]; - expectResults(results, ...expectedResults); + it('testToLowercase', async () => { + const results = await randomCol + .pipeline() + .select(Field.of('title').toLower().as('lowercaseTitle')) + .limit(1) + .execute(); + expectResults(results, { + lowercaseTitle: "the hitchhiker's guide to the galaxy" + }); + }); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(arrayOffset('title', 0).isError().as('firstTag')) - .execute(); - expectResults(results, ...expectedResults); - }); + it('testToUppercase', async () => { + const results = await randomCol + .pipeline() + .select(Field.of('author').toUpper().as('uppercaseAuthor')) + .limit(1) + .execute(); + expectResults(results, { uppercaseAuthor: 'DOUGLAS ADAMS' }); + }); - it('supports ifError', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select( - ifError(arrayOffset('title', 0), Constant.of('was error')).as( - 'firstTag' + it('testTrim', async () => { + const results = await randomCol + .pipeline() + .addFields( + Constant.of(" The Hitchhiker's Guide to the Galaxy ").as( + 'spacedTitle' + ) ) - ) - .execute(); - const expectedResults = [ - { - firstTag: 'was error' - } - ]; - expectResults(results, ...expectedResults); - - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select( - arrayOffset('title', 0) - .ifError(Constant.of('was error')) - .as('firstTag') - ) - .execute(); - expectResults(results, ...expectedResults); - }); - - it('supports isAbsent', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(isAbsent('foo').as('firstTag')) - .execute(); - const expectedResults = [ - { - firstTag: true - } - ]; - expectResults(results, ...expectedResults); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('foo').isAbsent().as('firstTag')) - .execute(); - expectResults(results, ...expectedResults); - }); - - it('supports isNull', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(isNull('remarks').as('remarksIsNull')) - .execute(); - const expectedResults = [ - { - remarksIsNull: true - } - ]; - expectResults(results, ...expectedResults); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('remarks').isNull().as('remarksIsNull')) - .execute(); - expectResults(results, ...expectedResults); - }); - - it('supports isNotNull', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(isNotNull('title').as('titleIsNotNull')) - .execute(); - expectResults(results, { - titleIsNotNull: true - }); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('title').isNotNull().as('titleIsNotNull')) - .execute(); - expectResults(results, { - titleIsNotNull: true + .select( + Field.of('spacedTitle').trim().as('trimmedTitle'), + Field.of('spacedTitle') + ) + .limit(1) + .execute(); + expectResults(results, { + spacedTitle: " The Hitchhiker's Guide to the Galaxy ", + trimmedTitle: "The Hitchhiker's Guide to the Galaxy" + }); }); }); - - it('supports isNotNan', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(isNotNan('cost').as('costIsNotNan')) - .execute(); - expectResults(results, { - costIsNotNan: false - }); - results = await randomCol + + it('supports Rand', async () => { + const results = await randomCol .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('cost').isNotNan().as('costIsNotNan')) + .limit(10) + .select(rand().as('result')) .execute(); - expectResults(results, { - costIsNotNan: false + expect(results.length).to.equal(10); + results.forEach(d => { + expect(d.get('result')).to.be.lt(1); + expect(d.get('result')).to.be.gte(0); }); }); - it('supports map', async () => { + it('supports array', async () => { const result = await firestore .pipeline() .collection(randomCol.path) .sort(Field.of('rating').descending()) .limit(1) - .select( - map({ - foo: 'bar' - }).as('metadata') - ) + .select(array([1, 2, 3, 4]).as('metadata')) .execute(); - expect(result.length).to.equal(1); expectResults(result, { - metadata: { - foo: 'bar' - } + metadata: [1, 2, 3, 4] }); }); - it('evaluates expression in map', async () => { + it('evaluates expression in array', async () => { const result = await firestore .pipeline() .collection(randomCol.path) .sort(Field.of('rating').descending()) .limit(1) .select( - map({ - genre: Field.of('genre'), - rating: Field.of('rating').multiply(10) - }).as('metadata') + array([1, 2, Field.of('genre'), multiply('rating', 10)]).as( + 'metadata' + ) ) .execute(); - expect(result.length).to.equal(1); expectResults(result, { - metadata: { - genre: 'Fantasy', - rating: 47 - } + metadata: [1, 2, 'Fantasy', 47] }); }); - it('supports mapRemove', async () => { + it('supports arrayOffset', async () => { let results = await randomCol .pipeline() .sort(Field.of('rating').descending()) - .limit(1) - .select(mapRemove('awards', 'hugo').as('awards')) + .limit(3) + .select(arrayOffset('tags', 0).as('firstTag')) .execute(); - expectResults(results, { - awards: { nebula: false } - }); + const expectedResults = [ + { + firstTag: 'adventure' + }, + { + firstTag: 'politics' + }, + { + firstTag: 'classic' + } + ]; + expectResults(results, ...expectedResults); + results = await randomCol .pipeline() .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('awards').mapRemove('hugo').as('awards')) + .limit(3) + .select(Field.of('tags').arrayOffset(0).as('firstTag')) .execute(); - expectResults(results, { - awards: { nebula: false } - }); + expectResults(results, ...expectedResults); }); + }); - it('supports mapMerge', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(mapMerge('awards', { fakeAward: true }).as('awards')) - .execute(); - expectResults(results, { - awards: { nebula: false, hugo: false, fakeAward: true } - }); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('awards').mapMerge({ fakeAward: true }).as('awards')) - .execute(); - expectResults(results, { - awards: { nebula: false, hugo: false, fakeAward: true } - }); + // TODO: current_context tests with are failing because of b/395937453 + it.skip('supports currentContext', async () => { + const results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(currentContext().as('currentContext')) + .execute(); + expectResults(results, { + currentContext: 'TODO' }); + }); - it('supports manhattanDistance', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Constant.vector([1, 1]).as('embedding')) - .addFields(manhattanDistance('embedding', [3, 3]).as('distance')) - .execute(); - expectResults(results, { - distance: 4, - embedding: vector([1, 1]) - }); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Constant.vector([1, 1]).as('embedding')) - .addFields( - Field.of('embedding').manhattanDistance([3, 3]).as('distance') - ) - .execute(); - expectResults(results, { - distance: 4, - embedding: vector([1, 1]) - }); + it('supports map', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + map({ + foo: 'bar' + }).as('metadata') + ) + .execute(); + + expect(result.length).to.equal(1); + expectResults(result, { + metadata: { + foo: 'bar' + } }); }); - describe('pagination', () => { - /** - * Adds several books to the test collection. These - * additional books support pagination test scenarios - * that would otherwise not be possible with the original - * set of books. - * @param collection - */ - async function addBooks(collection: CollectionReference): Promise { - await setDoc(doc(randomCol, 'book11'), { - title: 'Jonathan Strange & Mr Norrell', - author: 'Susanna Clarke', + it('evaluates expression in map', async () => { + const result = await firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + map({ + genre: Field.of('genre'), + rating: Field.of('rating').multiply(10) + }).as('metadata') + ) + .execute(); + + expect(result.length).to.equal(1); + expectResults(result, { + metadata: { genre: 'Fantasy', - published: 2004, - rating: 4.6, - tags: ['historical fantasy', 'magic', 'alternate history', 'england'], - awards: { hugo: false, nebula: false } - }); - await setDoc(doc(randomCol, 'book12'), { - title: 'The Master and Margarita', - author: 'Mikhail Bulgakov', - genre: 'Satire', - published: 1967, // Though written much earlier - rating: 4.6, - tags: [ - 'russian literature', - 'supernatural', - 'philosophy', - 'dark comedy' - ], - awards: {} - }); - await setDoc(doc(randomCol, 'book13'), { - title: 'A Long Way to a Small, Angry Planet', - author: 'Becky Chambers', - genre: 'Science Fiction', - published: 2014, - rating: 4.6, - tags: [ - 'space opera', - 'found family', - 'character-driven', - 'optimistic' - ], - awards: { hugo: false, nebula: false, kitschies: true } - }); - } - - it('supports pagination with filters', async () => { - await addBooks(randomCol); - const pageSize = 2; - const pipeline = randomCol - .pipeline() - .select('title', 'rating', '__name__') - .sort( - Field.of('rating').descending(), - Field.of('__name__').ascending() - ); - - let results = await pipeline.limit(pageSize).execute(); - expectResults( - results, - { title: 'The Lord of the Rings', rating: 4.7 }, - { title: 'Jonathan Strange & Mr Norrell', rating: 4.6 } - ); - - const lastDoc = results[results.length - 1]; - - results = await pipeline - .where( - orFunction( - andFunction( - Field.of('rating').eq(lastDoc.get('rating')), - Field.of('__path__').gt(lastDoc.ref?.id) - ), - Field.of('rating').lt(lastDoc.get('rating')) - ) - ) - .limit(pageSize) - .execute(); - expectResults( - results, - { title: 'Pride and Prejudice', rating: 4.5 }, - { title: 'Crime and Punishment', rating: 4.3 } - ); + rating: 47 + } }); + }); - it('supports pagination with offsets', async () => { - await addBooks(randomCol); - - const secondFilterField = '__path__'; - - const pipeline = randomCol - .pipeline() - .select('title', 'rating', secondFilterField) - .sort( - Field.of('rating').descending(), - Field.of(secondFilterField).ascending() - ); - - const pageSize = 2; - let currPage = 0; - - let results = await pipeline - .offset(currPage++ * pageSize) - .limit(pageSize) - .execute(); - - expectResults( - results, - { - title: 'The Lord of the Rings', - rating: 4.7 - }, - { title: 'Dune', rating: 4.6 } - ); - - results = await pipeline - .offset(currPage++ * pageSize) - .limit(pageSize) - .execute(); - expectResults( - results, - { - title: 'Jonathan Strange & Mr Norrell', - rating: 4.6 - }, - { title: 'The Master and Margarita', rating: 4.6 } - ); - - results = await pipeline - .offset(currPage++ * pageSize) - .limit(pageSize) - .execute(); - expectResults( - results, - { - title: 'A Long Way to a Small, Angry Planet', - rating: 4.6 - }, - { - title: 'Pride and Prejudice', - rating: 4.5 - } - ); + it('supports mapRemove', async () => { + let results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(mapRemove('awards', 'hugo').as('awards')) + .execute(); + expectResults(results, { + awards: { nebula: false } + }); + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('awards').mapRemove('hugo').as('awards')) + .execute(); + expectResults(results, { + awards: { nebula: false } }); }); - describe('modular API', () => { - it('works when creating a pipeline from a Firestore instance', async () => { - const myPipeline = pipeline(firestore) - .collection(randomCol.path) - .where(lt(Field.of('published'), 1984)) - .aggregate({ - accumulators: [avgFunction('rating').as('avgRating')], - groups: ['genre'] - }) - .where(gt('avgRating', 4.3)) - .sort(Field.of('avgRating').descending()); - - const results = await execute(myPipeline); - - expectResults( - results, - { avgRating: 4.7, genre: 'Fantasy' }, - { avgRating: 4.5, genre: 'Romance' }, - { avgRating: 4.4, genre: 'Science Fiction' } - ); + it('supports mapMerge', async () => { + let results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(mapMerge('awards', { fakeAward: true }).as('awards')) + .execute(); + expectResults(results, { + awards: { nebula: false, hugo: false, fakeAward: true } }); - - it('works when creating a pipeline from a collection', async () => { - const myPipeline = pipeline(randomCol) - .where(lt(Field.of('published'), 1984)) - .aggregate({ - accumulators: [avgFunction('rating').as('avgRating')], - groups: ['genre'] - }) - .where(gt('avgRating', 4.3)) - .sort(Field.of('avgRating').descending()); - - const results = await execute(myPipeline); - - expectResults( - results, - { avgRating: 4.7, genre: 'Fantasy' }, - { avgRating: 4.5, genre: 'Romance' }, - { avgRating: 4.4, genre: 'Science Fiction' } - ); + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('awards').mapMerge({ fakeAward: true }).as('awards')) + .execute(); + expectResults(results, { + awards: { nebula: false, hugo: false, fakeAward: true } }); }); }); - // This is the Query integration tests from the lite API (no cache support) - // with some additional test cases added for more complete coverage. - describe('Query to Pipeline', () => { - function verifyResults( - actual: Array>, - ...expected: DocumentData[] - ): void { - expect(actual.length).to.equal(expected.length); - - for (let i = 0; i < expected.length; ++i) { - expect(actual[i].data()).to.deep.equal(expected[i]); - } + describe('pagination', () => { + /** + * Adds several books to the test collection. These + * additional books support pagination test scenarios + * that would otherwise not be possible with the original + * set of books. + * @param collection + */ + async function addBooks(collection: CollectionReference): Promise { + await setDoc(doc(randomCol, 'book11'), { + title: 'Jonathan Strange & Mr Norrell', + author: 'Susanna Clarke', + genre: 'Fantasy', + published: 2004, + rating: 4.6, + tags: ['historical fantasy', 'magic', 'alternate history', 'england'], + awards: { hugo: false, nebula: false } + }); + await setDoc(doc(randomCol, 'book12'), { + title: 'The Master and Margarita', + author: 'Mikhail Bulgakov', + genre: 'Satire', + published: 1967, // Though written much earlier + rating: 4.6, + tags: [ + 'russian literature', + 'supernatural', + 'philosophy', + 'dark comedy' + ], + awards: {} + }); + await setDoc(doc(randomCol, 'book13'), { + title: 'A Long Way to a Small, Angry Planet', + author: 'Becky Chambers', + genre: 'Science Fiction', + published: 2014, + rating: 4.6, + tags: ['space opera', 'found family', 'character-driven', 'optimistic'], + awards: { hugo: false, nebula: false, kitschies: true } + }); } - it('supports default query', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { 1: { foo: 1 } }, - async collRef => { - const result = await collRef.pipeline().execute(); - verifyResults(result, { foo: 1 }); - } - ); - }); - - it('supports filtered query', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - 1: { foo: 1 }, - 2: { foo: 2 } - }, - async collRef => { - const query1 = query(collRef, where('foo', '==', 1)); - const result = await query1.pipeline().execute(); - verifyResults(result, { foo: 1 }); - } - ); - }); - - it('supports filtered query (with FieldPath)', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - 1: { foo: 1 }, - 2: { foo: 2 } - }, - async collRef => { - const query1 = query(collRef, where(new FieldPath('foo'), '==', 1)); - const result = await query1.pipeline().execute(); - verifyResults(result, { foo: 1 }); - } - ); - }); - - it('supports ordered query (with default order)', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - 1: { foo: 1 }, - 2: { foo: 2 } - }, - async collRef => { - const query1 = query(collRef, orderBy('foo')); - const result = await query1.pipeline().execute(); - verifyResults(result, { foo: 1 }, { foo: 2 }); - } - ); - }); + it('supports pagination with filters', async () => { + await addBooks(randomCol); + const pageSize = 2; + const pipeline = randomCol + .pipeline() + .select('title', 'rating', '__name__') + .sort( + Field.of('rating').descending(), + Field.of('__name__').ascending() + ); - it('supports ordered query (with asc)', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - 1: { foo: 1 }, - 2: { foo: 2 } - }, - async collRef => { - const query1 = query(collRef, orderBy('foo', 'asc')); - const result = await query1.pipeline().execute(); - verifyResults(result, { foo: 1 }, { foo: 2 }); - } + let results = await pipeline.limit(pageSize).execute(); + expectResults( + results, + { title: 'The Lord of the Rings', rating: 4.7 }, + { title: 'Jonathan Strange & Mr Norrell', rating: 4.6 } ); - }); - it('supports ordered query (with desc)', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - 1: { foo: 1 }, - 2: { foo: 2 } - }, - async collRef => { - const query1 = query(collRef, orderBy('foo', 'desc')); - const result = await query1.pipeline().execute(); - verifyResults(result, { foo: 2 }, { foo: 1 }); - } - ); - }); + const lastDoc = results[results.length - 1]; - it('supports limit query', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - 1: { foo: 1 }, - 2: { foo: 2 } - }, - async collRef => { - const query1 = query(collRef, orderBy('foo'), limit(1)); - const result = await query1.pipeline().execute(); - verifyResults(result, { foo: 1 }); - } + results = await pipeline + .where( + orFunction( + andFunction( + Field.of('rating').eq(lastDoc.get('rating')), + Field.of('__path__').gt(lastDoc.ref?.id) + ), + Field.of('rating').lt(lastDoc.get('rating')) + ) + ) + .limit(pageSize) + .execute(); + expectResults( + results, + { title: 'Pride and Prejudice', rating: 4.5 }, + { title: 'Crime and Punishment', rating: 4.3 } ); }); - it('supports limitToLast query', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - 1: { foo: 1 }, - 2: { foo: 2 }, - 3: { foo: 3 } - }, - async collRef => { - const query1 = query(collRef, orderBy('foo'), limitToLast(2)); - const result = await query1.pipeline().execute(); - verifyResults(result, { foo: 2 }, { foo: 3 }); - } - ); - }); + it('supports pagination with offsets', async () => { + await addBooks(randomCol); - it('supports startAt', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - 1: { foo: 1 }, - 2: { foo: 2 } - }, - async collRef => { - const query1 = query(collRef, orderBy('foo'), startAt(2)); - const result = await query1.pipeline().execute(); - verifyResults(result, { foo: 2 }); - } - ); - }); + const secondFilterField = '__path__'; - it('supports startAfter (with DocumentReference)', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - 1: { id: 1, foo: 1, bar: 1, baz: 1 }, - 2: { id: 2, foo: 1, bar: 1, baz: 2 }, - 3: { id: 3, foo: 1, bar: 1, baz: 2 }, - 4: { id: 4, foo: 1, bar: 2, baz: 1 }, - 5: { id: 5, foo: 1, bar: 2, baz: 2 }, - 6: { id: 6, foo: 1, bar: 2, baz: 2 }, - 7: { id: 7, foo: 2, bar: 1, baz: 1 }, - 8: { id: 8, foo: 2, bar: 1, baz: 2 }, - 9: { id: 9, foo: 2, bar: 1, baz: 2 }, - 10: { id: 10, foo: 2, bar: 2, baz: 1 }, - 11: { id: 11, foo: 2, bar: 2, baz: 2 }, - 12: { id: 12, foo: 2, bar: 2, baz: 2 } - }, - async collRef => { - let docRef = await getDoc(doc(collRef, '2')); - let query1 = query( - collRef, - orderBy('foo'), - orderBy('bar'), - orderBy('baz'), - startAfter(docRef) - ); - let result = await query1.pipeline().execute(); - verifyResults( - result, - { id: 3, foo: 1, bar: 1, baz: 2 }, - { id: 4, foo: 1, bar: 2, baz: 1 }, - { id: 5, foo: 1, bar: 2, baz: 2 }, - { id: 6, foo: 1, bar: 2, baz: 2 }, - { id: 7, foo: 2, bar: 1, baz: 1 }, - { id: 8, foo: 2, bar: 1, baz: 2 }, - { id: 9, foo: 2, bar: 1, baz: 2 }, - { id: 10, foo: 2, bar: 2, baz: 1 }, - { id: 11, foo: 2, bar: 2, baz: 2 }, - { id: 12, foo: 2, bar: 2, baz: 2 } - ); - - docRef = await getDoc(doc(collRef, '3')); - query1 = query( - collRef, - orderBy('foo'), - orderBy('bar'), - orderBy('baz'), - startAfter(docRef) - ); - result = await query1.pipeline().execute(); - verifyResults( - result, - { id: 4, foo: 1, bar: 2, baz: 1 }, - { id: 5, foo: 1, bar: 2, baz: 2 }, - { id: 6, foo: 1, bar: 2, baz: 2 }, - { id: 7, foo: 2, bar: 1, baz: 1 }, - { id: 8, foo: 2, bar: 1, baz: 2 }, - { id: 9, foo: 2, bar: 1, baz: 2 }, - { id: 10, foo: 2, bar: 2, baz: 1 }, - { id: 11, foo: 2, bar: 2, baz: 2 }, - { id: 12, foo: 2, bar: 2, baz: 2 } - ); - } - ); - }); + const pipeline = randomCol + .pipeline() + .select('title', 'rating', secondFilterField) + .sort( + Field.of('rating').descending(), + Field.of(secondFilterField).ascending() + ); - it('supports startAt (with DocumentReference)', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - 1: { id: 1, foo: 1, bar: 1, baz: 1 }, - 2: { id: 2, foo: 1, bar: 1, baz: 2 }, - 3: { id: 3, foo: 1, bar: 1, baz: 2 }, - 4: { id: 4, foo: 1, bar: 2, baz: 1 }, - 5: { id: 5, foo: 1, bar: 2, baz: 2 }, - 6: { id: 6, foo: 1, bar: 2, baz: 2 }, - 7: { id: 7, foo: 2, bar: 1, baz: 1 }, - 8: { id: 8, foo: 2, bar: 1, baz: 2 }, - 9: { id: 9, foo: 2, bar: 1, baz: 2 }, - 10: { id: 10, foo: 2, bar: 2, baz: 1 }, - 11: { id: 11, foo: 2, bar: 2, baz: 2 }, - 12: { id: 12, foo: 2, bar: 2, baz: 2 } - }, - async collRef => { - let docRef = await getDoc(doc(collRef, '2')); - let query1 = query( - collRef, - orderBy('foo'), - orderBy('bar'), - orderBy('baz'), - startAt(docRef) - ); - let result = await query1.pipeline().execute(); - verifyResults( - result, - { id: 2, foo: 1, bar: 1, baz: 2 }, - { id: 3, foo: 1, bar: 1, baz: 2 }, - { id: 4, foo: 1, bar: 2, baz: 1 }, - { id: 5, foo: 1, bar: 2, baz: 2 }, - { id: 6, foo: 1, bar: 2, baz: 2 }, - { id: 7, foo: 2, bar: 1, baz: 1 }, - { id: 8, foo: 2, bar: 1, baz: 2 }, - { id: 9, foo: 2, bar: 1, baz: 2 }, - { id: 10, foo: 2, bar: 2, baz: 1 }, - { id: 11, foo: 2, bar: 2, baz: 2 }, - { id: 12, foo: 2, bar: 2, baz: 2 } - ); - - docRef = await getDoc(doc(collRef, '3')); - query1 = query( - collRef, - orderBy('foo'), - orderBy('bar'), - orderBy('baz'), - startAt(docRef) - ); - result = await query1.pipeline().execute(); - verifyResults( - result, - { id: 3, foo: 1, bar: 1, baz: 2 }, - { id: 4, foo: 1, bar: 2, baz: 1 }, - { id: 5, foo: 1, bar: 2, baz: 2 }, - { id: 6, foo: 1, bar: 2, baz: 2 }, - { id: 7, foo: 2, bar: 1, baz: 1 }, - { id: 8, foo: 2, bar: 1, baz: 2 }, - { id: 9, foo: 2, bar: 1, baz: 2 }, - { id: 10, foo: 2, bar: 2, baz: 1 }, - { id: 11, foo: 2, bar: 2, baz: 2 }, - { id: 12, foo: 2, bar: 2, baz: 2 } - ); - } - ); - }); + const pageSize = 2; + let currPage = 0; - it('supports startAfter', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - 1: { foo: 1 }, - 2: { foo: 2 } - }, - async collRef => { - const query1 = query(collRef, orderBy('foo'), startAfter(1)); - const result = await query1.pipeline().execute(); - verifyResults(result, { foo: 2 }); - } - ); - }); + let results = await pipeline + .offset(currPage++ * pageSize) + .limit(pageSize) + .execute(); - it('supports endAt', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, + expectResults( + results, { - 1: { foo: 1 }, - 2: { foo: 2 } + title: 'The Lord of the Rings', + rating: 4.7 }, - async collRef => { - const query1 = query(collRef, orderBy('foo'), endAt(1)); - const result = await query1.pipeline().execute(); - verifyResults(result, { foo: 1 }); - } + { title: 'Dune', rating: 4.6 } ); - }); - it('supports endBefore', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, + results = await pipeline + .offset(currPage++ * pageSize) + .limit(pageSize) + .execute(); + expectResults( + results, { - 1: { foo: 1 }, - 2: { foo: 2 } + title: 'Jonathan Strange & Mr Norrell', + rating: 4.6 }, - async collRef => { - const query1 = query(collRef, orderBy('foo'), endBefore(2)); - const result = await query1.pipeline().execute(); - verifyResults(result, { foo: 1 }); - } + { title: 'The Master and Margarita', rating: 4.6 } ); - }); - it('supports pagination', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, + results = await pipeline + .offset(currPage++ * pageSize) + .limit(pageSize) + .execute(); + expectResults( + results, { - 1: { foo: 1 }, - 2: { foo: 2 } + title: 'A Long Way to a Small, Angry Planet', + rating: 4.6 }, - async collRef => { - let query1 = query(collRef, orderBy('foo'), limit(1)); - const pipeline1 = query1.pipeline(); - let result = await pipeline1.execute(); - verifyResults(result, { foo: 1 }); - - // Pass the document snapshot from the previous result - query1 = query(query1, startAfter(result[0].get('foo'))); - result = await query1.pipeline().execute(); - verifyResults(result, { foo: 2 }); - } - ); - }); - - it('supports pagination on DocumentIds', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, { - 1: { foo: 1 }, - 2: { foo: 2 } - }, - async collRef => { - let query1 = query( - collRef, - orderBy('foo'), - orderBy(documentId(), 'asc'), - limit(1) - ); - const pipeline1 = query1.pipeline(); - let result = await pipeline1.execute(); - verifyResults(result, { foo: 1 }); - - // Pass the document snapshot from the previous result - query1 = query( - query1, - startAfter(result[0].get('foo'), result[0].ref?.id) - ); - result = await query1.pipeline().execute(); - verifyResults(result, { foo: 2 }); - } - ); - }); - - it('supports collection groups', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - {}, - async collRef => { - const collectionGroupId = `${collRef.id}group`; - - const fooDoc = doc( - collRef.firestore, - `${collRef.id}/foo/${collectionGroupId}/doc1` - ); - const barDoc = doc( - collRef.firestore, - `${collRef.id}/bar/baz/boo/${collectionGroupId}/doc2` - ); - await setDoc(fooDoc, { foo: 1 }); - await setDoc(barDoc, { bar: 1 }); - - const query1 = collectionGroup(collRef.firestore, collectionGroupId); - const result = await query1.pipeline().execute(); - - verifyResults(result, { bar: 1 }, { foo: 1 }); - } - ); - }); - - it('supports query over collection path with special characters', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - {}, - async collRef => { - const docWithSpecials = doc(collRef, 'so!@#$%^&*()_+special'); - - const collectionWithSpecials = collection( - docWithSpecials, - 'so!@#$%^&*()_+special' - ); - await addDoc(collectionWithSpecials, { foo: 1 }); - await addDoc(collectionWithSpecials, { foo: 2 }); - - const result = await query( - collectionWithSpecials, - orderBy('foo', 'asc') - ) - .pipeline() - .execute(); - - verifyResults(result, { foo: 1 }, { foo: 2 }); + title: 'Pride and Prejudice', + rating: 4.5 } ); }); + }); - it('supports multiple inequality on same field', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - '01': { id: 1, foo: 1, bar: 1, baz: 1 }, - '02': { id: 2, foo: 1, bar: 1, baz: 2 }, - '03': { id: 3, foo: 1, bar: 1, baz: 2 }, - '04': { id: 4, foo: 1, bar: 2, baz: 1 }, - '05': { id: 5, foo: 1, bar: 2, baz: 2 }, - '06': { id: 6, foo: 1, bar: 2, baz: 2 }, - '07': { id: 7, foo: 2, bar: 1, baz: 1 }, - '08': { id: 8, foo: 2, bar: 1, baz: 2 }, - '09': { id: 9, foo: 2, bar: 1, baz: 2 }, - '10': { id: 10, foo: 2, bar: 2, baz: 1 }, - '11': { id: 11, foo: 2, bar: 2, baz: 2 }, - '12': { id: 12, foo: 2, bar: 2, baz: 2 } - }, - async collRef => { - const query1 = query( - collRef, - and(where('id', '>', 2), where('id', '<=', 10)) - ); - const result = await query1.pipeline().execute(); - verifyResults( - result, - { id: 3, foo: 1, bar: 1, baz: 2 }, - { id: 4, foo: 1, bar: 2, baz: 1 }, - { id: 5, foo: 1, bar: 2, baz: 2 }, - { id: 6, foo: 1, bar: 2, baz: 2 }, - { id: 7, foo: 2, bar: 1, baz: 1 }, - { id: 8, foo: 2, bar: 1, baz: 2 }, - { id: 9, foo: 2, bar: 1, baz: 2 }, - { id: 10, foo: 2, bar: 2, baz: 1 } - ); - } + describe('modular API', () => { + it('works when creating a pipeline from a Firestore instance', async () => { + const myPipeline = pipeline(firestore) + .collection(randomCol.path) + .where(lt(Field.of('published'), 1984)) + .aggregate({ + accumulators: [avgFunction('rating').as('avgRating')], + groups: ['genre'] + }) + .where(gt('avgRating', 4.3)) + .sort(Field.of('avgRating').descending()); + + const results = await execute(myPipeline); + + expectResults( + results, + { avgRating: 4.7, genre: 'Fantasy' }, + { avgRating: 4.5, genre: 'Romance' }, + { avgRating: 4.4, genre: 'Science Fiction' } ); }); - it('supports multiple inequality on different fields', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - { - '01': { id: 1, foo: 1, bar: 1, baz: 1 }, - '02': { id: 2, foo: 1, bar: 1, baz: 2 }, - '03': { id: 3, foo: 1, bar: 1, baz: 2 }, - '04': { id: 4, foo: 1, bar: 2, baz: 1 }, - '05': { id: 5, foo: 1, bar: 2, baz: 2 }, - '06': { id: 6, foo: 1, bar: 2, baz: 2 }, - '07': { id: 7, foo: 2, bar: 1, baz: 1 }, - '08': { id: 8, foo: 2, bar: 1, baz: 2 }, - '09': { id: 9, foo: 2, bar: 1, baz: 2 }, - '10': { id: 10, foo: 2, bar: 2, baz: 1 }, - '11': { id: 11, foo: 2, bar: 2, baz: 2 }, - '12': { id: 12, foo: 2, bar: 2, baz: 2 } - }, - async collRef => { - const query1 = query( - collRef, - and(where('id', '>=', 2), where('baz', '<', 2)) - ); - const result = await query1.pipeline().execute(); - verifyResults( - result, - { id: 4, foo: 1, bar: 2, baz: 1 }, - { id: 7, foo: 2, bar: 1, baz: 1 }, - { id: 10, foo: 2, bar: 2, baz: 1 } - ); - } + it('works when creating a pipeline from a collection', async () => { + const myPipeline = pipeline(randomCol) + .where(lt(Field.of('published'), 1984)) + .aggregate({ + accumulators: [avgFunction('rating').as('avgRating')], + groups: ['genre'] + }) + .where(gt('avgRating', 4.3)) + .sort(Field.of('avgRating').descending()); + + const results = await execute(myPipeline); + + expectResults( + results, + { avgRating: 4.7, genre: 'Fantasy' }, + { avgRating: 4.5, genre: 'Romance' }, + { avgRating: 4.4, genre: 'Science Fiction' } ); }); }); diff --git a/packages/firestore/test/integration/api/query_to_pipeline.test.ts b/packages/firestore/test/integration/api/query_to_pipeline.test.ts new file mode 100644 index 00000000000..c41ba70425f --- /dev/null +++ b/packages/firestore/test/integration/api/query_to_pipeline.test.ts @@ -0,0 +1,554 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, use } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; + +import { addEqualityMatcher } from '../../util/equality_matcher'; +import { + doc, + DocumentData, + PipelineResult, + setDoc, + setLogLevel, + query, + where, + FieldPath, + orderBy, + limit, + limitToLast, + startAt, + startAfter, + endAt, + endBefore, + collectionGroup, + collection, + and, + documentId, + addDoc, + getDoc +} from '../util/firebase_export'; +import { + apiDescribe, + PERSISTENCE_MODE_UNSPECIFIED, + withTestCollection +} from '../util/helpers'; + +use(chaiAsPromised); + +setLogLevel('debug'); + +// This is the Query integration tests from the lite API (no cache support) +// with some additional test cases added for more complete coverage. +apiDescribe.only('Query to Pipeline', persistence => { + addEqualityMatcher(); + + function verifyResults( + actual: Array>, + ...expected: DocumentData[] + ): void { + expect(actual.length).to.equal(expected.length); + + for (let i = 0; i < expected.length; ++i) { + expect(actual[i].data()).to.deep.equal(expected[i]); + } + } + + it('supports default query', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { 1: { foo: 1 } }, + async collRef => { + const result = await collRef.pipeline().execute(); + verifyResults(result, { foo: 1 }); + } + ); + }); + + it('supports filtered query', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, where('foo', '==', 1)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }); + } + ); + }); + + it('supports filtered query (with FieldPath)', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, where(new FieldPath('foo'), '==', 1)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }); + } + ); + }); + + it('supports ordered query (with default order)', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo')); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }, { foo: 2 }); + } + ); + }); + + it('supports ordered query (with asc)', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo', 'asc')); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }, { foo: 2 }); + } + ); + }); + + it('supports ordered query (with desc)', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo', 'desc')); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 2 }, { foo: 1 }); + } + ); + }); + + it('supports limit query', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo'), limit(1)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }); + } + ); + }); + + it('supports limitToLast query', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 }, + 3: { foo: 3 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo'), limitToLast(2)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 2 }, { foo: 3 }); + } + ); + }); + + it('supports startAt', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo'), startAt(2)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 2 }); + } + ); + }); + + it('supports startAfter (with DocumentReference)', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { id: 1, foo: 1, bar: 1, baz: 1 }, + 2: { id: 2, foo: 1, bar: 1, baz: 2 }, + 3: { id: 3, foo: 1, bar: 1, baz: 2 }, + 4: { id: 4, foo: 1, bar: 2, baz: 1 }, + 5: { id: 5, foo: 1, bar: 2, baz: 2 }, + 6: { id: 6, foo: 1, bar: 2, baz: 2 }, + 7: { id: 7, foo: 2, bar: 1, baz: 1 }, + 8: { id: 8, foo: 2, bar: 1, baz: 2 }, + 9: { id: 9, foo: 2, bar: 1, baz: 2 }, + 10: { id: 10, foo: 2, bar: 2, baz: 1 }, + 11: { id: 11, foo: 2, bar: 2, baz: 2 }, + 12: { id: 12, foo: 2, bar: 2, baz: 2 } + }, + async collRef => { + let docRef = await getDoc(doc(collRef, '2')); + let query1 = query( + collRef, + orderBy('foo'), + orderBy('bar'), + orderBy('baz'), + startAfter(docRef) + ); + let result = await query1.pipeline().execute(); + verifyResults( + result, + { id: 3, foo: 1, bar: 1, baz: 2 }, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 }, + { id: 11, foo: 2, bar: 2, baz: 2 }, + { id: 12, foo: 2, bar: 2, baz: 2 } + ); + + docRef = await getDoc(doc(collRef, '3')); + query1 = query( + collRef, + orderBy('foo'), + orderBy('bar'), + orderBy('baz'), + startAfter(docRef) + ); + result = await query1.pipeline().execute(); + verifyResults( + result, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 }, + { id: 11, foo: 2, bar: 2, baz: 2 }, + { id: 12, foo: 2, bar: 2, baz: 2 } + ); + } + ); + }); + + it('supports startAt (with DocumentReference)', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { id: 1, foo: 1, bar: 1, baz: 1 }, + 2: { id: 2, foo: 1, bar: 1, baz: 2 }, + 3: { id: 3, foo: 1, bar: 1, baz: 2 }, + 4: { id: 4, foo: 1, bar: 2, baz: 1 }, + 5: { id: 5, foo: 1, bar: 2, baz: 2 }, + 6: { id: 6, foo: 1, bar: 2, baz: 2 }, + 7: { id: 7, foo: 2, bar: 1, baz: 1 }, + 8: { id: 8, foo: 2, bar: 1, baz: 2 }, + 9: { id: 9, foo: 2, bar: 1, baz: 2 }, + 10: { id: 10, foo: 2, bar: 2, baz: 1 }, + 11: { id: 11, foo: 2, bar: 2, baz: 2 }, + 12: { id: 12, foo: 2, bar: 2, baz: 2 } + }, + async collRef => { + let docRef = await getDoc(doc(collRef, '2')); + let query1 = query( + collRef, + orderBy('foo'), + orderBy('bar'), + orderBy('baz'), + startAt(docRef) + ); + let result = await query1.pipeline().execute(); + verifyResults( + result, + { id: 2, foo: 1, bar: 1, baz: 2 }, + { id: 3, foo: 1, bar: 1, baz: 2 }, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 }, + { id: 11, foo: 2, bar: 2, baz: 2 }, + { id: 12, foo: 2, bar: 2, baz: 2 } + ); + + docRef = await getDoc(doc(collRef, '3')); + query1 = query( + collRef, + orderBy('foo'), + orderBy('bar'), + orderBy('baz'), + startAt(docRef) + ); + result = await query1.pipeline().execute(); + verifyResults( + result, + { id: 3, foo: 1, bar: 1, baz: 2 }, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 }, + { id: 11, foo: 2, bar: 2, baz: 2 }, + { id: 12, foo: 2, bar: 2, baz: 2 } + ); + } + ); + }); + + it('supports startAfter', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo'), startAfter(1)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 2 }); + } + ); + }); + + it('supports endAt', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo'), endAt(1)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }); + } + ); + }); + + it('supports endBefore', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + const query1 = query(collRef, orderBy('foo'), endBefore(2)); + const result = await query1.pipeline().execute(); + verifyResults(result, { foo: 1 }); + } + ); + }); + + it('supports pagination', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + let query1 = query(collRef, orderBy('foo'), limit(1)); + const pipeline1 = query1.pipeline(); + let result = await pipeline1.execute(); + verifyResults(result, { foo: 1 }); + + // Pass the document snapshot from the previous result + query1 = query(query1, startAfter(result[0].get('foo'))); + result = await query1.pipeline().execute(); + verifyResults(result, { foo: 2 }); + } + ); + }); + + it('supports pagination on DocumentIds', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1 }, + 2: { foo: 2 } + }, + async collRef => { + let query1 = query( + collRef, + orderBy('foo'), + orderBy(documentId(), 'asc'), + limit(1) + ); + const pipeline1 = query1.pipeline(); + let result = await pipeline1.execute(); + verifyResults(result, { foo: 1 }); + + // Pass the document snapshot from the previous result + query1 = query( + query1, + startAfter(result[0].get('foo'), result[0].ref?.id) + ); + result = await query1.pipeline().execute(); + verifyResults(result, { foo: 2 }); + } + ); + }); + + it('supports collection groups', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + {}, + async collRef => { + const collectionGroupId = `${collRef.id}group`; + + const fooDoc = doc( + collRef.firestore, + `${collRef.id}/foo/${collectionGroupId}/doc1` + ); + const barDoc = doc( + collRef.firestore, + `${collRef.id}/bar/baz/boo/${collectionGroupId}/doc2` + ); + await setDoc(fooDoc, { foo: 1 }); + await setDoc(barDoc, { bar: 1 }); + + const query1 = collectionGroup(collRef.firestore, collectionGroupId); + const result = await query1.pipeline().execute(); + + verifyResults(result, { bar: 1 }, { foo: 1 }); + } + ); + }); + + it('supports query over collection path with special characters', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + {}, + async collRef => { + const docWithSpecials = doc(collRef, 'so!@#$%^&*()_+special'); + + const collectionWithSpecials = collection( + docWithSpecials, + 'so!@#$%^&*()_+special' + ); + await addDoc(collectionWithSpecials, { foo: 1 }); + await addDoc(collectionWithSpecials, { foo: 2 }); + + const result = await query( + collectionWithSpecials, + orderBy('foo', 'asc') + ) + .pipeline() + .execute(); + + verifyResults(result, { foo: 1 }, { foo: 2 }); + } + ); + }); + + it('supports multiple inequality on same field', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + '01': { id: 1, foo: 1, bar: 1, baz: 1 }, + '02': { id: 2, foo: 1, bar: 1, baz: 2 }, + '03': { id: 3, foo: 1, bar: 1, baz: 2 }, + '04': { id: 4, foo: 1, bar: 2, baz: 1 }, + '05': { id: 5, foo: 1, bar: 2, baz: 2 }, + '06': { id: 6, foo: 1, bar: 2, baz: 2 }, + '07': { id: 7, foo: 2, bar: 1, baz: 1 }, + '08': { id: 8, foo: 2, bar: 1, baz: 2 }, + '09': { id: 9, foo: 2, bar: 1, baz: 2 }, + '10': { id: 10, foo: 2, bar: 2, baz: 1 }, + '11': { id: 11, foo: 2, bar: 2, baz: 2 }, + '12': { id: 12, foo: 2, bar: 2, baz: 2 } + }, + async collRef => { + const query1 = query( + collRef, + and(where('id', '>', 2), where('id', '<=', 10)) + ); + const result = await query1.pipeline().execute(); + verifyResults( + result, + { id: 3, foo: 1, bar: 1, baz: 2 }, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 } + ); + } + ); + }); + + it('supports multiple inequality on different fields', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + '01': { id: 1, foo: 1, bar: 1, baz: 1 }, + '02': { id: 2, foo: 1, bar: 1, baz: 2 }, + '03': { id: 3, foo: 1, bar: 1, baz: 2 }, + '04': { id: 4, foo: 1, bar: 2, baz: 1 }, + '05': { id: 5, foo: 1, bar: 2, baz: 2 }, + '06': { id: 6, foo: 1, bar: 2, baz: 2 }, + '07': { id: 7, foo: 2, bar: 1, baz: 1 }, + '08': { id: 8, foo: 2, bar: 1, baz: 2 }, + '09': { id: 9, foo: 2, bar: 1, baz: 2 }, + '10': { id: 10, foo: 2, bar: 2, baz: 1 }, + '11': { id: 11, foo: 2, bar: 2, baz: 2 }, + '12': { id: 12, foo: 2, bar: 2, baz: 2 } + }, + async collRef => { + const query1 = query( + collRef, + and(where('id', '>=', 2), where('baz', '<', 2)) + ); + const result = await query1.pipeline().execute(); + verifyResults( + result, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 10, foo: 2, bar: 2, baz: 1 } + ); + } + ); + }); +}); From 33f5811039a95b8ee212adc652c2a46eec31eaaf Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 20 Feb 2025 18:15:55 -0700 Subject: [PATCH 27/75] Implementing new stages Sample, Union, Unnest, Replace --- packages/firestore/src/api/pipeline.ts | 3 +- .../firestore/src/lite-api/expressions.ts | 27 +- packages/firestore/src/lite-api/pipeline.ts | 501 +++++++++++------- packages/firestore/src/lite-api/stage.ts | 103 ++++ packages/firestore/src/remote/datastore.ts | 10 +- packages/firestore/src/remote/serializer.ts | 7 +- .../test/integration/api/pipeline.test.ts | 211 +++++++- 7 files changed, 644 insertions(+), 218 deletions(-) diff --git a/packages/firestore/src/api/pipeline.ts b/packages/firestore/src/api/pipeline.ts index aaddf00274b..500dd1afba6 100644 --- a/packages/firestore/src/api/pipeline.ts +++ b/packages/firestore/src/api/pipeline.ts @@ -41,8 +41,7 @@ export class Pipeline extends LitePipeline { db: Firestore, userDataReader: UserDataReader, userDataWriter: AbstractUserDataWriter, - stages: Stage[], - converter: unknown = {} + stages: Stage[] ): Pipeline { return new Pipeline(db, userDataReader, userDataWriter, stages); } diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 42e4ec9f8bf..cf22f7ec3cf 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -2105,6 +2105,7 @@ export abstract class Expr implements ProtoSerializable, UserData { */ export abstract class Selectable extends Expr { selectable: true = true; + abstract readonly alias: string; } /** @@ -2245,25 +2246,17 @@ export class Field extends Selectable { */ static of(name: string): Field; static of(path: FieldPath): Field; - static of( - pipelineOrName: Pipeline | string | FieldPath, - name?: string - ): Field { - if (typeof pipelineOrName === 'string') { - if (DOCUMENT_KEY_NAME === pipelineOrName) { + static of(nameOrPath: string | FieldPath): Field { + if (typeof nameOrPath === 'string') { + if (DOCUMENT_KEY_NAME === nameOrPath) { return new Field(documentId()._internalPath); } - return new Field(fieldPathFromArgument('of', pipelineOrName)); - } else if (pipelineOrName instanceof FieldPath) { - if (documentId().isEqual(pipelineOrName)) { + return new Field(fieldPathFromArgument('of', nameOrPath)); + } else { + if (documentId().isEqual(nameOrPath)) { return new Field(documentId()._internalPath); } - return new Field(pipelineOrName._internalPath); - } else { - return new Field( - fieldPathFromArgument('of', name!), - pipelineOrName as Pipeline - ); + return new Field(nameOrPath._internalPath); } } @@ -2271,6 +2264,10 @@ export class Field extends Selectable { return this.fieldPath.canonicalString(); } + get alias(): string { + return this.fieldPath.canonicalString(); + } + /** * @private * @internal diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index c2fc83c0d19..b494ae220f8 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -19,16 +19,11 @@ import { ObjectValue } from '../model/object_value'; import { - ExecutePipelineRequest, - StructuredPipeline, + Pipeline as ProtoPipeline, Stage as ProtoStage } from '../protos/firestore_proto_api'; import { invokeExecutePipeline } from '../remote/datastore'; -import { - getEncodedDatabaseId, - JsonProtoSerializer, - ProtoSerializable -} from '../remote/serializer'; +import { JsonProtoSerializer, ProtoSerializable } from '../remote/serializer'; import { isPlainObject } from '../util/input_validation'; import { getDatastore } from './components'; @@ -56,8 +51,13 @@ import { GenericStage, Limit, Offset, + RemoveFields, + Replace, Select, Sort, + Sample, + Union, + Unnest, Stage, Where } from './stage'; @@ -122,7 +122,7 @@ function isReadableUserData(value: any): value is ReadableUserData { /** * Base-class implementation */ -export class Pipeline implements ProtoSerializable { +export class Pipeline implements ProtoSerializable { /** * @internal * @private @@ -173,18 +173,36 @@ export class Pipeline implements ProtoSerializable { * @return A new Pipeline object with this stage appended to the stage list. */ addFields(...fields: Selectable[]): Pipeline { - const copy = this.stages.map(s => s); - copy.push( + return this._addStage( new AddFields( this.readUserData('addFields', this.selectablesToMap(fields)) ) ); - return this.newPipeline( - this._db, - this.userDataReader, - this._userDataWriter, - copy + } + + /** + * Remove fields from outputs of previous stages. + * + * Example: + * + * ```typescript + * firestore.pipeline().collection('books') + * // removes field 'rating' and 'cost' from the previous stage outputs. + * .removeFields( + * Field.of('rating'), + * 'cost' + * ); + * ``` + * + * @param fields The fields to remove. + * @return A new Pipeline object with this stage appended to the stage list. + */ + removeFields(...fields: Array): Pipeline { + const fieldExpressions = fields.map(f => + typeof f === 'string' ? Field.of(f) : (f as Field) ); + this.readUserData('removeFields', fieldExpressions); + return this._addStage(new RemoveFields(fieldExpressions)); } /** @@ -219,77 +237,9 @@ export class Pipeline implements ProtoSerializable { * @return A new Pipeline object with this stage appended to the stage list. */ select(...selections: Array): Pipeline { - const copy = this.stages.map(s => s); let projections: Map = this.selectablesToMap(selections); projections = this.readUserData('select', projections); - copy.push(new Select(projections)); - return this.newPipeline( - this._db, - this.userDataReader, - this._userDataWriter, - copy - ); - } - - private selectablesToMap( - selectables: Array - ): Map { - const result = new Map(); - for (const selectable of selectables) { - if (typeof selectable === 'string') { - result.set(selectable as string, Field.of(selectable)); - } else if (selectable instanceof Field) { - result.set((selectable as Field).fieldName(), selectable); - } else if (selectable instanceof ExprWithAlias) { - const expr = selectable as ExprWithAlias; - result.set(expr.alias, expr.expr); - } - } - return result; - } - - /** - * Reads user data for each expression in the expressionMap. - * @param name Name of the calling function. Used for error messages when invalid user data is encountered. - * @param expressionMap - * @return the expressionMap argument. - * @private - */ - private readUserData< - T extends - | Map - | ReadableUserData[] - | ReadableUserData - >(name: string, expressionMap: T): T { - if (isReadableUserData(expressionMap)) { - expressionMap._readUserData(this.userDataReader); - } else if (Array.isArray(expressionMap)) { - expressionMap.forEach(readableData => - readableData._readUserData(this.userDataReader) - ); - } else { - expressionMap.forEach(expr => expr._readUserData(this.userDataReader)); - } - return expressionMap; - } - - /** - * @internal - * @private - * @param db - * @param userDataReader - * @param userDataWriter - * @param stages - * @protected - */ - protected newPipeline( - db: Firestore, - userDataReader: UserDataReader, - userDataWriter: AbstractUserDataWriter, - stages: Stage[], - converter: unknown = {} - ): Pipeline { - return new Pipeline(db, userDataReader, userDataWriter, stages); + return this._addStage(new Select(projections)); } /** @@ -324,15 +274,8 @@ export class Pipeline implements ProtoSerializable { * @return A new Pipeline object with this stage appended to the stage list. */ where(condition: FilterCondition): Pipeline { - const copy = this.stages.map(s => s); this.readUserData('where', condition); - copy.push(new Where(condition)); - return this.newPipeline( - this._db, - this.userDataReader, - this._userDataWriter, - copy - ); + return this._addStage(new Where(condition)); } /** @@ -356,14 +299,7 @@ export class Pipeline implements ProtoSerializable { * @return A new Pipeline object with this stage appended to the stage list. */ offset(offset: number): Pipeline { - const copy = this.stages.map(s => s); - copy.push(new Offset(offset)); - return this.newPipeline( - this._db, - this.userDataReader, - this._userDataWriter, - copy - ); + return this._addStage(new Offset(offset)); } /** @@ -392,25 +328,21 @@ export class Pipeline implements ProtoSerializable { * @return A new Pipeline object with this stage appended to the stage list. */ limit(limit: number): Pipeline { - const copy = this.stages.map(s => s); - copy.push(new Limit(limit)); - return this.newPipeline( - this._db, - this.userDataReader, - this._userDataWriter, - copy - ); + return this._addStage(new Limit(limit)); } + /** + * Internal use only. + * Helper to add a limit stage when converting from a Query. + * + * @internal + * @private + * + * @param limit + * @param convertedFromLimitTolast + */ _limit(limit: number, convertedFromLimitTolast: boolean): Pipeline { - const copy = this.stages.map(s => s); - copy.push(new Limit(limit, convertedFromLimitTolast)); - return this.newPipeline( - this._db, - this.userDataReader, - this._userDataWriter, - copy - ); + return this._addStage(new Limit(limit, convertedFromLimitTolast)); } /** @@ -437,23 +369,16 @@ export class Pipeline implements ProtoSerializable { * .select("authorName"); * ``` * - * @param selectables The {@link Selectable} expressions to consider when determining distinct + * @param groups The {@link Selectable} expressions to consider when determining distinct * value combinations or {@code string}s representing field names. * @return A new {@code Pipeline} object with this stage appended to the stage list. */ distinct(...groups: Array): Pipeline { - const copy = this.stages.map(s => s); - copy.push( + return this._addStage( new Distinct( this.readUserData('distinct', this.selectablesToMap(groups || [])) ) ); - return this.newPipeline( - this._db, - this.userDataReader, - this._userDataWriter, - copy - ); } /** @@ -507,9 +432,10 @@ export class Pipeline implements ProtoSerializable { * }); * ``` * - * @param aggregate An {@link Aggregate} object that specifies the grouping fields (if any) and - * the aggregation operations to perform. - * @return A new {@code Pipeline} object with this stage appended to the stage list. + * @param options An object that specifies the accumulators + * and optional grouping fields to perform. + * @return A new {@code Pipeline} object with this stage appended to the stage + * list. */ aggregate(options: { accumulators: AccumulatorTarget[]; @@ -524,9 +450,8 @@ export class Pipeline implements ProtoSerializable { }, ...rest: AccumulatorTarget[] ): Pipeline { - const copy = this.stages.map(s => s); if ('accumulators' in optionsOrTarget) { - copy.push( + return this._addStage( new Aggregate( new Map( optionsOrTarget.accumulators.map((target: AccumulatorTarget) => [ @@ -544,7 +469,7 @@ export class Pipeline implements ProtoSerializable { ) ); } else { - copy.push( + return this._addStage( new Aggregate( new Map( [optionsOrTarget, ...rest].map(target => [ @@ -559,23 +484,16 @@ export class Pipeline implements ProtoSerializable { ) ); } - return this.newPipeline( - this._db, - this.userDataReader, - this._userDataWriter, - copy - ); } findNearest(options: FindNearestOptions): Pipeline { - const copy = this.stages.map(s => s); const parseContext = this.userDataReader.createContext( UserDataSource.Argument, 'findNearest' ); const value = parseVectorValue(options.vectorValue, parseContext); const vectorObjectValue = new ObjectValue(value); - copy.push( + return this._addStage( new FindNearest( options.field, vectorObjectValue, @@ -584,12 +502,6 @@ export class Pipeline implements ProtoSerializable { options.distanceField ) ); - return this.newPipeline( - this._db, - this.userDataReader, - this._userDataWriter, - copy - ); } /** @@ -613,7 +525,7 @@ export class Pipeline implements ProtoSerializable { * ); * ``` * - * @param orders One or more {@link Ordering} instances specifying the sorting criteria. + * @param orderings One or more {@link Ordering} instances specifying the sorting criteria. * @return A new {@code Pipeline} object with this stage appended to the stage list. */ sort(...orderings: Ordering[]): Pipeline; @@ -625,10 +537,9 @@ export class Pipeline implements ProtoSerializable { }, ...rest: Ordering[] ): Pipeline { - const copy = this.stages.map(s => s); // Option object if ('orderings' in optionsOrOrderings) { - copy.push( + return this._addStage( new Sort( this.readUserData( 'sort', @@ -638,17 +549,169 @@ export class Pipeline implements ProtoSerializable { ); } else { // Ordering object - copy.push( + return this._addStage( new Sort(this.readUserData('sort', [optionsOrOrderings, ...rest])) ); } + } - return this.newPipeline( - this._db, - this.userDataReader, - this._userDataWriter, - copy - ); + /** + * Fully overwrites all fields in a document with those coming from a nested map. + * + *

This stage allows you to emit a map value as a document. Each key of the map becomes a field + * on the document that contains the corresponding value. + * + *

Example: + * + * ```typescript + * // Input. + * // { + * // 'name': 'John Doe Jr.', + * // 'parents': { + * // 'father': 'John Doe Sr.', + * // 'mother': 'Jane Doe' + * // } + * // } + * + * // Emit parents as document. + * firestore.pipeline().collection('people').replaceWith(Field.of('parents')); + * + * // Output + * // { + * // 'father': 'John Doe Sr.', + * // 'mother': 'Jane Doe' + * // } + * ``` + * + * @param field The {@link Field} field containing the nested map. + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + replaceWith(field: Field | string): Pipeline { + const fieldExpr = typeof field === 'string' ? Field.of(field) : field; + return this._addStage(new Replace(fieldExpr, 'full_replace')); + } + + /** + * Performs a pseudo-random sampling of the documents from the previous stage. + * + *

This stage will filter documents pseudo-randomly. The parameter specifies how number of + * documents to be returned. + * + *

Examples: + * + * ```typescript + * // Sample 25 books, if available. + * firestore.pipeline().collection('books') + * .sample(25); + * ``` + * + * @param documents The number of documents to sample.. + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + sample(documents: number): Pipeline; + + /** + * Performs a pseudo-random sampling of the documents from the previous stage. + * + *

This stage will filter documents pseudo-randomly. The 'options' parameter specifies how + * sampling will be performed. See {@code SampleOptions} for more information. + * + *

Examples: + * + * // Sample 10 books, if available. + * firestore.pipeline().collection("books") + * .sample({ documents: 10 }); + * + * // Sample 50% of books. + * firestore.pipeline().collection("books") + * .sample({ percentage: 0.5 }); + * } + * + * + * @param options The {@code SampleOptions} specifies how sampling is performed. + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + sample(options: { percentage: number } | { documents: number }): Pipeline; + sample( + documentsOrOptions: number | { percentage: number } | { documents: number } + ): Pipeline { + if (typeof documentsOrOptions === 'number') { + return this._addStage(new Sample(documentsOrOptions, 'documents')); + } else if ('percentage' in documentsOrOptions) { + return this._addStage( + new Sample(documentsOrOptions.percentage, 'percent') + ); + } else { + return this._addStage( + new Sample(documentsOrOptions.documents, 'documents') + ); + } + } + + /** + * Performs union of all documents from two pipelines, including duplicates. + * + *

This stage will pass through documents from previous stage, and also pass through documents + * from previous stage of the `other` {@code Pipeline} given in parameter. The order of documents + * emitted from this stage is undefined. + * + *

Example: + * + * ```typescript + * // Emit documents from books collection and magazines collection. + * firestore.pipeline().collection('books') + * .union(firestore.pipeline().collection('magazines')); + * ``` + * + * @param other The other {@code Pipeline} that is part of union. + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + union(other: Pipeline): Pipeline { + return this._addStage(new Union(other)); + } + + /** + * Produces a document for each element in array found in previous stage document. + * + * For each previous stage document, this stage will emit zero or more augmented documents. The + * input array found in the previous stage document field specified by the `selectable` parameter, + * will emit an augmented document for each input array element. The input array element will + * augment the previous stage document by setting the `alias` field with the array element value. + * + * When `selectable` evaluates to a non-array value (ex: number, null, absent), then the stage becomes a no-op for + * the current input document, returning it as is with the `alias` field absent. + * + * No documents are emitted when `selectable` evaluates to an empty array. + * + * Example: + * + * ```typescript + * // Input: + * // { "title": "The Hitchhiker's Guide to the Galaxy", "tags": [ "comedy", "space", "adventure" ], ... } + * + * // Emit a book document for each tag of the book. + * firestore.pipeline().collection("books") + * .unnest(Field.of("tags").as('tag'), 'tagIndex'); + * + * // Output: + * // { "title": "The Hitchhiker's Guide to the Galaxy", "tag": "comedy", "tagIndex": 0, ... } + * // { "title": "The Hitchhiker's Guide to the Galaxy", "tag": "space", "tagIndex": 1, ... } + * // { "title": "The Hitchhiker's Guide to the Galaxy", "tag": "adventure", "tagIndex": 2, ... } + * ``` + * + * @param selectable A selectable expression defining the field to unnest and the alias to use for each unnested element in the output documents. + * @param indexField An optional string value specifying the field path to write the offset (starting at zero) into the array the unnested element is from + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + unnest(selectable: Selectable, indexField?: string): Pipeline { + const field = + selectable instanceof ExprWithAlias ? selectable.expr : selectable; + this.readUserData('unnest', field); + + const alias = Field.of(selectable.alias); + this.readUserData('unnest', alias); + + return this._addStage(new Unnest(field, alias, indexField)); } /** @@ -672,8 +735,6 @@ export class Pipeline implements ProtoSerializable { * @return A new {@code Pipeline} object with this stage appended to the stage list. */ genericStage(name: string, params: any[]): Pipeline { - const copy = this.stages.map(s => s); - // Convert input values to Expressions. // We treat objects as mapValues and arrays as arrayValues, // this is unlike the default conversion for objects and arrays @@ -693,13 +754,7 @@ export class Pipeline implements ProtoSerializable { param._readUserData(this.userDataReader); } }); - copy.push(new GenericStage(name, expressionParams)); - return this.newPipeline( - this._db, - this.userDataReader, - this._userDataWriter, - copy - ); + return this._addStage(new GenericStage(name, expressionParams)); } /** @@ -736,25 +791,25 @@ export class Pipeline implements ProtoSerializable { execute(): Promise { const datastore = getDatastore(this._db); return invokeExecutePipeline(datastore, this).then(result => { - const docs = result - // Currently ignore any response from ExecutePipeline that does - // not contain any document data in the `fields` property. - .filter(element => !!element.fields) - .map( - element => - new PipelineResult( - this._userDataWriter, - element.key?.path - ? new DocumentReference(this._db, null, element.key) - : undefined, - element.fields, - element.executionTime?.toTimestamp(), - element.createTime?.toTimestamp(), - element.updateTime?.toTimestamp() - ) - ); - - return docs; + return ( + result + // Currently ignore any response from ExecutePipeline that does + // not contain any document data in the `fields` property. + .filter(element => !!element.fields) + .map( + element => + new PipelineResult( + this._userDataWriter, + element.key?.path + ? new DocumentReference(this._db, null, element.key) + : undefined, + element.fields, + element.executionTime?.toTimestamp(), + element.createTime?.toTimestamp(), + element.updateTime?.toTimestamp() + ) + ) + ); }); } @@ -762,14 +817,82 @@ export class Pipeline implements ProtoSerializable { * @internal * @private */ - _toProto(jsonProtoSerializer: JsonProtoSerializer): ExecutePipelineRequest { + _toProto(jsonProtoSerializer: JsonProtoSerializer): ProtoPipeline { const stages: ProtoStage[] = this.stages.map(stage => stage._toProto(jsonProtoSerializer) ); - const structuredPipeline: StructuredPipeline = { pipeline: { stages } }; - return { - database: getEncodedDatabaseId(jsonProtoSerializer), - structuredPipeline - }; + return { stages }; + } + + private _addStage(stage: Stage): Pipeline { + const copy = this.stages.map(s => s); + copy.push(stage); + return this.newPipeline( + this._db, + this.userDataReader, + this._userDataWriter, + copy + ); + } + + private selectablesToMap( + selectables: Array + ): Map { + const result = new Map(); + for (const selectable of selectables) { + if (typeof selectable === 'string') { + result.set(selectable as string, Field.of(selectable)); + } else if (selectable instanceof Field) { + result.set((selectable as Field).fieldName(), selectable); + } else if (selectable instanceof ExprWithAlias) { + const expr = selectable as ExprWithAlias; + result.set(expr.alias, expr.expr); + } + } + return result; + } + + /** + * Reads user data for each expression in the expressionMap. + * @param name Name of the calling function. Used for error messages when invalid user data is encountered. + * @param expressionMap + * @return the expressionMap argument. + * @private + */ + private readUserData< + T extends + | Map + | ReadableUserData[] + | ReadableUserData + >(name: string, expressionMap: T): T { + if (isReadableUserData(expressionMap)) { + expressionMap._readUserData(this.userDataReader); + } else if (Array.isArray(expressionMap)) { + expressionMap.forEach(readableData => + readableData._readUserData(this.userDataReader) + ); + } else { + expressionMap.forEach(expr => expr._readUserData(this.userDataReader)); + } + return expressionMap; + } + + /** + * @internal + * @private + * @param db + * @param userDataReader + * @param userDataWriter + * @param stages + * @protected + */ + protected newPipeline( + db: Firestore, + userDataReader: UserDataReader, + userDataWriter: AbstractUserDataWriter, + stages: Stage[], + converter: unknown = {} + ): Pipeline { + return new Pipeline(db, userDataReader, userDataWriter, stages); } } diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index a30148ebc78..71d5cd95763 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -25,6 +25,7 @@ import { JsonProtoSerializer, ProtoSerializable, toMapValue, + toPipelineValue, toStringValue } from '../remote/serializer'; import { hardAssert } from '../util/assert'; @@ -36,6 +37,7 @@ import { FilterCondition, Ordering } from './expressions'; +import { Pipeline } from './pipeline'; import { DocumentReference } from './reference'; import { VectorValue } from './vector_value'; @@ -66,6 +68,26 @@ export class AddFields implements Stage { } } +/** + * @beta + */ +export class RemoveFields implements Stage { + name = 'remove_fields'; + + constructor(private fields: Field[]) {} + + /** + * @internal + * @private + */ + _toProto(serializer: JsonProtoSerializer): ProtoStage { + return { + name: this.name, + args: this.fields.map(f => f._toProto(serializer)) + }; + } +} + /** * @beta */ @@ -380,6 +402,87 @@ export class Sort implements Stage { } } +/** + * @beta + */ +export class Sample implements Stage { + name = 'sample'; + + constructor(private limit: number, private mode: string) {} + + _toProto(serializer: JsonProtoSerializer): ProtoStage { + return { + name: this.name, + args: [toNumber(serializer, this.limit)!, toStringValue(this.mode)!] + }; + } +} + +/** + * @beta + */ +export class Union implements Stage { + name = 'union'; + + constructor(private _other: Pipeline) {} + + _toProto(serializer: JsonProtoSerializer): ProtoStage { + return { + name: this.name, + args: [toPipelineValue(this._other._toProto(serializer))] + }; + } +} + +/** + * @beta + */ +export class Unnest implements Stage { + name = 'unnest'; + constructor( + private expr: Expr, + private alias: Field, + private indexField?: string + ) {} + + _toProto(serializer: JsonProtoSerializer): ProtoStage { + const stageProto: ProtoStage = { + name: this.name, + args: [this.expr._toProto(serializer), this.alias._toProto(serializer)] + }; + + if (this.indexField) { + stageProto.options = { + indexField: toStringValue(this.indexField) + }; + } + + return stageProto; + } +} + +/** + * @beta + */ +export class Replace implements Stage { + name = 'replace'; + + constructor( + private field: Field, + private mode: + | 'full_replace' + | 'merge_prefer_nest' + | 'merge_prefer_parent' = 'full_replace' + ) {} + + _toProto(serializer: JsonProtoSerializer): ProtoStage { + return { + name: this.name, + args: [this.field._toProto(serializer), toStringValue(this.mode)] + }; + } +} + /** * @beta */ diff --git a/packages/firestore/src/remote/datastore.ts b/packages/firestore/src/remote/datastore.ts index 00c1e7fca9e..32666feeea1 100644 --- a/packages/firestore/src/remote/datastore.ts +++ b/packages/firestore/src/remote/datastore.ts @@ -59,7 +59,8 @@ import { toQueryTarget, toResourcePath, toRunAggregationQueryRequest, - fromPipelineResponse + fromPipelineResponse, + getEncodedDatabaseId } from './serializer'; /** @@ -244,7 +245,12 @@ export async function invokeExecutePipeline( pipeline: Pipeline ): Promise { const datastoreImpl = debugCast(datastore, DatastoreImpl); - const executePipelineRequest = pipeline._toProto(datastoreImpl.serializer); + const executePipelineRequest: ProtoExecutePipelineRequest = { + database: getEncodedDatabaseId(datastoreImpl.serializer), + structuredPipeline: { + pipeline: pipeline._toProto(datastoreImpl.serializer) + } + }; const response = await datastoreImpl.invokeStreamingRPC< ProtoExecutePipelineRequest, diff --git a/packages/firestore/src/remote/serializer.ts b/packages/firestore/src/remote/serializer.ts index 4759571b4a5..617816615aa 100644 --- a/packages/firestore/src/remote/serializer.ts +++ b/packages/firestore/src/remote/serializer.ts @@ -94,7 +94,8 @@ import { WriteResult as ProtoWriteResult, Value as ProtoValue, MapValue as ProtoMapValue, - ExecutePipelineResponse as ProtoExecutePipelineResponse + ExecutePipelineResponse as ProtoExecutePipelineResponse, + Pipeline } from '../protos/firestore_proto_api'; import { debugAssert, fail, hardAssert } from '../util/assert'; import { ByteString } from '../util/byte_string'; @@ -1466,6 +1467,10 @@ export function toStringValue(value: string): ProtoValue { return { stringValue: value }; } +export function toPipelineValue(value: Pipeline): ProtoValue { + return { pipelineValue: value }; +} + export function dateToTimestampValue( serializer: JsonProtoSerializer, value: Date diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index b9130323ac7..714fac83be4 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -18,19 +18,20 @@ import { expect, use } from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import { Bytes, getFirestore, terminate, vector } from '../../../src/api'; +import { addEqualityMatcher } from '../../util/equality_matcher'; +import { Deferred } from '../../util/promise'; import { + GeoPoint, + Timestamp, array, descending, genericFunction, isNan, - map -} from '../../../src/lite-api/expressions'; -import { GeoPoint } from '../../../src/lite-api/geo_point'; -import { Timestamp } from '../../../src/lite-api/timestamp'; -import { addEqualityMatcher } from '../../util/equality_matcher'; -import { Deferred } from '../../util/promise'; -import { + map, + Bytes, + getFirestore, + terminate, + vector, pipeline, execute, _internalPipelineToExecutePipelineRequestProto, @@ -91,7 +92,8 @@ import { mapMerge, documentIdFunction, substr, - manhattanDistance + manhattanDistance, + documentId } from '../util/firebase_export'; import { apiDescribe, withTestCollection } from '../util/helpers'; @@ -905,6 +907,197 @@ apiDescribe.only('Pipelines', persistence => { ); }); }); + + describe('replace stage', () => { + it('run pipleine with replace', async () => { + const results = await randomCol + .pipeline() + .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) + .replaceWith('awards') + .execute(); + expectResults(results, { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }); + }); + }); + + describe('sample stage', () => { + it('run pipeline with sample limit of 3', async () => { + const results = await randomCol.pipeline().sample(3).execute(); + expect(results.length).to.equal(3); + }); + + it('run pipeline with sample limit of {documents: 3}', async () => { + const results = await randomCol + .pipeline() + .sample({ documents: 3 }) + .execute(); + expect(results.length).to.equal(3); + }); + + it('run pipeline with sample limit of {percentage: 0.6}', async () => { + let avgSize = 0; + const numIterations = 20; + for (let i = 0; i < numIterations; i++) { + const results = await randomCol + .pipeline() + .sample({ percentage: 0.6 }) + .execute(); + + avgSize += results.length; + } + avgSize /= numIterations; + expect(avgSize).to.be.closeTo(6, 1); + }); + }); + + describe('union stage', () => { + it('run pipeline with union', async () => { + const results = await randomCol + .pipeline() + .union(randomCol.pipeline()) + .sort(Field.of(documentId()).ascending()) + .execute(); + expectResults( + results, + 'book1', + 'book1', + 'book10', + 'book10', + 'book2', + 'book2', + 'book3', + 'book3', + 'book4', + 'book4', + 'book5', + 'book5', + 'book6', + 'book6', + 'book7', + 'book7', + 'book8', + 'book8', + 'book9', + 'book9' + ); + }); + }); + + describe('unnest stage', () => { + it('run pipeline with unnest', async () => { + const results = await randomCol + .pipeline() + .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) + .unnest(Field.of('tags').as('tag')) + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + tag: 'comedy', + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + }, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + tag: 'space', + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + }, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + tag: 'adventure', + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + } + ); + }); + it('unnest an expr', async () => { + const results = await randomCol + .pipeline() + .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) + .unnest(array([1, 2, 3]).as('copy')) + .execute(); + expectResults( + results, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + copy: 1, + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + }, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + copy: 2, + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + }, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + copy: 3, + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + } + ); + }); + }); }); describe('function expressions', () => { From ac42e1f89d57fbcfa6a764ebb02c133bef85ff67 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 21 Feb 2025 11:21:12 -0700 Subject: [PATCH 28/75] Rename FilterCondition to BooleanExpr --- .../firestore/lite/pipelines/pipelines.ts | 2 +- packages/firestore/src/api_pipelines.ts | 2 +- packages/firestore/src/core/pipeline-util.ts | 12 +-- .../firestore/src/lite-api/expressions.ts | 84 +++++++++---------- packages/firestore/src/lite-api/pipeline.ts | 10 +-- packages/firestore/src/lite-api/stage.ts | 4 +- 6 files changed, 57 insertions(+), 57 deletions(-) diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index ee770a3855c..4a27618da48 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -204,6 +204,6 @@ export { ExprType, AccumulatorTarget, Selectable, - FilterCondition, + BooleanExpr, Accumulator } from '../../src/lite-api/expressions'; diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index bbf39f35f22..e8fb29ae82b 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -233,6 +233,6 @@ export type { ExprType, AccumulatorTarget, Selectable, - FilterCondition, + BooleanExpr, Accumulator } from './lite-api/expressions'; diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index 8f584db30bb..278e9f387e4 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -19,7 +19,7 @@ import { Firestore } from '../api/database'; import { Constant, Field, - FilterCondition, + BooleanExpr, not, andFunction, orFunction, @@ -56,7 +56,7 @@ import { /* eslint @typescript-eslint/no-explicit-any: 0 */ -export function toPipelineFilterCondition(f: FilterInternal): FilterCondition { +export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { if (f instanceof FieldFilterInternal) { const field = Field.of(f.field.toString()); if (isNanValue(f.value)) { @@ -137,13 +137,13 @@ export function toPipelineFilterCondition(f: FilterInternal): FilterCondition { case CompositeOperator.AND: { const conditions = f .getFilters() - .map(f => toPipelineFilterCondition(f)); + .map(f => toPipelineBooleanExpr(f)); return andFunction(conditions[0], ...conditions.slice(1)); } case CompositeOperator.OR: { const conditions = f .getFilters() - .map(f => toPipelineFilterCondition(f)); + .map(f => toPipelineBooleanExpr(f)); return orFunction(conditions[0], ...conditions.slice(1)); } default: @@ -176,7 +176,7 @@ export function toPipeline(query: Query, db: Firestore): Pipeline { // filters for (const filter of query.filters) { - pipeline = pipeline.where(toPipelineFilterCondition(filter)); + pipeline = pipeline.where(toPipelineBooleanExpr(filter)); } // orders @@ -240,7 +240,7 @@ function whereConditionsFromCursor( bound: Bound, orderings: Ordering[], position: 'before' | 'after' -): FilterCondition { +): BooleanExpr { const cursors = bound.position.map(value => Constant._fromProto(value)); const filterFunc = position === 'before' ? lt : gt; const filterInclusiveFunc = position === 'before' ? lte : gte; diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index cf22f7ec3cf..97f35e5dc1f 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -2113,7 +2113,7 @@ export abstract class Selectable extends Expr { * * An interface that represents a filter condition. */ -export abstract class FilterCondition extends Expr { +export abstract class BooleanExpr extends Expr { filterable: true = true; } @@ -2559,7 +2559,7 @@ export class FirestoreFunction extends Expr { */ export class GenericFunction extends FirestoreFunction - implements FilterCondition, Accumulator + implements BooleanExpr, Accumulator { accumulator: true = true; filterable: true = true; @@ -2625,7 +2625,7 @@ export class ArrayFunction extends FirestoreFunction { /** * @beta */ -export class Eq extends FirestoreFunction implements FilterCondition { +export class Eq extends FirestoreFunction implements BooleanExpr { constructor(private left: Expr, private right: Expr) { super('eq', [left, right]); } @@ -2636,7 +2636,7 @@ export class Eq extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class Neq extends FirestoreFunction implements FilterCondition { +export class Neq extends FirestoreFunction implements BooleanExpr { constructor(private left: Expr, private right: Expr) { super('neq', [left, right]); } @@ -2647,7 +2647,7 @@ export class Neq extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class Lt extends FirestoreFunction implements FilterCondition { +export class Lt extends FirestoreFunction implements BooleanExpr { constructor(private left: Expr, private right: Expr) { super('lt', [left, right]); } @@ -2658,7 +2658,7 @@ export class Lt extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class Lte extends FirestoreFunction implements FilterCondition { +export class Lte extends FirestoreFunction implements BooleanExpr { constructor(private left: Expr, private right: Expr) { super('lte', [left, right]); } @@ -2669,7 +2669,7 @@ export class Lte extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class Gt extends FirestoreFunction implements FilterCondition { +export class Gt extends FirestoreFunction implements BooleanExpr { constructor(private left: Expr, private right: Expr) { super('gt', [left, right]); } @@ -2680,7 +2680,7 @@ export class Gt extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class Gte extends FirestoreFunction implements FilterCondition { +export class Gte extends FirestoreFunction implements BooleanExpr { constructor(private left: Expr, private right: Expr) { super('gte', [left, right]); } @@ -2711,7 +2711,7 @@ export class ArrayReverse extends FirestoreFunction { */ export class ArrayContains extends FirestoreFunction - implements FilterCondition + implements BooleanExpr { constructor(private array: Expr, private element: Expr) { super('array_contains', [array, element]); @@ -2725,7 +2725,7 @@ export class ArrayContains */ export class ArrayContainsAll extends FirestoreFunction - implements FilterCondition + implements BooleanExpr { constructor(private array: Expr, private values: Expr[]) { super('array_contains_all', [array, new ListOfExprs(values)]); @@ -2739,7 +2739,7 @@ export class ArrayContainsAll */ export class ArrayContainsAny extends FirestoreFunction - implements FilterCondition + implements BooleanExpr { constructor(private array: Expr, private values: Expr[]) { super('array_contains_any', [array, new ListOfExprs(values)]); @@ -2769,7 +2769,7 @@ export class ArrayElement extends FirestoreFunction { /** * @beta */ -export class EqAny extends FirestoreFunction implements FilterCondition { +export class EqAny extends FirestoreFunction implements BooleanExpr { constructor(private left: Expr, private others: Expr[]) { super('eq_any', [left, new ListOfExprs(others)]); } @@ -2780,7 +2780,7 @@ export class EqAny extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class NotEqAny extends FirestoreFunction implements FilterCondition { +export class NotEqAny extends FirestoreFunction implements BooleanExpr { constructor(private left: Expr, private others: Expr[]) { super('not_eq_any', [left, new ListOfExprs(others)]); } @@ -2791,7 +2791,7 @@ export class NotEqAny extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class IsNan extends FirestoreFunction implements FilterCondition { +export class IsNan extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr) { super('is_nan', [expr]); } @@ -2802,7 +2802,7 @@ export class IsNan extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class Exists extends FirestoreFunction implements FilterCondition { +export class Exists extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr) { super('exists', [expr]); } @@ -2813,7 +2813,7 @@ export class Exists extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class Not extends FirestoreFunction implements FilterCondition { +export class Not extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr) { super('not', [expr]); } @@ -2824,8 +2824,8 @@ export class Not extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class And extends FirestoreFunction implements FilterCondition { - constructor(private conditions: FilterCondition[]) { +export class And extends FirestoreFunction implements BooleanExpr { + constructor(private conditions: BooleanExpr[]) { super('and', conditions); } @@ -2835,8 +2835,8 @@ export class And extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class Or extends FirestoreFunction implements FilterCondition { - constructor(private conditions: FilterCondition[]) { +export class Or extends FirestoreFunction implements BooleanExpr { + constructor(private conditions: BooleanExpr[]) { super('or', conditions); } @@ -2846,8 +2846,8 @@ export class Or extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class Xor extends FirestoreFunction implements FilterCondition { - constructor(private conditions: FilterCondition[]) { +export class Xor extends FirestoreFunction implements BooleanExpr { + constructor(private conditions: BooleanExpr[]) { super('xor', conditions); } @@ -2859,7 +2859,7 @@ export class Xor extends FirestoreFunction implements FilterCondition { */ export class Cond extends FirestoreFunction { constructor( - private condition: FilterCondition, + private condition: BooleanExpr, private thenExpr: Expr, private elseExpr: Expr ) { @@ -2935,7 +2935,7 @@ export class ByteLength extends FirestoreFunction { /** * @beta */ -export class Like extends FirestoreFunction implements FilterCondition { +export class Like extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr, private pattern: Expr) { super('like', [expr, pattern]); } @@ -2948,7 +2948,7 @@ export class Like extends FirestoreFunction implements FilterCondition { */ export class RegexContains extends FirestoreFunction - implements FilterCondition + implements BooleanExpr { constructor(private expr: Expr, private pattern: Expr) { super('regex_contains', [expr, pattern]); @@ -2960,7 +2960,7 @@ export class RegexContains /** * @beta */ -export class RegexMatch extends FirestoreFunction implements FilterCondition { +export class RegexMatch extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr, private pattern: Expr) { super('regex_match', [expr, pattern]); } @@ -2971,7 +2971,7 @@ export class RegexMatch extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class StrContains extends FirestoreFunction implements FilterCondition { +export class StrContains extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr, private substring: Expr) { super('str_contains', [expr, substring]); } @@ -2982,7 +2982,7 @@ export class StrContains extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class StartsWith extends FirestoreFunction implements FilterCondition { +export class StartsWith extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr, private prefix: Expr) { super('starts_with', [expr, prefix]); } @@ -2993,7 +2993,7 @@ export class StartsWith extends FirestoreFunction implements FilterCondition { /** * @beta */ -export class EndsWith extends FirestoreFunction implements FilterCondition { +export class EndsWith extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr, private suffix: Expr) { super('ends_with', [expr, suffix]); } @@ -3241,7 +3241,7 @@ export class Countif extends FirestoreFunction implements Accumulator { * @param booleanExpr - The boolean expression to evaluate on each input. * @returns A new `Accumulator` representing the 'countif' aggregation. */ -export function countif(booleanExpr: FilterCondition): Countif { +export function countif(booleanExpr: BooleanExpr): Countif { return new Countif(booleanExpr); } @@ -3811,7 +3811,7 @@ export function currentContext(): CurrentContext { /** * @beta */ -export class IsError extends FirestoreFunction implements FilterCondition { +export class IsError extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr) { super('is_error', [expr]); } @@ -3889,7 +3889,7 @@ export function ifError(tryExpr: Expr, catchValue: any): IfError { /** * @beta */ -export class IsAbsent extends FirestoreFunction implements FilterCondition { +export class IsAbsent extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr) { super('is_absent', [expr]); } @@ -3935,7 +3935,7 @@ export function isAbsent(value: Expr | string): IsAbsent { /** * @beta */ -export class IsNull extends FirestoreFunction implements FilterCondition { +export class IsNull extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr) { super('is_null', [expr]); } @@ -3979,7 +3979,7 @@ export function isNull(value: Expr | string): IsNull { /** * @beta */ -export class IsNotNull extends FirestoreFunction implements FilterCondition { +export class IsNotNull extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr) { super('is_not_null', [expr]); } @@ -4023,7 +4023,7 @@ export function isNotNull(value: Expr | string): IsNotNull { /** * @beta */ -export class IsNotNan extends FirestoreFunction implements FilterCondition { +export class IsNotNan extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr) { super('is_not_nan', [expr]); } @@ -6195,7 +6195,7 @@ export function notEqAny(element: Expr | string, others: any[]): NotEqAny { * @param right Additional filter conditions to 'XOR' together. * @return A new {@code Expr} representing the logical 'XOR' operation. */ -export function xor(left: FilterCondition, ...right: FilterCondition[]): Xor { +export function xor(left: BooleanExpr, ...right: BooleanExpr[]): Xor { return new Xor([left, ...right]); } @@ -6217,7 +6217,7 @@ export function xor(left: FilterCondition, ...right: FilterCondition[]): Xor { * @return A new {@code Expr} representing the conditional expression. */ export function cond( - condition: FilterCondition, + condition: BooleanExpr, thenExpr: Expr, elseExpr: Expr ): Cond { @@ -6237,7 +6237,7 @@ export function cond( * @param filter The filter condition to negate. * @return A new {@code Expr} representing the negated filter condition. */ -export function not(filter: FilterCondition): Not { +export function not(filter: BooleanExpr): Not { return new Not(filter); } @@ -8313,8 +8313,8 @@ export function genericFunction( * @return A new {@code Expr} representing the logical 'AND' operation. */ export function andFunction( - left: FilterCondition, - ...right: FilterCondition[] + left: BooleanExpr, + ...right: BooleanExpr[] ): And { return new And([left, ...right]); } @@ -8335,8 +8335,8 @@ export function andFunction( * @return A new {@code Expr} representing the logical 'OR' operation. */ export function orFunction( - left: FilterCondition, - ...right: FilterCondition[] + left: BooleanExpr, + ...right: BooleanExpr[] ): Or { return new Or([left, ...right]); } diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index b494ae220f8..433c2b6976c 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -36,7 +36,7 @@ import { Expr, ExprWithAlias, Field, - FilterCondition, + BooleanExpr, Ordering, Selectable } from './expressions'; @@ -244,11 +244,11 @@ export class Pipeline implements ProtoSerializable { /** * Filters the documents from previous stages to only include those matching the specified {@link - * FilterCondition}. + * BooleanExpr}. * *

This stage allows you to apply conditions to the data, similar to a "WHERE" clause in SQL. * You can filter documents based on their field values, using implementations of {@link - * FilterCondition}, typically including but not limited to: + * BooleanExpr}, typically including but not limited to: * *

    *
  • field comparators: {@link Function#eq}, {@link Function#lt} (less than), {@link @@ -270,10 +270,10 @@ export class Pipeline implements ProtoSerializable { * ); * ``` * - * @param condition The {@link FilterCondition} to apply. + * @param condition The {@link BooleanExpr} to apply. * @return A new Pipeline object with this stage appended to the stage list. */ - where(condition: FilterCondition): Pipeline { + where(condition: BooleanExpr): Pipeline { this.readUserData('where', condition); return this._addStage(new Where(condition)); } diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index 71d5cd95763..e5f2d8b0baf 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -34,7 +34,7 @@ import { Accumulator, Expr, Field, - FilterCondition, + BooleanExpr, Ordering } from './expressions'; import { Pipeline } from './pipeline'; @@ -235,7 +235,7 @@ export class DocumentsSource implements Stage { export class Where implements Stage { name = 'where'; - constructor(private condition: FilterCondition) {} + constructor(private condition: BooleanExpr) {} /** * @internal From 06d72b4bba0cac55e75cf61ff43d3142b5e21cde Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 21 Feb 2025 17:18:13 -0700 Subject: [PATCH 29/75] Update functions with variadic params to match signatures of the backend --- packages/firestore/src/api_pipelines.ts | 4 +- packages/firestore/src/core/pipeline-util.ts | 16 +- .../firestore/src/lite-api/expressions.ts | 608 +++++++----------- packages/firestore/src/lite-api/stage.ts | 8 +- .../test/integration/api/pipeline.test.ts | 119 +++- .../integration/api/query_to_pipeline.test.ts | 2 +- 6 files changed, 356 insertions(+), 401 deletions(-) diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index e8fb29ae82b..589694dd106 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -107,7 +107,7 @@ export { genericFunction, ascending, descending, - countif, + countIf, bitAnd, bitOr, bitXor, @@ -133,7 +133,7 @@ export { key, substr, manhattanDistance, - Countif, + CountIf, BitAnd, BitOr, BitXor, diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index 278e9f387e4..fbb9c502f54 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -135,16 +135,16 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { } else if (f instanceof CompositeFilterInternal) { switch (f.op) { case CompositeOperator.AND: { - const conditions = f - .getFilters() - .map(f => toPipelineBooleanExpr(f)); - return andFunction(conditions[0], ...conditions.slice(1)); + const conditions = f.getFilters().map(f => toPipelineBooleanExpr(f)); + return andFunction( + conditions[0], + conditions[1], + ...conditions.slice(2) + ); } case CompositeOperator.OR: { - const conditions = f - .getFilters() - .map(f => toPipelineBooleanExpr(f)); - return orFunction(conditions[0], ...conditions.slice(1)); + const conditions = f.getFilters().map(f => toPipelineBooleanExpr(f)); + return orFunction(conditions[0], conditions[1], ...conditions.slice(2)); } default: fail('Unexpected operator'); diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 97f35e5dc1f..e0b02526d1f 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -126,25 +126,16 @@ export abstract class Expr implements ProtoSerializable, UserData { * Field.of("quantity").add(Field.of("reserve")); * ``` * - * @param expression The expression to add to this expression. + * @param second The expression or literal to add to this expression. + * @param others Optional additional expressions or literals to add to this expression. * @return A new `Expr` representing the addition operation. */ - add(expression: Expr): Add; - - /** - * Creates an expression that adds this expression to another expression or constant value. - * - * ```typescript - * // Add 5 to the value of the 'age' field - * Field.of("age").add(5); - * ``` - * - * @param value The constant value to add. - * @return A new `Expr` representing the addition operation. - */ - add(value: any): Add; - add(other: Expr | any): Add { - return new Add(this, valueToDefaultExpr(other)); + add(second: Expr | any, ...others: Array): Add { + const values = [second, ...others]; + return new Add( + this, + values.map(value => valueToDefaultExpr(value)) + ); } /** @@ -184,25 +175,16 @@ export abstract class Expr implements ProtoSerializable, UserData { * Field.of("quantity").multiply(Field.of("price")); * ``` * - * @param other The expression to multiply by. + * @param second The second expression or literal to multiply by. + * @param others Optional additional expressions or literals to multiply by. * @return A new `Expr` representing the multiplication operation. */ - multiply(other: Expr): Multiply; - - /** - * Creates an expression that multiplies this expression by a constant value. - * - * ```typescript - * // Multiply the 'value' field by 2 - * Field.of("value").multiply(2); - * ``` - * - * @param other The constant value to multiply by. - * @return A new `Expr` representing the multiplication operation. - */ - multiply(other: any): Multiply; - multiply(other: any): Multiply { - return new Multiply(this, valueToDefaultExpr(other)); + multiply(second: Expr | any, ...others: Array): Multiply { + const values = [second, ...others]; + return new Multiply( + this, + values.map(value => valueToDefaultExpr(value)) + ); } /** @@ -447,28 +429,16 @@ export abstract class Expr implements ProtoSerializable, UserData { * // Combine the 'items' array with another array field. * Field.of("items").arrayConcat(Field.of("otherItems")); * ``` - * - * @param arrays The array expressions to concatenate. + * @param secondArray Second array expression or array literal to concatenate. + * @param otherArrays Optional additional array expressions or array literals to concatenate. * @return A new `Expr` representing the concatenated array. */ - arrayConcat(...arrays: Expr[]): ArrayConcat; - - /** - * Creates an expression that concatenates an array with one or more other arrays. - * - * ```typescript - * // Combine the 'tags' array with a new array and an array field - * Field.of("tags").arrayConcat(Arrays.asList("newTag1", "newTag2"), Field.of("otherTag")); - * ``` - * - * @param arrays The arrays to concatenate. - * @return A new `Expr` representing the concatenated arrays. - */ - arrayConcat(...arrays: any[][]): ArrayConcat; - arrayConcat(...arrays: any[]): ArrayConcat { - const exprValues = arrays.map(value => - value instanceof Expr ? value : valueToDefaultExpr(value) - ); + arrayConcat( + secondArray: Expr | any[], + ...otherArrays: Array + ): ArrayConcat { + const elements = [secondArray, ...otherArrays]; + const exprValues = elements.map(value => valueToDefaultExpr(value)); return new ArrayConcat(this, exprValues); } @@ -950,10 +920,15 @@ export abstract class Expr implements ProtoSerializable, UserData { * Field.of("firstName").strConcat(Constant.of(" "), Field.of("lastName")); * ``` * - * @param elements The expressions (typically strings) to concatenate. + * @param secondString The additional expression or string literal to concatenate. + * @param otherStrings Optional additional expressions or string literals to concatenate. * @return A new `Expr` representing the concatenated string. */ - strConcat(...elements: Array): StrConcat { + strConcat( + secondString: Expr | string, + ...otherStrings: Array + ): StrConcat { + const elements = [secondString, ...otherStrings]; const exprs = elements.map(e => typeof e === 'string' ? Constant.of(e) : (e as Expr) ); @@ -1164,8 +1139,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * * @return A new `Accumulator` representing the 'countIf' aggregation. */ - countif(): Countif { - return new Countif(this); + countIf(): CountIf { + return new CountIf(this); } /** @@ -1176,25 +1151,19 @@ export abstract class Expr implements ProtoSerializable, UserData { * Field.of("timestamp").logicalMaximum(Function.currentTimestamp()); * ``` * - * @param other The expression to compare with. - * @return A new {@code Expr} representing the logical max operation. - */ - logicalMaximum(other: Expr): LogicalMaximum; - - /** - * Creates an expression that returns the larger value between this expression and a constant value, based on Firestore's value type ordering. - * - * ```typescript - * // Returns the larger value between the 'value' field and 10. - * Field.of("value").logicalMaximum(10); - * ``` - * - * @param other The constant value to compare with. + * @param second The second expression or literal to compare with. + * @param others Optional additional expressions or literals to compare with. * @return A new {@code Expr} representing the logical max operation. */ - logicalMaximum(other: any): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum { - return new LogicalMaximum(this, valueToDefaultExpr(other)); + logicalMaximum( + second: Expr | any, + ...others: Array + ): LogicalMaximum { + const values = [second, ...others]; + return new LogicalMaximum( + this, + values.map(value => valueToDefaultExpr(value)) + ); } /** @@ -1205,25 +1174,19 @@ export abstract class Expr implements ProtoSerializable, UserData { * Field.of("timestamp").logicalMinimum(Function.currentTimestamp()); * ``` * - * @param other The expression to compare with. - * @return A new {@code Expr} representing the logical min operation. - */ - logicalMinimum(other: Expr): LogicalMinimum; - - /** - * Creates an expression that returns the smaller value between this expression and a constant value, based on Firestore's value type ordering. - * - * ```typescript - * // Returns the smaller value between the 'value' field and 10. - * Field.of("value").logicalMinimum(10); - * ``` - * - * @param other The constant value to compare with. + * @param second The second expression or literal to compare with. + * @param others Optional additional expressions or literals to compare with. * @return A new {@code Expr} representing the logical min operation. */ - logicalMinimum(other: any): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum { - return new LogicalMinimum(this, valueToDefaultExpr(other)); + logicalMinimum( + second: Expr | any, + ...others: Array + ): LogicalMinimum { + const values = [second, ...others]; + return new LogicalMinimum( + this, + values.map(value => valueToDefaultExpr(value)) + ); } /** @@ -1772,9 +1735,10 @@ export abstract class Expr implements ProtoSerializable, UserData { * Creates an expression that returns a substring of the results of this expression. * * @param position Index of the first character of the substring. - * @param length Length of the substring. + * @param length Length of the substring. If not provided, the substring will + * end at the end of the input. */ - substr(position: number, length: number): Substr; + substr(position: number, length?: number): Substr; /** * @beta @@ -1782,12 +1746,14 @@ export abstract class Expr implements ProtoSerializable, UserData { * Creates an expression that returns a substring of the results of this expression. * * @param position An expression returning the index of the first character of the substring. - * @param length An expression returning the length of the substring. + * @param length An expression returning the length of the substring. If not provided the + * substring will end at the end of the input. */ - substr(position: Expr, length: Expr): Substr; - substr(position: Expr | number, length: Expr | number): Substr { + substr(position: Expr, length?: Expr): Substr; + substr(position: Expr | number, length?: Expr | number): Substr { const positionExpr = valueToDefaultExpr(position); - const lengthExpr = valueToDefaultExpr(length); + const lengthExpr = + length === undefined ? undefined : valueToDefaultExpr(length); return new Substr(this, positionExpr, lengthExpr); } @@ -2569,8 +2535,8 @@ export class GenericFunction * @beta */ export class Add extends FirestoreFunction { - constructor(private left: Expr, private right: Expr) { - super('add', [left, right]); + constructor(left: Expr, others: Expr[]) { + super('add', [left, ...others]); } } @@ -2587,8 +2553,8 @@ export class Subtract extends FirestoreFunction { * @beta */ export class Multiply extends FirestoreFunction { - constructor(private left: Expr, private right: Expr) { - super('multiply', [left, right]); + constructor(left: Expr, others: Expr[]) { + super('multiply', [left, ...others]); } } @@ -2692,7 +2658,7 @@ export class Gte extends FirestoreFunction implements BooleanExpr { * @beta */ export class ArrayConcat extends FirestoreFunction { - constructor(private array: Expr, private elements: Expr[]) { + constructor(array: Expr, elements: Expr[]) { super('array_concat', [array, ...elements]); } } @@ -2709,10 +2675,7 @@ export class ArrayReverse extends FirestoreFunction { /** * @beta */ -export class ArrayContains - extends FirestoreFunction - implements BooleanExpr -{ +export class ArrayContains extends FirestoreFunction implements BooleanExpr { constructor(private array: Expr, private element: Expr) { super('array_contains', [array, element]); } @@ -2723,10 +2686,7 @@ export class ArrayContains /** * @beta */ -export class ArrayContainsAll - extends FirestoreFunction - implements BooleanExpr -{ +export class ArrayContainsAll extends FirestoreFunction implements BooleanExpr { constructor(private array: Expr, private values: Expr[]) { super('array_contains_all', [array, new ListOfExprs(values)]); } @@ -2737,10 +2697,7 @@ export class ArrayContainsAll /** * @beta */ -export class ArrayContainsAny - extends FirestoreFunction - implements BooleanExpr -{ +export class ArrayContainsAny extends FirestoreFunction implements BooleanExpr { constructor(private array: Expr, private values: Expr[]) { super('array_contains_any', [array, new ListOfExprs(values)]); } @@ -2873,8 +2830,8 @@ export class Cond extends FirestoreFunction { * @beta */ export class LogicalMaximum extends FirestoreFunction { - constructor(private left: Expr, private right: Expr) { - super('logical_maximum', [left, right]); + constructor(first: Expr, others: Expr[]) { + super('logical_maximum', [first, ...others]); } } @@ -2882,8 +2839,8 @@ export class LogicalMaximum extends FirestoreFunction { * @beta */ export class LogicalMinimum extends FirestoreFunction { - constructor(private left: Expr, private right: Expr) { - super('logical_minimum', [left, right]); + constructor(first: Expr, others: Expr[]) { + super('logical_minimum', [first, ...others]); } } @@ -2946,10 +2903,7 @@ export class Like extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class RegexContains - extends FirestoreFunction - implements BooleanExpr -{ +export class RegexContains extends FirestoreFunction implements BooleanExpr { constructor(private expr: Expr, private pattern: Expr) { super('regex_contains', [expr, pattern]); } @@ -3220,9 +3174,9 @@ export class TimestampSub extends FirestoreFunction { /** * @beta */ -export class Countif extends FirestoreFunction implements Accumulator { +export class CountIf extends FirestoreFunction implements Accumulator { constructor(private booleanExpr: Expr) { - super('countif', [booleanExpr]); + super('count_if', [booleanExpr]); } accumulator = true as const; @@ -3241,8 +3195,8 @@ export class Countif extends FirestoreFunction implements Accumulator { * @param booleanExpr - The boolean expression to evaluate on each input. * @returns A new `Accumulator` representing the 'countif' aggregation. */ -export function countif(booleanExpr: BooleanExpr): Countif { - return new Countif(booleanExpr); +export function countIf(booleanExpr: BooleanExpr): CountIf { + return new CountIf(booleanExpr); } /** @@ -4315,8 +4269,12 @@ export function key(namespace: Expr | string, path: Expr | string): Key { * @beta */ export class Substr extends FirestoreFunction { - constructor(inputExpr: Expr, position: Expr, length: Expr) { - super('substr', [inputExpr, position, length]); + constructor(inputExpr: Expr, position: Expr, length: Expr | undefined) { + if (length) { + super('substr', [inputExpr, position, length]); + } else { + super('substr', [inputExpr, position]); + } } } @@ -4329,7 +4287,11 @@ export class Substr extends FirestoreFunction { * @param position Index of the first character of the substring. * @param length Length of the substring. */ -export function substr(field: string, position: number, length: number): Substr; +export function substr( + field: string, + position: number, + length?: number +): Substr; /** * @beta @@ -4340,7 +4302,7 @@ export function substr(field: string, position: number, length: number): Substr; * @param position Index of the first character of the substring. * @param length Length of the substring. */ -export function substr(input: Expr, position: number, length: number): Substr; +export function substr(input: Expr, position: number, length?: number): Substr; /** * @beta @@ -4351,7 +4313,7 @@ export function substr(input: Expr, position: number, length: number): Substr; * @param position An expression that returns the index of the first character of the substring. * @param length An expression that returns the length of the substring. */ -export function substr(field: string, position: Expr, length: Expr): Substr; +export function substr(field: string, position: Expr, length?: Expr): Substr; /** * @beta @@ -4362,16 +4324,17 @@ export function substr(field: string, position: Expr, length: Expr): Substr; * @param position An expression that returns the index of the first character of the substring. * @param length An expression that returns the length of the substring. */ -export function substr(input: Expr, position: Expr, length: Expr): Substr; +export function substr(input: Expr, position: Expr, length?: Expr): Substr; export function substr( field: Expr | string, position: Expr | number, - length: Expr | number + length?: Expr | number ): Substr { const fieldExpr = fieldOfOrExpr(field); const positionExpr = valueToDefaultExpr(position); - const lengthExpr = valueToDefaultExpr(length); + const lengthExpr = + length === undefined ? undefined : valueToDefaultExpr(length); return new Substr(fieldExpr, positionExpr, lengthExpr); } @@ -4511,27 +4474,16 @@ export function manhattanDistance( * add(Field.of("quantity"), Field.of("reserve")); * ``` * - * @param left The first expression to add. - * @param right The second expression to add. + * @param first The first expression to add. + * @param second The second expression or literal to add. + * @param others Optional other expressions or literals to add. * @return A new {@code Expr} representing the addition operation. */ -export function add(left: Expr, right: Expr): Add; - -/** - * @beta - * - * Creates an expression that adds an expression to a constant value. - * - * ```typescript - * // Add 5 to the value of the 'age' field - * add(Field.of("age"), 5); - * ``` - * - * @param left The expression to add to. - * @param right The constant value to add. - * @return A new {@code Expr} representing the addition operation. - */ -export function add(left: Expr, right: any): Add; +export function add( + first: Expr, + second: Expr | any, + ...others: Array +): Add; /** * @beta @@ -4543,31 +4495,20 @@ export function add(left: Expr, right: any): Add; * add("quantity", Field.of("reserve")); * ``` * - * @param left The field name to add to. - * @param right The expression to add. + * @param fieldName The name of the field containing the value to add. + * @param second The second expression or literal to add. + * @param others Optional other expressions or literals to add. * @return A new {@code Expr} representing the addition operation. */ -export function add(left: string, right: Expr): Add; +export function add( + fieldName: string, + second: Expr | any, + ...others: Array +): Add; -/** - * @beta - * - * Creates an expression that adds a field's value to a constant value. - * - * ```typescript - * // Add 5 to the value of the 'age' field - * add("age", 5); - * ``` - * - * @param left The field name to add to. - * @param right The constant value to add. - * @return A new {@code Expr} representing the addition operation. - */ -export function add(left: string, right: any): Add; -export function add(left: Expr | string, right: Expr | any): Add { - const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = - right instanceof Expr ? right : valueToDefaultExpr(right); +export function add(first: Expr | string, ...others: Array): Add { + const normalizedLeft = fieldOfOrExpr(first); + const normalizedRight = others.map(value => valueToDefaultExpr(value)); return new Add(normalizedLeft, normalizedRight); } @@ -4651,27 +4592,16 @@ export function subtract(left: Expr | string, right: Expr | any): Subtract { * multiply(Field.of("quantity"), Field.of("price")); * ``` * - * @param left The first expression to multiply. - * @param right The second expression to multiply. - * @return A new {@code Expr} representing the multiplication operation. - */ -export function multiply(left: Expr, right: Expr): Multiply; - -/** - * @beta - * - * Creates an expression that multiplies an expression by a constant value. - * - * ```typescript - * // Multiply the value of the 'price' field by 2 - * multiply(Field.of("price"), 2); - * ``` - * - * @param left The expression to multiply. - * @param right The constant value to multiply by. + * @param first The first expression to multiply. + * @param second The second expression or literal to multiply. + * @param others Optional additional expressions or literals to multiply. * @return A new {@code Expr} representing the multiplication operation. */ -export function multiply(left: Expr, right: any): Multiply; +export function multiply( + first: Expr, + second: Expr | any, + ...others: Array +): Multiply; /** * @beta @@ -4683,31 +4613,23 @@ export function multiply(left: Expr, right: any): Multiply; * multiply("quantity", Field.of("price")); * ``` * - * @param left The field name to multiply. - * @param right The expression to multiply by. + * @param fieldName The name of the field containing the value to add. + * @param second The second expression or literal to add. + * @param others Optional other expressions or literals to add. * @return A new {@code Expr} representing the multiplication operation. */ -export function multiply(left: string, right: Expr): Multiply; +export function multiply( + fieldName: string, + second: Expr | any, + ...others: Array +): Multiply; -/** - * @beta - * - * Creates an expression that multiplies a field's value by a constant value. - * - * ```typescript - * // Multiply the 'value' field by 2 - * multiply("value", 2); - * ``` - * - * @param left The field name to multiply. - * @param right The constant value to multiply by. - * @return A new {@code Expr} representing the multiplication operation. - */ -export function multiply(left: string, right: any): Multiply; -export function multiply(left: Expr | string, right: Expr | any): Multiply { - const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = - right instanceof Expr ? right : valueToDefaultExpr(right); +export function multiply( + left: Expr | string, + ...others: Array +): Multiply { + const normalizedLeft = fieldOfOrExpr(left); + const normalizedRight = others.map(value => valueToDefaultExpr(value)); return new Multiply(normalizedLeft, normalizedRight); } @@ -5704,27 +5626,16 @@ export function gte(left: Expr | string, right: any): Gte { * arrayConcat(Field.of("items"), [Field.of("newItems"), Field.of("otherItems")]); * ``` * - * @param array The array expression to concatenate to. - * @param elements The array expressions to concatenate. - * @return A new {@code Expr} representing the concatenated array. - */ -export function arrayConcat(array: Expr, elements: Expr[]): ArrayConcat; - -/** - * @beta - * - * Creates an expression that concatenates an array expression with other arrays and/or values. - * - * ```typescript - * // Combine the 'tags' array with a new array - * arrayConcat(Field.of("tags"), ["newTag1", "newTag2"]); - * ``` - * - * @param array The array expression to concatenate to. - * @param elements The array expressions or single values to concatenate. + * @param firstArray The first array expression to concatenate to. + * @param secondArray The second array expression or array literal to concatenate to. + * @param otherArrays Optional additional array expressions or array literals to concatenate. * @return A new {@code Expr} representing the concatenated array. */ -export function arrayConcat(array: Expr, elements: any[]): ArrayConcat; +export function arrayConcat( + firstArray: Expr, + secondArray: Expr | any, + ...otherArrays: Array +): ArrayConcat; /** * @beta @@ -5736,35 +5647,23 @@ export function arrayConcat(array: Expr, elements: any[]): ArrayConcat; * arrayConcat("items", [Field.of("newItems"), Field.of("otherItems")]); * ``` * - * @param array The field name containing array values. - * @param elements The array expressions to concatenate. + * @param firstArrayField The first array to concatenate to. + * @param secondArray The second array expression or array literal to concatenate to. + * @param otherArrays Optional additional array expressions or array literals to concatenate. * @return A new {@code Expr} representing the concatenated array. */ -export function arrayConcat(array: string, elements: Expr[]): ArrayConcat; +export function arrayConcat( + firstArrayField: string, + secondArray: Expr | any[], + ...otherArrays: Array +): ArrayConcat; -/** - * @beta - * - * Creates an expression that concatenates a field's array value with other arrays and/or values. - * - * ```typescript - * // Combine the 'tags' array with a new array - * arrayConcat("tags", ["newTag1", "newTag2"]); - * ``` - * - * @param array The field name containing array values. - * @param elements The array expressions or single values to concatenate. - * @return A new {@code Expr} representing the concatenated array. - */ -export function arrayConcat(array: string, elements: any[]): ArrayConcat; export function arrayConcat( - array: Expr | string, - elements: any[] + firstArray: Expr | string, + ...otherArrays: Array ): ArrayConcat { - const arrayExpr = array instanceof Expr ? array : Field.of(array); - const exprValues = elements.map(element => - element instanceof Expr ? element : valueToDefaultExpr(element) - ); + const arrayExpr = fieldOfOrExpr(firstArray); + const exprValues = otherArrays.map(element => valueToDefaultExpr(element)); return new ArrayConcat(arrayExpr, exprValues); } @@ -6191,12 +6090,17 @@ export function notEqAny(element: Expr | string, others: any[]): NotEqAny { * eq("status", "active")); * ``` * - * @param left The first filter condition. - * @param right Additional filter conditions to 'XOR' together. + * @param first The first filter condition. + * @param second The second filter condition. + * @param more Additional filter conditions to 'XOR' together. * @return A new {@code Expr} representing the logical 'XOR' operation. */ -export function xor(left: BooleanExpr, ...right: BooleanExpr[]): Xor { - return new Xor([left, ...right]); +export function xor( + first: BooleanExpr, + second: BooleanExpr, + ...more: BooleanExpr[] +): Xor { + return new Xor([first, second, ...more]); } /** @@ -6251,27 +6155,16 @@ export function not(filter: BooleanExpr): Not { * logicalMaximum(Field.of("field1"), Field.of("field2")); * ``` * - * @param left The left operand expression. - * @param right The right operand expression. - * @return A new {@code Expr} representing the logical max operation. - */ -export function logicalMaximum(left: Expr, right: Expr): LogicalMaximum; - -/** - * @beta - * - * Creates an expression that returns the larger value between an expression and a constant value, based on Firestore's value type ordering. - * - * ```typescript - * // Returns the larger value between the 'value' field and 10. - * logicalMaximum(Field.of("value"), 10); - * ``` - * - * @param left The left operand expression. - * @param right The right operand constant. + * @param first The first operand expression. + * @param second The second expression or literal. + * @param others Optional additional expressions or literals. * @return A new {@code Expr} representing the logical max operation. */ -export function logicalMaximum(left: Expr, right: any): LogicalMaximum; +export function logicalMaximum( + first: Expr, + second: Expr | any, + ...others: Array +): LogicalMaximum; /** * @beta @@ -6283,35 +6176,25 @@ export function logicalMaximum(left: Expr, right: any): LogicalMaximum; * logicalMaximum("field1", Field.of('field2')); * ``` * - * @param left The left operand field name. - * @param right The right operand expression. + * @param fieldName The first operand field name. + * @param second The second expression or literal. + * @param others Optional additional expressions or literals. * @return A new {@code Expr} representing the logical max operation. */ -export function logicalMaximum(left: string, right: Expr): LogicalMaximum; +export function logicalMaximum( + left: string, + second: Expr | any, + ...others: Array +): LogicalMaximum; -/** - * @beta - * - * Creates an expression that returns the larger value between a field and a constant value, based on Firestore's value type ordering. - * - * ```typescript - * // Returns the larger value between the 'value' field and 10. - * logicalMaximum("value", 10); - * ``` - * - * @param left The left operand field name. - * @param right The right operand constant. - * @return A new {@code Expr} representing the logical max operation. - */ -export function logicalMaximum(left: string, right: any): LogicalMaximum; export function logicalMaximum( - left: Expr | string, - right: Expr | any + first: Expr | string, + ...others: Array ): LogicalMaximum { - const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = - right instanceof Expr ? right : valueToDefaultExpr(right); - return new LogicalMaximum(normalizedLeft, normalizedRight); + return new LogicalMaximum( + fieldOfOrExpr(first), + others.map(value => valueToDefaultExpr(value)) + ); } /** @@ -6324,27 +6207,16 @@ export function logicalMaximum( * logicalMinimum(Field.of("field1"), Field.of("field2")); * ``` * - * @param left The left operand expression. - * @param right The right operand expression. + * @param first The first operand expression. + * @param second The second expression or literal. + * @param others Optional additional expressions or literals. * @return A new {@code Expr} representing the logical min operation. */ -export function logicalMinimum(left: Expr, right: Expr): LogicalMinimum; - -/** - * @beta - * - * Creates an expression that returns the smaller value between an expression and a constant value, based on Firestore's value type ordering. - * - * ```typescript - * // Returns the smaller value between the 'value' field and 10. - * logicalMinimum(Field.of("value"), 10); - * ``` - * - * @param left The left operand expression. - * @param right The right operand constant. - * @return A new {@code Expr} representing the logical min operation. - */ -export function logicalMinimum(left: Expr, right: any): LogicalMinimum; +export function logicalMinimum( + first: Expr, + second: Expr | any, + ...others: Array +): LogicalMinimum; /** * @beta @@ -6356,35 +6228,25 @@ export function logicalMinimum(left: Expr, right: any): LogicalMinimum; * logicalMinimum("field1", Field.of("field2")); * ``` * - * @param left The left operand field name. - * @param right The right operand expression. + * @param fieldName The first operand field name. + * @param second The second expression or literal. + * @param others Optional additional expressions or literals. * @return A new {@code Expr} representing the logical min operation. */ -export function logicalMinimum(left: string, right: Expr): LogicalMinimum; +export function logicalMinimum( + fieldName: string, + second: Expr | any, + ...others: Array +): LogicalMinimum; -/** - * @beta - * - * Creates an expression that returns the smaller value between a field and a constant value, based on Firestore's value type ordering. - * - * ```typescript - * // Returns the smaller value between the 'value' field and 10. - * logicalMinimum("value", 10); - * ``` - * - * @param left The left operand field name. - * @param right The right operand constant. - * @return A new {@code Expr} representing the logical min operation. - */ -export function logicalMinimum(left: string, right: any): LogicalMinimum; export function logicalMinimum( - left: Expr | string, - right: Expr | any + first: Expr | string, + ...others: Array ): LogicalMinimum { - const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = - right instanceof Expr ? right : valueToDefaultExpr(right); - return new LogicalMinimum(normalizedLeft, normalizedRight); + return new LogicalMinimum( + fieldOfOrExpr(first), + others.map(value => valueToDefaultExpr(value)) + ); } /** @@ -7253,13 +7115,15 @@ export function trim(expr: Expr | string): Trim { * strConcat("firstName", " ", Field.of("lastName")); * ``` * - * @param first The field name containing the initial string value. - * @param elements The expressions (typically strings) to concatenate. + * @param fieldName The field name containing the initial string value. + * @param secondString An expression or string literal to concatenate. + * @param otherStrings Optional additional expressions or literals (typically strings) to concatenate. * @return A new {@code Expr} representing the concatenated string. */ export function strConcat( - first: string, - ...elements: Array + fieldName: string, + secondString: Expr | string, + ...otherStrings: Array ): StrConcat; /** @@ -7271,13 +7135,15 @@ export function strConcat( * strConcat(Field.of("firstName"), " ", Field.of("lastName")); * ``` * - * @param first The initial string expression to concatenate to. - * @param elements The expressions (typically strings) to concatenate. + * @param firstString The initial string expression to concatenate to. + * @param secondString An expression or string literal to concatenate. + * @param otherStrings Optional additional expressions or literals (typically strings) to concatenate. * @return A new {@code Expr} representing the concatenated string. */ export function strConcat( - first: Expr, - ...elements: Array + firstString: Expr, + secondString: Expr | string, + ...otherStrings: Array ): StrConcat; export function strConcat( first: string | Expr, @@ -7286,7 +7152,7 @@ export function strConcat( const exprs = elements.map(e => e instanceof Expr ? e : valueToDefaultExpr(e) ); - return new StrConcat(first instanceof Expr ? first : Field.of(first), exprs); + return new StrConcat(valueToDefaultExpr(first), exprs); } /** @@ -8308,15 +8174,17 @@ export function genericFunction( * const condition = and(gt("age", 18), eq("city", "London"), eq("status", "active")); * ``` * - * @param left The first filter condition. - * @param right Additional filter conditions to 'AND' together. + * @param first The first filter condition. + * @param second The second filter condition. + * @param more Additional filter conditions to 'AND' together. * @return A new {@code Expr} representing the logical 'AND' operation. */ export function andFunction( - left: BooleanExpr, - ...right: BooleanExpr[] + first: BooleanExpr, + second: BooleanExpr, + ...more: BooleanExpr[] ): And { - return new And([left, ...right]); + return new And([first, second, ...more]); } /** @@ -8330,15 +8198,17 @@ export function andFunction( * const condition = or(gt("age", 18), eq("city", "London"), eq("status", "active")); * ``` * - * @param left The first filter condition. - * @param right Additional filter conditions to 'OR' together. + * @param first The first filter condition. + * @param second The second filter condition. + * @param more Additional filter conditions to 'OR' together. * @return A new {@code Expr} representing the logical 'OR' operation. */ export function orFunction( - left: BooleanExpr, - ...right: BooleanExpr[] + first: BooleanExpr, + second: BooleanExpr, + ...more: BooleanExpr[] ): Or { - return new Or([left, ...right]); + return new Or([first, second, ...more]); } /** diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index e5f2d8b0baf..2562777a4da 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -30,13 +30,7 @@ import { } from '../remote/serializer'; import { hardAssert } from '../util/assert'; -import { - Accumulator, - Expr, - Field, - BooleanExpr, - Ordering -} from './expressions'; +import { Accumulator, Expr, Field, BooleanExpr, Ordering } from './expressions'; import { Pipeline } from './pipeline'; import { DocumentReference } from './reference'; import { VectorValue } from './vector_value'; diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 714fac83be4..7abb7f0c7cf 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -72,7 +72,7 @@ import { notEqAny, collection, multiply, - countif, + countIf, bitAnd, bitOr, bitXor, @@ -93,7 +93,9 @@ import { documentIdFunction, substr, manhattanDistance, - documentId + documentId, + logicalMinimum, + xor } from '../util/firebase_export'; import { apiDescribe, withTestCollection } from '../util/helpers'; @@ -618,7 +620,7 @@ apiDescribe.only('Pipelines', persistence => { it('returns countif accumulation', async () => { let results = await randomCol .pipeline() - .aggregate(countif(Field.of('rating').gt(4.3)).as('count')) + .aggregate(countIf(Field.of('rating').gt(4.3)).as('count')) .execute(); const expectedResults = { count: 3 @@ -627,7 +629,7 @@ apiDescribe.only('Pipelines', persistence => { results = await randomCol .pipeline() - .aggregate(Field.of('rating').gt(4.3).countif().as('count')) + .aggregate(Field.of('rating').gt(4.3).countIf().as('count')) .execute(); expectResults(results, expectedResults); }); @@ -743,23 +745,57 @@ apiDescribe.only('Pipelines', persistence => { it('where with and', async () => { const results = await randomCol .pipeline() - .where(andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction'))) + .where( + andFunction( + gt('rating', 4.5), + eq('genre', 'Science Fiction'), + lte('published', 1965) + ) + ) .execute(); expectResults(results, 'book10'); }); it('where with or', async () => { const results = await randomCol .pipeline() - .where(orFunction(eq('genre', 'Romance'), eq('genre', 'Dystopian'))) + .where( + orFunction( + eq('genre', 'Romance'), + eq('genre', 'Dystopian'), + eq('genre', 'Fantasy') + ) + ) .select('title') .execute(); expectResults( results, { title: 'Pride and Prejudice' }, + { title: 'The Lord of the Rings' }, { title: "The Handmaid's Tale" }, { title: '1984' } ); }); + + it('where with xor', async () => { + const results = await randomCol + .pipeline() + .where( + xor( + eq('genre', 'Romance'), + eq('genre', 'Dystopian'), + eq('genre', 'Fantasy'), + eq('published', 1949) + ) + ) + .select('title') + .execute(); + expectResults( + results, + { title: 'Pride and Prejudice' }, + { title: 'The Lord of the Rings' }, + { title: "The Handmaid's Tale" } + ); + }); }); describe('sort, offset, and limit stages', () => { @@ -1106,7 +1142,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .select( 'title', - logicalMaximum(Constant.of(1960), Field.of('published')).as( + logicalMaximum(Constant.of(1960), Field.of('published'), 1961).as( 'published-safe' ) ) @@ -1115,12 +1151,32 @@ apiDescribe.only('Pipelines', persistence => { .execute(); expectResults( results, - { title: '1984', 'published-safe': 1960 }, - { title: 'Crime and Punishment', 'published-safe': 1960 }, + { title: '1984', 'published-safe': 1961 }, + { title: 'Crime and Punishment', 'published-safe': 1961 }, { title: 'Dune', 'published-safe': 1965 } ); }); + it('logical min works', async () => { + const results = await randomCol + .pipeline() + .select( + 'title', + logicalMinimum(Constant.of(1960), Field.of('published'), 1961).as( + 'published-safe' + ) + ) + .sort(Field.of('title').ascending()) + .limit(3) + .execute(); + expectResults( + results, + { title: '1984', 'published-safe': 1949 }, + { title: 'Crime and Punishment', 'published-safe': 1866 }, + { title: 'Dune', 'published-safe': 1960 } + ); + }); + it('cond works', async () => { const results = await randomCol .pipeline() @@ -1322,7 +1378,9 @@ apiDescribe.only('Pipelines', persistence => { add(Field.of('rating'), 1).as('ratingPlusOne'), subtract(Field.of('published'), 1900).as('yearsSince1900'), Field.of('rating').multiply(10).as('ratingTimesTen'), - Field.of('rating').divide(2).as('ratingDividedByTwo') + Field.of('rating').divide(2).as('ratingDividedByTwo'), + multiply('rating', 10, 2).as('ratingTimes20'), + add('rating', 1, 2).as('ratingPlus3') ) .limit(1) .execute(); @@ -1330,7 +1388,9 @@ apiDescribe.only('Pipelines', persistence => { ratingPlusOne: 5.2, yearsSince1900: 79, ratingTimesTen: 42, - ratingDividedByTwo: 2.1 + ratingDividedByTwo: 2.1, + ratingTimes20: 84, + ratingPlus3: 7.2 }); }); @@ -1601,7 +1661,7 @@ apiDescribe.only('Pipelines', persistence => { const results = await randomCol .pipeline() .aggregate( - genericFunction('countif', [Field.of('rating').gte(4.5)]).as( + genericFunction('count_if', [Field.of('rating').gte(4.5)]).as( 'countOfBest' ) ) @@ -1820,18 +1880,49 @@ apiDescribe.only('Pipelines', persistence => { }); }); + it.only('supports Substr without length', async () => { + let results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(substr('title', 9).as('of')) + .execute(); + expectResults(results, { + of: 'of the Rings' + }); + results = await randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('title').substr(9).as('of')) + .execute(); + expectResults(results, { + of: 'of the Rings' + }); + }); + it('arrayConcat works', async () => { const results = await randomCol .pipeline() .select( Field.of('tags') - .arrayConcat(['newTag1', 'newTag2']) + .arrayConcat(['newTag1', 'newTag2'], Field.of('tags'), [null]) .as('modifiedTags') ) .limit(1) .execute(); expectResults(results, { - modifiedTags: ['comedy', 'space', 'adventure', 'newTag1', 'newTag2'] + modifiedTags: [ + 'comedy', + 'space', + 'adventure', + 'newTag1', + 'newTag2', + 'comedy', + 'space', + 'adventure', + null + ] }); }); diff --git a/packages/firestore/test/integration/api/query_to_pipeline.test.ts b/packages/firestore/test/integration/api/query_to_pipeline.test.ts index c41ba70425f..878aca4faa7 100644 --- a/packages/firestore/test/integration/api/query_to_pipeline.test.ts +++ b/packages/firestore/test/integration/api/query_to_pipeline.test.ts @@ -54,7 +54,7 @@ setLogLevel('debug'); // This is the Query integration tests from the lite API (no cache support) // with some additional test cases added for more complete coverage. -apiDescribe.only('Query to Pipeline', persistence => { +apiDescribe('Query to Pipeline', persistence => { addEqualityMatcher(); function verifyResults( From b3d1f0cb56a05c2119e6a54fddfdc12f9177400e Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 24 Feb 2025 16:38:51 -0700 Subject: [PATCH 30/75] Fix and implementation. --- packages/firestore/src/core/pipeline-util.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index fbb9c502f54..727f05f6836 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -186,7 +186,11 @@ export function toPipeline(query: Query, db: Firestore): Pipeline { ); if (existsConditions.length > 1) { pipeline = pipeline.where( - andFunction(existsConditions[0], ...existsConditions.slice(1)) + andFunction( + existsConditions[0], + existsConditions[1], + ...existsConditions.slice(2) + ) ); } else { pipeline = pipeline.where(existsConditions[0]); From 6c79ddda4178c28cbf63eef2400a58d8b0d45e3d Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 24 Feb 2025 16:41:22 -0700 Subject: [PATCH 31/75] Refactor AggregateFunction out of Expr --- .../firestore/src/lite-api/expressions.ts | 342 +++++++++++------- packages/firestore/src/lite-api/pipeline.ts | 56 +-- packages/firestore/src/lite-api/stage.ts | 19 +- .../src/lite-api/user_data_reader.ts | 7 +- 4 files changed, 268 insertions(+), 156 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index e0b02526d1f..ada13ffb142 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -37,7 +37,6 @@ import { isString } from '../util/types'; import { Bytes } from './bytes'; import { documentId, FieldPath } from './field_path'; import { GeoPoint } from './geo_point'; -import { Pipeline } from './pipeline'; import { DocumentReference } from './reference'; import { Timestamp } from './timestamp'; import { @@ -1065,7 +1064,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * Field.of("productId").count().as("totalProducts"); * ``` * - * @return A new `Accumulator` representing the 'count' aggregation. + * @return A new `AggregateFunction` representing the 'count' aggregation. */ count(): Count { return new Count(this, false); @@ -1079,7 +1078,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * Field.of("orderAmount").sum().as("totalRevenue"); * ``` * - * @return A new `Accumulator` representing the 'sum' aggregation. + * @return A new `AggregateFunction` representing the 'sum' aggregation. */ sum(): Sum { return new Sum(this, false); @@ -1094,7 +1093,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * Field.of("age").avg().as("averageAge"); * ``` * - * @return A new `Accumulator` representing the 'avg' aggregation. + * @return A new `AggregateFunction` representing the 'avg' aggregation. */ avg(): Avg { return new Avg(this, false); @@ -1108,7 +1107,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * Field.of("price").minimum().as("lowestPrice"); * ``` * - * @return A new `Accumulator` representing the 'min' aggregation. + * @return A new `AggregateFunction` representing the 'min' aggregation. */ minimum(): Minimum { return new Minimum(this, false); @@ -1122,27 +1121,12 @@ export abstract class Expr implements ProtoSerializable, UserData { * Field.of("score").maximum().as("highestScore"); * ``` * - * @return A new `Accumulator` representing the 'max' aggregation. + * @return A new `AggregateFunction` representing the 'max' aggregation. */ maximum(): Maximum { return new Maximum(this, false); } - /** - * Creates an aggregation that finds the count of input documents satisfying - * the conditional expression. - * - * ```typescript - * // Find the count of documents with a score greater than 90 - * Field.of("score").gt(90).countIf().as("highestScore"); - * ``` - * - * @return A new `Accumulator` representing the 'countIf' aggregation. - */ - countIf(): CountIf { - return new CountIf(this); - } - /** * Creates an expression that returns the larger value between this expression and another expression, based on Firestore's value type ordering. * @@ -2069,52 +2053,75 @@ export abstract class Expr implements ProtoSerializable, UserData { * * An interface that represents a selectable expression. */ -export abstract class Selectable extends Expr { - selectable: true = true; - abstract readonly alias: string; +export interface Selectable { + selectable: true; + readonly alias: string; + readonly expr: Expr; } /** * @beta * - * An interface that represents a filter condition. + * An class that represents an aggregate function. */ -export abstract class BooleanExpr extends Expr { - filterable: true = true; -} +export class AggregateFunction + implements ProtoSerializable, UserData +{ + aggregateFunction: true = true; -/** - * @beta - * - * An interface that represents an accumulator. - */ -export abstract class Accumulator extends Expr { - accumulator: true = true; + constructor(private name: string, private params: Expr[]) {} + + /** + * Assigns an alias to this AggregateFunction. The alias specifies the name that + * the aggregated value will have in the output document. + * + * ```typescript + * // Calculate the average price of all items and assign it the alias "averagePrice". + * firestore.pipeline().collection("items") + * .aggregate(Field.of("price").avg().as("averagePrice")); + * ``` + * + * @param name The alias to assign to this AggregateFunction. + * @return A new {@link AggregateFunctionWithAlias} that wraps this + * AggregateFunction and associates it with the provided alias. + */ + as(name: string): AggregateFunctionWithAlias { + return new AggregateFunctionWithAlias(this, name); + } /** * @private * @internal */ - abstract _toProto(serializer: JsonProtoSerializer): ProtoValue; + _toProto(serializer: JsonProtoSerializer): ProtoValue { + return { + functionValue: { + name: this.name, + args: this.params.map(p => p._toProto(serializer)) + } + }; + } + + /** + * @private + * @internal + */ + _readUserData(dataReader: UserDataReader): void { + this.params.forEach(expr => { + return expr._readUserData(dataReader); + }); + } } /** * @beta * - * An accumulator target, which is an expression with an alias that also implements the Accumulator interface. + * An AggregateFunction with alias. */ -export type AccumulatorTarget = ExprWithAlias; - -/** - * @beta - */ -export class ExprWithAlias extends Selectable { - exprType: ExprType = 'ExprWithAlias'; - selectable = true as const; - - constructor(readonly expr: T, readonly alias: string) { - super(); - } +export class AggregateFunctionWithAlias + implements UserData, ProtoSerializable +{ + constructor(readonly expr: AggregateFunction, readonly alias: string) {} /** * @private @@ -2133,6 +2140,24 @@ export class ExprWithAlias extends Selectable { } } +/** + * @beta + */ +export class ExprWithAlias implements Selectable, UserData { + exprType: ExprType = 'ExprWithAlias'; + selectable = true as const; + + constructor(readonly expr: T, readonly alias: string) {} + + /** + * @private + * @internal + */ + _readUserData(dataReader: UserDataReader): void { + this.expr._readUserData(dataReader); + } +} + /** * @internal */ @@ -2182,14 +2207,11 @@ class ListOfExprs extends Expr { * const cityField = Field.of("address.city"); * ``` */ -export class Field extends Selectable { +export class Field extends Expr implements Selectable { exprType: ExprType = 'Field'; selectable = true as const; - private constructor( - private fieldPath: InternalFieldPath, - private pipeline: Pipeline | null = null - ) { + private constructor(private fieldPath: InternalFieldPath) { super(); } @@ -2231,7 +2253,11 @@ export class Field extends Selectable { } get alias(): string { - return this.fieldPath.canonicalString(); + return this.fieldName(); + } + + get expr(): Expr { + return this; } /** @@ -2522,13 +2548,40 @@ export class FirestoreFunction extends Expr { /** * @beta + * + * An interface that represents a filter condition. */ -export class GenericFunction - extends FirestoreFunction - implements BooleanExpr, Accumulator -{ - accumulator: true = true; +export class BooleanExpr extends FirestoreFunction { filterable: true = true; + + /** + * Creates an aggregation that finds the count of input documents satisfying + * this boolean expression. + * + * ```typescript + * // Find the count of documents with a score greater than 90 + * Field.of("score").gt(90).countIf().as("highestScore"); + * ``` + * + * @return A new `AggregateFunction` representing the 'countIf' aggregation. + */ + countIf(): AggregateFunction { + return new CountIf(this); + } + + /** + * Creates an expression that negates this boolean expression. + * + * ```typescript + * // Find documents where the 'tags' field does not contain 'completed' + * Field.of("tags").arrayContains("completed").not(); + * ``` + * + * @return A new {@code Expr} representing the negated filter condition. + */ + not(filter: BooleanExpr): BooleanExpr { + return new Not(filter); + } } /** @@ -2591,7 +2644,7 @@ export class ArrayFunction extends FirestoreFunction { /** * @beta */ -export class Eq extends FirestoreFunction implements BooleanExpr { +export class Eq extends BooleanExpr { constructor(private left: Expr, private right: Expr) { super('eq', [left, right]); } @@ -2602,7 +2655,7 @@ export class Eq extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class Neq extends FirestoreFunction implements BooleanExpr { +export class Neq extends BooleanExpr { constructor(private left: Expr, private right: Expr) { super('neq', [left, right]); } @@ -2613,7 +2666,7 @@ export class Neq extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class Lt extends FirestoreFunction implements BooleanExpr { +export class Lt extends BooleanExpr { constructor(private left: Expr, private right: Expr) { super('lt', [left, right]); } @@ -2624,7 +2677,7 @@ export class Lt extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class Lte extends FirestoreFunction implements BooleanExpr { +export class Lte extends BooleanExpr { constructor(private left: Expr, private right: Expr) { super('lte', [left, right]); } @@ -2635,7 +2688,7 @@ export class Lte extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class Gt extends FirestoreFunction implements BooleanExpr { +export class Gt extends BooleanExpr { constructor(private left: Expr, private right: Expr) { super('gt', [left, right]); } @@ -2646,7 +2699,7 @@ export class Gt extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class Gte extends FirestoreFunction implements BooleanExpr { +export class Gte extends BooleanExpr { constructor(private left: Expr, private right: Expr) { super('gte', [left, right]); } @@ -2675,7 +2728,7 @@ export class ArrayReverse extends FirestoreFunction { /** * @beta */ -export class ArrayContains extends FirestoreFunction implements BooleanExpr { +export class ArrayContains extends BooleanExpr { constructor(private array: Expr, private element: Expr) { super('array_contains', [array, element]); } @@ -2686,7 +2739,7 @@ export class ArrayContains extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class ArrayContainsAll extends FirestoreFunction implements BooleanExpr { +export class ArrayContainsAll extends BooleanExpr { constructor(private array: Expr, private values: Expr[]) { super('array_contains_all', [array, new ListOfExprs(values)]); } @@ -2697,7 +2750,7 @@ export class ArrayContainsAll extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class ArrayContainsAny extends FirestoreFunction implements BooleanExpr { +export class ArrayContainsAny extends BooleanExpr { constructor(private array: Expr, private values: Expr[]) { super('array_contains_any', [array, new ListOfExprs(values)]); } @@ -2726,7 +2779,7 @@ export class ArrayElement extends FirestoreFunction { /** * @beta */ -export class EqAny extends FirestoreFunction implements BooleanExpr { +export class EqAny extends BooleanExpr { constructor(private left: Expr, private others: Expr[]) { super('eq_any', [left, new ListOfExprs(others)]); } @@ -2737,7 +2790,7 @@ export class EqAny extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class NotEqAny extends FirestoreFunction implements BooleanExpr { +export class NotEqAny extends BooleanExpr { constructor(private left: Expr, private others: Expr[]) { super('not_eq_any', [left, new ListOfExprs(others)]); } @@ -2748,7 +2801,7 @@ export class NotEqAny extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class IsNan extends FirestoreFunction implements BooleanExpr { +export class IsNan extends BooleanExpr { constructor(private expr: Expr) { super('is_nan', [expr]); } @@ -2759,7 +2812,7 @@ export class IsNan extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class Exists extends FirestoreFunction implements BooleanExpr { +export class Exists extends BooleanExpr { constructor(private expr: Expr) { super('exists', [expr]); } @@ -2770,7 +2823,7 @@ export class Exists extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class Not extends FirestoreFunction implements BooleanExpr { +export class Not extends BooleanExpr { constructor(private expr: Expr) { super('not', [expr]); } @@ -2781,7 +2834,7 @@ export class Not extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class And extends FirestoreFunction implements BooleanExpr { +export class And extends BooleanExpr { constructor(private conditions: BooleanExpr[]) { super('and', conditions); } @@ -2792,7 +2845,7 @@ export class And extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class Or extends FirestoreFunction implements BooleanExpr { +export class Or extends BooleanExpr { constructor(private conditions: BooleanExpr[]) { super('or', conditions); } @@ -2803,7 +2856,7 @@ export class Or extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class Xor extends FirestoreFunction implements BooleanExpr { +export class Xor extends BooleanExpr { constructor(private conditions: BooleanExpr[]) { super('xor', conditions); } @@ -2840,7 +2893,7 @@ export class LogicalMaximum extends FirestoreFunction { */ export class LogicalMinimum extends FirestoreFunction { constructor(first: Expr, others: Expr[]) { - super('logical_minimum', [first, ...others]); + super('logical_min', [first, ...others]); } } @@ -2892,7 +2945,7 @@ export class ByteLength extends FirestoreFunction { /** * @beta */ -export class Like extends FirestoreFunction implements BooleanExpr { +export class Like extends BooleanExpr { constructor(private expr: Expr, private pattern: Expr) { super('like', [expr, pattern]); } @@ -2903,7 +2956,7 @@ export class Like extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class RegexContains extends FirestoreFunction implements BooleanExpr { +export class RegexContains extends BooleanExpr { constructor(private expr: Expr, private pattern: Expr) { super('regex_contains', [expr, pattern]); } @@ -2914,7 +2967,7 @@ export class RegexContains extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class RegexMatch extends FirestoreFunction implements BooleanExpr { +export class RegexMatch extends BooleanExpr { constructor(private expr: Expr, private pattern: Expr) { super('regex_match', [expr, pattern]); } @@ -2925,7 +2978,7 @@ export class RegexMatch extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class StrContains extends FirestoreFunction implements BooleanExpr { +export class StrContains extends BooleanExpr { constructor(private expr: Expr, private substring: Expr) { super('str_contains', [expr, substring]); } @@ -2936,7 +2989,7 @@ export class StrContains extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class StartsWith extends FirestoreFunction implements BooleanExpr { +export class StartsWith extends BooleanExpr { constructor(private expr: Expr, private prefix: Expr) { super('starts_with', [expr, prefix]); } @@ -2947,7 +3000,7 @@ export class StartsWith extends FirestoreFunction implements BooleanExpr { /** * @beta */ -export class EndsWith extends FirestoreFunction implements BooleanExpr { +export class EndsWith extends BooleanExpr { constructor(private expr: Expr, private suffix: Expr) { super('ends_with', [expr, suffix]); } @@ -3003,8 +3056,8 @@ export class MapGet extends FirestoreFunction { /** * @beta */ -export class Count extends FirestoreFunction implements Accumulator { - accumulator = true as const; +export class Count extends AggregateFunction { + aggregateFunction = true as const; constructor(private value: Expr | undefined, private distinct: boolean) { super('count', value === undefined ? [] : [value]); @@ -3014,8 +3067,8 @@ export class Count extends FirestoreFunction implements Accumulator { /** * @beta */ -export class Sum extends FirestoreFunction implements Accumulator { - accumulator = true as const; +export class Sum extends AggregateFunction { + aggregateFunction = true as const; constructor(private value: Expr, private distinct: boolean) { super('sum', [value]); @@ -3025,8 +3078,8 @@ export class Sum extends FirestoreFunction implements Accumulator { /** * @beta */ -export class Avg extends FirestoreFunction implements Accumulator { - accumulator = true as const; +export class Avg extends AggregateFunction { + aggregateFunction = true as const; constructor(private value: Expr, private distinct: boolean) { super('avg', [value]); @@ -3036,8 +3089,8 @@ export class Avg extends FirestoreFunction implements Accumulator { /** * @beta */ -export class Minimum extends FirestoreFunction implements Accumulator { - accumulator = true as const; +export class Minimum extends AggregateFunction { + aggregateFunction = true as const; constructor(private value: Expr, private distinct: boolean) { super('minimum', [value]); @@ -3047,8 +3100,8 @@ export class Minimum extends FirestoreFunction implements Accumulator { /** * @beta */ -export class Maximum extends FirestoreFunction implements Accumulator { - accumulator = true as const; +export class Maximum extends AggregateFunction { + aggregateFunction = true as const; constructor(private value: Expr, private distinct: boolean) { super('maximum', [value]); @@ -3174,12 +3227,12 @@ export class TimestampSub extends FirestoreFunction { /** * @beta */ -export class CountIf extends FirestoreFunction implements Accumulator { - constructor(private booleanExpr: Expr) { +export class CountIf extends AggregateFunction { + constructor(private booleanExpr: BooleanExpr) { super('count_if', [booleanExpr]); } - accumulator = true as const; + aggregateFunction = true as const; } /** @@ -3193,7 +3246,7 @@ export class CountIf extends FirestoreFunction implements Accumulator { * ``` * * @param booleanExpr - The boolean expression to evaluate on each input. - * @returns A new `Accumulator` representing the 'countif' aggregation. + * @returns A new `AggregateFunction` representing the 'countif' aggregation. */ export function countIf(booleanExpr: BooleanExpr): CountIf { return new CountIf(booleanExpr); @@ -3765,7 +3818,7 @@ export function currentContext(): CurrentContext { /** * @beta */ -export class IsError extends FirestoreFunction implements BooleanExpr { +export class IsError extends BooleanExpr { constructor(private expr: Expr) { super('is_error', [expr]); } @@ -3843,7 +3896,7 @@ export function ifError(tryExpr: Expr, catchValue: any): IfError { /** * @beta */ -export class IsAbsent extends FirestoreFunction implements BooleanExpr { +export class IsAbsent extends BooleanExpr { constructor(private expr: Expr) { super('is_absent', [expr]); } @@ -3889,7 +3942,7 @@ export function isAbsent(value: Expr | string): IsAbsent { /** * @beta */ -export class IsNull extends FirestoreFunction implements BooleanExpr { +export class IsNull extends BooleanExpr { constructor(private expr: Expr) { super('is_null', [expr]); } @@ -3933,7 +3986,7 @@ export function isNull(value: Expr | string): IsNull { /** * @beta */ -export class IsNotNull extends FirestoreFunction implements BooleanExpr { +export class IsNotNull extends BooleanExpr { constructor(private expr: Expr) { super('is_not_null', [expr]); } @@ -3977,7 +4030,7 @@ export function isNotNull(value: Expr | string): IsNotNull { /** * @beta */ -export class IsNotNan extends FirestoreFunction implements BooleanExpr { +export class IsNotNan extends BooleanExpr { constructor(private expr: Expr) { super('is_not_nan', [expr]); } @@ -4168,11 +4221,13 @@ export class Parent extends FirestoreFunction { } } -export function parent(path: string | DocumentReference): Parent; +export function parentFunction(path: string | DocumentReference): Parent; -export function parent(pathExpr: Expr): Parent; +export function parentFunction(pathExpr: Expr): Parent; -export function parent(path: Expr | string | DocumentReference): Parent { +export function parentFunction( + path: Expr | string | DocumentReference +): Parent { // @ts-ignore const pathExpr = valueToDefaultExpr(path); return new Parent(pathExpr); @@ -7203,7 +7258,7 @@ export function mapGet(fieldOrExpr: string | Expr, subField: string): MapGet { * countAll().as("totalUsers"); * ``` * - * @return A new {@code Accumulator} representing the 'countAll' aggregation. + * @return A new {@code AggregateFunction} representing the 'countAll' aggregation. */ export function countAll(): Count { return new Count(undefined, false); @@ -7221,7 +7276,7 @@ export function countAll(): Count { * ``` * * @param value The expression to count. - * @return A new {@code Accumulator} representing the 'count' aggregation. + * @return A new {@code AggregateFunction} representing the 'count' aggregation. */ export function countFunction(value: Expr): Count; @@ -7235,7 +7290,7 @@ export function countFunction(value: Expr): Count; * ``` * * @param value The name of the field to count. - * @return A new {@code Accumulator} representing the 'count' aggregation. + * @return A new {@code AggregateFunction} representing the 'count' aggregation. */ export function countFunction(value: string): Count; export function countFunction(value: Expr | string): Count { @@ -7255,7 +7310,7 @@ export function countFunction(value: Expr | string): Count { * ``` * * @param value The expression to sum up. - * @return A new {@code Accumulator} representing the 'sum' aggregation. + * @return A new {@code AggregateFunction} representing the 'sum' aggregation. */ export function sumFunction(value: Expr): Sum; @@ -7271,7 +7326,7 @@ export function sumFunction(value: Expr): Sum; * ``` * * @param value The name of the field containing numeric values to sum up. - * @return A new {@code Accumulator} representing the 'sum' aggregation. + * @return A new {@code AggregateFunction} representing the 'sum' aggregation. */ export function sumFunction(value: string): Sum; export function sumFunction(value: Expr | string): Sum { @@ -7291,7 +7346,7 @@ export function sumFunction(value: Expr | string): Sum { * ``` * * @param value The expression representing the values to average. - * @return A new {@code Accumulator} representing the 'avg' aggregation. + * @return A new {@code AggregateFunction} representing the 'avg' aggregation. */ export function avgFunction(value: Expr): Avg; @@ -7307,7 +7362,7 @@ export function avgFunction(value: Expr): Avg; * ``` * * @param value The name of the field containing numeric values to average. - * @return A new {@code Accumulator} representing the 'avg' aggregation. + * @return A new {@code AggregateFunction} representing the 'avg' aggregation. */ export function avgFunction(value: string): Avg; export function avgFunction(value: Expr | string): Avg { @@ -7327,7 +7382,7 @@ export function avgFunction(value: Expr | string): Avg { * ``` * * @param value The expression to find the minimum value of. - * @return A new {@code Accumulator} representing the 'min' aggregation. + * @return A new {@code AggregateFunction} representing the 'min' aggregation. */ export function minimum(value: Expr): Minimum; @@ -7342,7 +7397,7 @@ export function minimum(value: Expr): Minimum; * ``` * * @param value The name of the field to find the minimum value of. - * @return A new {@code Accumulator} representing the 'min' aggregation. + * @return A new {@code AggregateFunction} representing the 'min' aggregation. */ export function minimum(value: string): Minimum; export function minimum(value: Expr | string): Minimum { @@ -7362,7 +7417,7 @@ export function minimum(value: Expr | string): Minimum { * ``` * * @param value The expression to find the maximum value of. - * @return A new {@code Accumulator} representing the 'max' aggregation. + * @return A new {@code AggregateFunction} representing the 'max' aggregation. */ export function maximum(value: Expr): Maximum; @@ -7377,7 +7432,7 @@ export function maximum(value: Expr): Maximum; * ``` * * @param value The name of the field to find the maximum value of. - * @return A new {@code Accumulator} representing the 'max' aggregation. + * @return A new {@code AggregateFunction} representing the 'max' aggregation. */ export function maximum(value: string): Maximum; export function maximum(value: Expr | string): Maximum { @@ -8147,20 +8202,61 @@ export function timestampSub( * Creates functions that work on the backend but do not exist in the SDK yet. * * ```typescript - * // Call a user defined function named "myFunc" with the arguments 10 and 20 - * // This is the same of the 'sum(Field.of("price"))', if it did not exist + * // This is the same of the 'sum(Field.of("price"))', if it was not yet implemented in the SDK. * genericFunction("sum", [Field.of("price")]); * ``` * - * @param functionName The name of the user defined function. + * @param functionName The name of the server function. * @param params The arguments to pass to the function. - * @return A new {@code GenericFucntion} representing the function call. + * @return A new {@code FirestoreFunction} representing the function call. */ export function genericFunction( functionName: string, params: any[] -): GenericFunction { - return new GenericFunction(functionName, params.map(valueToDefaultExpr)); +): FirestoreFunction { + return new FirestoreFunction(functionName, params.map(valueToDefaultExpr)); +} + +/** + * @beta + * + * Creates a boolean expression that works on the backend but does not exist in the SDK yet. + * + * ```typescript + * // This is the same of the 'eq("price", 10)', if it was not yet implemented in the SDK. + * genericFunction("eq", [Field.of("price"), Constant.of(10)]); + * ``` + * + * @param functionName The name of the server boolean expression. + * @param params The arguments to pass to the boolean expression. + * @return A new {@code BooleanExpr} representing the function call. + */ +export function genericBooleanExpr( + functionName: string, + params: any[] +): BooleanExpr { + return new BooleanExpr(functionName, params.map(valueToDefaultExpr)); +} + +/** + * @beta + * + * Creates a boolean expression that works on the backend but does not exist in the SDK yet. + * + * ```typescript + * // This is the same of the 'eq("price", 10)', if it was not yet implemented in the SDK. + * genericFunction("eq", [Field.of("price"), Constant.of(10)]); + * ``` + * + * @param functionName The name of the server boolean expression. + * @param params The arguments to pass to the boolean expression. + * @return A new {@code BooleanExpr} representing the function call. + */ +export function genericAggregateFunction( + functionName: string, + params: any[] +): AggregateFunction { + return new AggregateFunction(functionName, params.map(valueToDefaultExpr)); } /** diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index 433c2b6976c..d642df22739 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -20,7 +20,8 @@ import { ObjectValue } from '../model/object_value'; import { Pipeline as ProtoPipeline, - Stage as ProtoStage + Stage as ProtoStage, + Value as ProtoValue } from '../protos/firestore_proto_api'; import { invokeExecutePipeline } from '../remote/datastore'; import { JsonProtoSerializer, ProtoSerializable } from '../remote/serializer'; @@ -30,8 +31,8 @@ import { getDatastore } from './components'; import { Firestore } from './database'; import { _mapValue, - Accumulator, - AccumulatorTarget, + AggregateFunction, + AggregateFunctionWithAlias, Constant, Expr, ExprWithAlias, @@ -385,8 +386,8 @@ export class Pipeline implements ProtoSerializable { * Performs aggregation operations on the documents from previous stages. * *

    This stage allows you to calculate aggregate values over a set of documents. You define the - * aggregations to perform using {@link AccumulatorTarget} expressions which are typically results of - * calling {@link Expr#as} on {@link Accumulator} instances. + * aggregations to perform using {@link AggregateFunctionWithAlias} expressions which are typically results of + * calling {@link Expr#as} on {@link AggregateFunction} instances. * *

    Example: * @@ -399,11 +400,11 @@ export class Pipeline implements ProtoSerializable { * ); * ``` * - * @param accumulators The {@link AccumulatorTarget} expressions, each wrapping an {@link Accumulator} + * @param accumulators The {@link AggregateFunctionWithAlias} expressions, each wrapping an {@link AggregateFunction} * and provide a name for the accumulated results. * @return A new Pipeline object with this stage appended to the stage list. */ - aggregate(...accumulators: AccumulatorTarget[]): Pipeline; + aggregate(...accumulators: AggregateFunctionWithAlias[]): Pipeline; /** * Performs optionally grouped aggregation operations on the documents from previous stages. * @@ -416,8 +417,8 @@ export class Pipeline implements ProtoSerializable { * If no grouping fields are provided, a single group containing all documents is used. Not * specifying groups is the same as putting the entire inputs into one group.

  • *
  • **Accumulators:** One or more accumulation operations to perform within each group. These - * are defined using {@link AccumulatorTarget} expressions, which are typically created by - * calling {@link Expr#as} on {@link Accumulator} instances. Each aggregation + * are defined using {@link AggregateFunctionWithAlias} expressions, which are typically created by + * calling {@link Expr#as} on {@link AggregateFunction} instances. Each aggregation * calculates a value (e.g., sum, average, count) based on the documents within its group.
  • *
* @@ -438,29 +439,31 @@ export class Pipeline implements ProtoSerializable { * list. */ aggregate(options: { - accumulators: AccumulatorTarget[]; + accumulators: AggregateFunctionWithAlias[]; groups?: Array; }): Pipeline; aggregate( optionsOrTarget: - | AccumulatorTarget + | AggregateFunctionWithAlias | { - accumulators: AccumulatorTarget[]; + accumulators: AggregateFunctionWithAlias[]; groups?: Array; }, - ...rest: AccumulatorTarget[] + ...rest: AggregateFunctionWithAlias[] ): Pipeline { if ('accumulators' in optionsOrTarget) { return this._addStage( new Aggregate( - new Map( - optionsOrTarget.accumulators.map((target: AccumulatorTarget) => [ - (target as unknown as AccumulatorTarget).alias, - this.readUserData( - 'aggregate', - (target as unknown as AccumulatorTarget).expr - ) - ]) + new Map( + optionsOrTarget.accumulators.map( + (target: AggregateFunctionWithAlias) => [ + (target as unknown as AggregateFunctionWithAlias).alias, + this.readUserData( + 'aggregate', + (target as unknown as AggregateFunctionWithAlias).expr + ) + ] + ) ), this.readUserData( 'aggregate', @@ -471,12 +474,12 @@ export class Pipeline implements ProtoSerializable { } else { return this._addStage( new Aggregate( - new Map( + new Map( [optionsOrTarget, ...rest].map(target => [ - (target as unknown as AccumulatorTarget).alias, + (target as unknown as AggregateFunctionWithAlias).alias, this.readUserData( 'aggregate', - (target as unknown as AccumulatorTarget).expr + (target as unknown as AggregateFunctionWithAlias).expr ) ]) ), @@ -740,7 +743,7 @@ export class Pipeline implements ProtoSerializable { // this is unlike the default conversion for objects and arrays // passed to an expression. const expressionParams = params.map((value: any) => { - if (value instanceof Expr) { + if (value instanceof Expr || value instanceof AggregateFunction) { return value; } else if (isPlainObject(value)) { return _mapValue(value); @@ -890,8 +893,7 @@ export class Pipeline implements ProtoSerializable { db: Firestore, userDataReader: UserDataReader, userDataWriter: AbstractUserDataWriter, - stages: Stage[], - converter: unknown = {} + stages: Stage[] ): Pipeline { return new Pipeline(db, userDataReader, userDataWriter, stages); } diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index 2562777a4da..de18556b730 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -30,7 +30,13 @@ import { } from '../remote/serializer'; import { hardAssert } from '../util/assert'; -import { Accumulator, Expr, Field, BooleanExpr, Ordering } from './expressions'; +import { + AggregateFunction, + Expr, + Field, + BooleanExpr, + Ordering +} from './expressions'; import { Pipeline } from './pipeline'; import { DocumentReference } from './reference'; import { VectorValue } from './vector_value'; @@ -89,7 +95,7 @@ export class Aggregate implements Stage { name = 'aggregate'; constructor( - private accumulators: Map, + private accumulators: Map, private groups: Map ) {} @@ -481,7 +487,14 @@ export class Replace implements Stage { * @beta */ export class GenericStage implements Stage { - constructor(public name: string, private params: Expr[]) {} + /** + * @private + * @internal + */ + constructor( + public name: string, + private params: Array> + ) {} /** * @internal diff --git a/packages/firestore/src/lite-api/user_data_reader.ts b/packages/firestore/src/lite-api/user_data_reader.ts index 7d24482c95e..d6f4093f882 100644 --- a/packages/firestore/src/lite-api/user_data_reader.ts +++ b/packages/firestore/src/lite-api/user_data_reader.ts @@ -65,7 +65,7 @@ import { Dict, forEach, isEmpty } from '../util/obj'; import { Bytes } from './bytes'; import { Firestore } from './database'; -import { Expr } from './expressions'; +import { Expr, AggregateFunction } from './expressions'; import { FieldPath } from './field_path'; import { FieldValue } from './field_value'; import { GeoPoint } from './geo_point'; @@ -910,7 +910,7 @@ export function parseScalarValue( }; } else if (value instanceof VectorValue) { return parseVectorValue(value, context); - } else if (value instanceof Expr) { + } else if (value instanceof Expr || value instanceof AggregateFunction) { return value._toProto(context.serializer); } else { throw context.createError( @@ -970,7 +970,8 @@ export function looksLikeJsonObject(input: unknown): boolean { !(input instanceof DocumentReference) && !(input instanceof FieldValue) && !(input instanceof VectorValue) && - !(input instanceof Expr) + !(input instanceof Expr) && + !(input instanceof AggregateFunction) ); } From c4593b5ec05c939b9d5201d03ace8ea07d5c6676 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:00:40 -0700 Subject: [PATCH 32/75] Add ScalarExpr class and make Expr a base class of AggregateFunction --- .../firestore/src/lite-api/expressions.ts | 1333 ++++++++++------- packages/firestore/src/lite-api/pipeline.ts | 35 +- packages/firestore/src/lite-api/stage.ts | 18 +- .../src/lite-api/user_data_reader.ts | 7 +- 4 files changed, 789 insertions(+), 604 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index ada13ffb142..f1e31a3ed4d 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -56,6 +56,7 @@ export type ExprType = | 'Field' | 'Constant' | 'Function' + | 'AggregateFunction' | 'ListOfExprs' | 'ExprWithAlias'; @@ -67,8 +68,8 @@ export type ExprType = * @internal * @param value */ -function valueToDefaultExpr(value: any): Expr { - if (value instanceof Expr) { +function valueToDefaultExpr(value: any): ScalarExpr { + if (value instanceof ScalarExpr) { return value; } else if (isPlainObject(value)) { return map(value); @@ -89,7 +90,7 @@ function valueToDefaultExpr(value: any): Expr { * @internal * @param value */ -function fieldOfOrExpr(value: any): Expr { +function fieldOfOrExpr(value: any): ScalarExpr { if (isString(value)) { return Field.of(value); } else { @@ -117,6 +118,37 @@ function fieldOfOrExpr(value: any): Expr { export abstract class Expr implements ProtoSerializable, UserData { abstract exprType: ExprType; + /** + * @private + * @internal + */ + abstract _toProto(serializer: JsonProtoSerializer): ProtoValue; + + /** + * @private + * @internal + */ + abstract _readUserData(dataReader: UserDataReader): void; +} + +/** + * @beta + * + * Represents an expression that can be evaluated to a value within the execution of a {@link + * Pipeline}. + * + * Expressions are the building blocks for creating complex queries and transformations in + * Firestore pipelines. They can represent: + * + * - **Field references:** Access values from document fields. + * - **Literals:** Represent constant values (strings, numbers, booleans). + * - **Function calls:** Apply functions to one or more expressions. + * - **Aggregations:** Calculate aggregate values (e.g., sum, average) over a set of documents. + * + * The `Expr` class provides a fluent API for building expressions. You can chain together + * method calls to create complex expressions. + */ +export abstract class ScalarExpr extends Expr { /** * Creates an expression that adds this expression to another expression. * @@ -129,7 +161,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param others Optional additional expressions or literals to add to this expression. * @return A new `Expr` representing the addition operation. */ - add(second: Expr | any, ...others: Array): Add { + add(second: ScalarExpr | any, ...others: Array): Add { const values = [second, ...others]; return new Add( this, @@ -148,7 +180,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The expression to subtract from this expression. * @return A new `Expr` representing the subtraction operation. */ - subtract(other: Expr): Subtract; + subtract(other: ScalarExpr): Subtract; /** * Creates an expression that subtracts a constant value from this expression. @@ -178,7 +210,10 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param others Optional additional expressions or literals to multiply by. * @return A new `Expr` representing the multiplication operation. */ - multiply(second: Expr | any, ...others: Array): Multiply { + multiply( + second: ScalarExpr | any, + ...others: Array + ): Multiply { const values = [second, ...others]; return new Multiply( this, @@ -197,7 +232,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The expression to divide by. * @return A new `Expr` representing the division operation. */ - divide(other: Expr): Divide; + divide(other: ScalarExpr): Divide; /** * Creates an expression that divides this expression by a constant value. @@ -226,7 +261,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The expression to divide by. * @return A new `Expr` representing the modulo operation. */ - mod(other: Expr): Mod; + mod(other: ScalarExpr): Mod; /** * Creates an expression that calculates the modulo (remainder) of dividing this expression by a constant value. @@ -255,7 +290,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The expression to compare for equality. * @return A new `Expr` representing the equality comparison. */ - eq(other: Expr): Eq; + eq(other: ScalarExpr): Eq; /** * Creates an expression that checks if this expression is equal to a constant value. @@ -284,7 +319,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The expression to compare for inequality. * @return A new `Expr` representing the inequality comparison. */ - neq(other: Expr): Neq; + neq(other: ScalarExpr): Neq; /** * Creates an expression that checks if this expression is not equal to a constant value. @@ -313,7 +348,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The expression to compare for less than. * @return A new `Expr` representing the less than comparison. */ - lt(other: Expr): Lt; + lt(other: ScalarExpr): Lt; /** * Creates an expression that checks if this expression is less than a constant value. @@ -343,7 +378,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The expression to compare for less than or equal to. * @return A new `Expr` representing the less than or equal to comparison. */ - lte(other: Expr): Lte; + lte(other: ScalarExpr): Lte; /** * Creates an expression that checks if this expression is less than or equal to a constant value. @@ -372,7 +407,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The expression to compare for greater than. * @return A new `Expr` representing the greater than comparison. */ - gt(other: Expr): Gt; + gt(other: ScalarExpr): Gt; /** * Creates an expression that checks if this expression is greater than a constant value. @@ -402,7 +437,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The expression to compare for greater than or equal to. * @return A new `Expr` representing the greater than or equal to comparison. */ - gte(other: Expr): Gte; + gte(other: ScalarExpr): Gte; /** * Creates an expression that checks if this expression is greater than or equal to a constant @@ -433,8 +468,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * @return A new `Expr` representing the concatenated array. */ arrayConcat( - secondArray: Expr | any[], - ...otherArrays: Array + secondArray: ScalarExpr | any[], + ...otherArrays: Array ): ArrayConcat { const elements = [secondArray, ...otherArrays]; const exprValues = elements.map(value => valueToDefaultExpr(value)); @@ -452,7 +487,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param element The element to search for in the array. * @return A new `Expr` representing the 'array_contains' comparison. */ - arrayContains(element: Expr): ArrayContains; + arrayContains(element: ScalarExpr): ArrayContains; /** * Creates an expression that checks if an array contains a specific value. @@ -481,7 +516,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param values The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_all' comparison. */ - arrayContainsAll(...values: Expr[]): ArrayContainsAll; + arrayContainsAll(...values: ScalarExpr[]): ArrayContainsAll; /** * Creates an expression that checks if an array contains all the specified elements. @@ -497,7 +532,7 @@ export abstract class Expr implements ProtoSerializable, UserData { arrayContainsAll(...values: any[]): ArrayContainsAll; arrayContainsAll(...values: any[]): ArrayContainsAll { const exprValues = values.map(value => - value instanceof Expr ? value : valueToDefaultExpr(value) + value instanceof ScalarExpr ? value : valueToDefaultExpr(value) ); return new ArrayContainsAll(this, exprValues); } @@ -513,7 +548,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param values The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_any' comparison. */ - arrayContainsAny(...values: Expr[]): ArrayContainsAny; + arrayContainsAny(...values: ScalarExpr[]): ArrayContainsAny; /** * Creates an expression that checks if an array contains any of the specified elements. @@ -530,7 +565,7 @@ export abstract class Expr implements ProtoSerializable, UserData { arrayContainsAny(...values: any[]): ArrayContainsAny; arrayContainsAny(...values: any[]): ArrayContainsAny { const exprValues = values.map(value => - value instanceof Expr ? value : valueToDefaultExpr(value) + value instanceof ScalarExpr ? value : valueToDefaultExpr(value) ); return new ArrayContainsAny(this, exprValues); } @@ -561,7 +596,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param others The values or expressions to check against. * @return A new `Expr` representing the 'IN' comparison. */ - eqAny(...others: Expr[]): EqAny; + eqAny(...others: ScalarExpr[]): EqAny; /** * Creates an expression that checks if this expression is equal to any of the provided values or @@ -578,7 +613,7 @@ export abstract class Expr implements ProtoSerializable, UserData { eqAny(...others: any[]): EqAny; eqAny(...others: any[]): EqAny { const exprOthers = others.map(other => - other instanceof Expr ? other : valueToDefaultExpr(other) + other instanceof ScalarExpr ? other : valueToDefaultExpr(other) ); return new EqAny(this, exprOthers); } @@ -595,7 +630,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param others The values or expressions to check against. * @return A new `Expr` representing the 'NotEqAny' comparison. */ - notEqAny(...others: Expr[]): NotEqAny; + notEqAny(...others: ScalarExpr[]): NotEqAny; /** * Creates an expression that checks if this expression is not equal to any of the provided values or @@ -612,7 +647,7 @@ export abstract class Expr implements ProtoSerializable, UserData { notEqAny(...others: any[]): NotEqAny; notEqAny(...others: any[]): NotEqAny { const exprOthers = others.map(other => - other instanceof Expr ? other : valueToDefaultExpr(other) + other instanceof ScalarExpr ? other : valueToDefaultExpr(other) ); return new NotEqAny(this, exprOthers); } @@ -697,12 +732,12 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new `Expr` representing the 'like' comparison. */ - like(pattern: Expr): Like; - like(stringOrExpr: string | Expr): Like { + like(pattern: ScalarExpr): Like; + like(stringOrExpr: string | ScalarExpr): Like { if (typeof stringOrExpr === 'string') { return new Like(this, Constant.of(stringOrExpr)); } - return new Like(this, stringOrExpr as Expr); + return new Like(this, stringOrExpr as ScalarExpr); } /** @@ -731,12 +766,12 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param pattern The regular expression to use for the search. * @return A new `Expr` representing the 'contains' comparison. */ - regexContains(pattern: Expr): RegexContains; - regexContains(stringOrExpr: string | Expr): RegexContains { + regexContains(pattern: ScalarExpr): RegexContains; + regexContains(stringOrExpr: string | ScalarExpr): RegexContains { if (typeof stringOrExpr === 'string') { return new RegexContains(this, Constant.of(stringOrExpr)); } - return new RegexContains(this, stringOrExpr as Expr); + return new RegexContains(this, stringOrExpr as ScalarExpr); } /** @@ -763,12 +798,12 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param pattern The regular expression to use for the match. * @return A new `Expr` representing the regular expression match. */ - regexMatch(pattern: Expr): RegexMatch; - regexMatch(stringOrExpr: string | Expr): RegexMatch { + regexMatch(pattern: ScalarExpr): RegexMatch; + regexMatch(stringOrExpr: string | ScalarExpr): RegexMatch { if (typeof stringOrExpr === 'string') { return new RegexMatch(this, Constant.of(stringOrExpr)); } - return new RegexMatch(this, stringOrExpr as Expr); + return new RegexMatch(this, stringOrExpr as ScalarExpr); } /** @@ -795,12 +830,12 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param expr The expression representing the substring to search for. * @return A new `Expr` representing the 'contains' comparison. */ - strContains(expr: Expr): StrContains; - strContains(stringOrExpr: string | Expr): StrContains { + strContains(expr: ScalarExpr): StrContains; + strContains(stringOrExpr: string | ScalarExpr): StrContains { if (typeof stringOrExpr === 'string') { return new StrContains(this, Constant.of(stringOrExpr)); } - return new StrContains(this, stringOrExpr as Expr); + return new StrContains(this, stringOrExpr as ScalarExpr); } /** @@ -828,12 +863,12 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param prefix The prefix expression to check for. * @return A new `Expr` representing the 'starts with' comparison. */ - startsWith(prefix: Expr): StartsWith; - startsWith(stringOrExpr: string | Expr): StartsWith { + startsWith(prefix: ScalarExpr): StartsWith; + startsWith(stringOrExpr: string | ScalarExpr): StartsWith { if (typeof stringOrExpr === 'string') { return new StartsWith(this, Constant.of(stringOrExpr)); } - return new StartsWith(this, stringOrExpr as Expr); + return new StartsWith(this, stringOrExpr as ScalarExpr); } /** @@ -861,12 +896,12 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param suffix The postfix expression to check for. * @return A new `Expr` representing the 'ends with' comparison. */ - endsWith(suffix: Expr): EndsWith; - endsWith(stringOrExpr: string | Expr): EndsWith { + endsWith(suffix: ScalarExpr): EndsWith; + endsWith(stringOrExpr: string | ScalarExpr): EndsWith { if (typeof stringOrExpr === 'string') { return new EndsWith(this, Constant.of(stringOrExpr)); } - return new EndsWith(this, stringOrExpr as Expr); + return new EndsWith(this, stringOrExpr as ScalarExpr); } /** @@ -924,12 +959,12 @@ export abstract class Expr implements ProtoSerializable, UserData { * @return A new `Expr` representing the concatenated string. */ strConcat( - secondString: Expr | string, - ...otherStrings: Array + secondString: ScalarExpr | string, + ...otherStrings: Array ): StrConcat { const elements = [secondString, ...otherStrings]; const exprs = elements.map(e => - typeof e === 'string' ? Constant.of(e) : (e as Expr) + typeof e === 'string' ? Constant.of(e) : (e as ScalarExpr) ); return new StrConcat(this, exprs); } @@ -975,15 +1010,18 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param replace The expression representing the substring to replace the first occurrence of 'find' with. * @return A new {@code Expr} representing the string with the first occurrence replaced. */ - replaceFirst(find: Expr, replace: Expr): ReplaceFirst; - replaceFirst(find: Expr | string, replace: Expr | string): ReplaceFirst { + replaceFirst(find: ScalarExpr, replace: ScalarExpr): ReplaceFirst; + replaceFirst( + find: ScalarExpr | string, + replace: ScalarExpr | string + ): ReplaceFirst { const normalizedFind = typeof find === 'string' ? Constant.of(find) : find; const normalizedReplace = typeof replace === 'string' ? Constant.of(replace) : replace; return new ReplaceFirst( this, - normalizedFind as Expr, - normalizedReplace as Expr + normalizedFind as ScalarExpr, + normalizedReplace as ScalarExpr ); } @@ -1014,15 +1052,18 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param replace The expression representing the substring to replace all occurrences of 'find' with. * @return A new {@code Expr} representing the string with all occurrences replaced. */ - replaceAll(find: Expr, replace: Expr): ReplaceAll; - replaceAll(find: Expr | string, replace: Expr | string): ReplaceAll { + replaceAll(find: ScalarExpr, replace: ScalarExpr): ReplaceAll; + replaceAll( + find: ScalarExpr | string, + replace: ScalarExpr | string + ): ReplaceAll { const normalizedFind = typeof find === 'string' ? Constant.of(find) : find; const normalizedReplace = typeof replace === 'string' ? Constant.of(replace) : replace; return new ReplaceAll( this, - normalizedFind as Expr, - normalizedReplace as Expr + normalizedFind as ScalarExpr, + normalizedReplace as ScalarExpr ); } @@ -1140,8 +1181,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * @return A new {@code Expr} representing the logical max operation. */ logicalMaximum( - second: Expr | any, - ...others: Array + second: ScalarExpr | any, + ...others: Array ): LogicalMaximum { const values = [second, ...others]; return new LogicalMaximum( @@ -1163,8 +1204,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * @return A new {@code Expr} representing the logical min operation. */ logicalMinimum( - second: Expr | any, - ...others: Array + second: ScalarExpr | any, + ...others: Array ): LogicalMinimum { const values = [second, ...others]; return new LogicalMinimum( @@ -1198,7 +1239,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The other vector (represented as an Expr) to compare against. * @return A new `Expr` representing the cosine distance between the two vectors. */ - cosineDistance(other: Expr): CosineDistance; + cosineDistance(other: ScalarExpr): CosineDistance; /** * Calculates the Cosine distance between two vectors. * @@ -1223,9 +1264,9 @@ export abstract class Expr implements ProtoSerializable, UserData { * @return A new `Expr` representing the Cosine distance between the two vectors. */ cosineDistance(other: number[]): CosineDistance; - cosineDistance(other: Expr | VectorValue | number[]): CosineDistance { - if (other instanceof Expr) { - return new CosineDistance(this, other as Expr); + cosineDistance(other: ScalarExpr | VectorValue | number[]): CosineDistance { + if (other instanceof ScalarExpr) { + return new CosineDistance(this, other as ScalarExpr); } else { return new CosineDistance( this, @@ -1245,7 +1286,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the dot product between the two vectors. */ - dotProduct(other: Expr): DotProduct; + dotProduct(other: ScalarExpr): DotProduct; /** * Calculates the dot product between two vectors. @@ -1272,9 +1313,9 @@ export abstract class Expr implements ProtoSerializable, UserData { * @return A new `Expr` representing the dot product between the two vectors. */ dotProduct(other: number[]): DotProduct; - dotProduct(other: Expr | VectorValue | number[]): DotProduct { - if (other instanceof Expr) { - return new DotProduct(this, other as Expr); + dotProduct(other: ScalarExpr | VectorValue | number[]): DotProduct { + if (other instanceof ScalarExpr) { + return new DotProduct(this, other as ScalarExpr); } else { return new DotProduct( this, @@ -1294,7 +1335,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the Euclidean distance between the two vectors. */ - euclideanDistance(other: Expr): EuclideanDistance; + euclideanDistance(other: ScalarExpr): EuclideanDistance; /** * Calculates the Euclidean distance between two vectors. @@ -1321,9 +1362,11 @@ export abstract class Expr implements ProtoSerializable, UserData { * @return A new `Expr` representing the Euclidean distance between the two vectors. */ euclideanDistance(other: number[]): EuclideanDistance; - euclideanDistance(other: Expr | VectorValue | number[]): EuclideanDistance { - if (other instanceof Expr) { - return new EuclideanDistance(this, other as Expr); + euclideanDistance( + other: ScalarExpr | VectorValue | number[] + ): EuclideanDistance { + if (other instanceof ScalarExpr) { + return new EuclideanDistance(this, other as ScalarExpr); } else { return new EuclideanDistance( this, @@ -1431,7 +1474,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param amount The expression evaluates to amount of the unit. * @return A new {@code Expr} representing the resulting timestamp. */ - timestampAdd(unit: Expr, amount: Expr): TimestampAdd; + timestampAdd(unit: ScalarExpr, amount: ScalarExpr): TimestampAdd; /** * Creates an expression that adds a specified amount of time to this timestamp expression. @@ -1451,22 +1494,22 @@ export abstract class Expr implements ProtoSerializable, UserData { ): TimestampAdd; timestampAdd( unit: - | Expr + | ScalarExpr | 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', - amount: Expr | number + amount: ScalarExpr | number ): TimestampAdd { const normalizedUnit = typeof unit === 'string' ? Constant.of(unit) : unit; const normalizedAmount = typeof amount === 'number' ? Constant.of(amount) : amount; return new TimestampAdd( this, - normalizedUnit as Expr, - normalizedAmount as Expr + normalizedUnit as ScalarExpr, + normalizedAmount as ScalarExpr ); } @@ -1482,7 +1525,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param amount The expression evaluates to amount of the unit. * @return A new {@code Expr} representing the resulting timestamp. */ - timestampSub(unit: Expr, amount: Expr): TimestampSub; + timestampSub(unit: ScalarExpr, amount: ScalarExpr): TimestampSub; /** * Creates an expression that subtracts a specified amount of time from this timestamp expression. @@ -1502,22 +1545,22 @@ export abstract class Expr implements ProtoSerializable, UserData { ): TimestampSub; timestampSub( unit: - | Expr + | ScalarExpr | 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', - amount: Expr | number + amount: ScalarExpr | number ): TimestampSub { const normalizedUnit = typeof unit === 'string' ? Constant.of(unit) : unit; const normalizedAmount = typeof amount === 'number' ? Constant.of(amount) : amount; return new TimestampSub( this, - normalizedUnit as Expr, - normalizedAmount as Expr + normalizedUnit as ScalarExpr, + normalizedAmount as ScalarExpr ); } @@ -1548,8 +1591,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise AND operation. */ - bitAnd(bitsExpression: Expr): BitAnd; - bitAnd(bitsOrExpression: number | Expr | Bytes): BitAnd { + bitAnd(bitsExpression: ScalarExpr): BitAnd; + bitAnd(bitsOrExpression: number | ScalarExpr | Bytes): BitAnd { return new BitAnd(this, valueToDefaultExpr(bitsOrExpression)); } @@ -1580,8 +1623,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise OR operation. */ - bitOr(bitsExpression: Expr): BitOr; - bitOr(bitsOrExpression: number | Expr | Bytes): BitOr { + bitOr(bitsExpression: ScalarExpr): BitOr; + bitOr(bitsOrExpression: number | ScalarExpr | Bytes): BitOr { return new BitOr(this, valueToDefaultExpr(bitsOrExpression)); } @@ -1612,8 +1655,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise XOR operation. */ - bitXor(bitsExpression: Expr): BitXor; - bitXor(bitsOrExpression: number | Expr | Bytes): BitXor { + bitXor(bitsExpression: ScalarExpr): BitXor; + bitXor(bitsOrExpression: number | ScalarExpr | Bytes): BitXor { return new BitXor(this, valueToDefaultExpr(bitsOrExpression)); } @@ -1660,8 +1703,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param numberExpr The operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ - bitLeftShift(numberExpr: Expr): BitLeftShift; - bitLeftShift(numberExpr: number | Expr): BitLeftShift { + bitLeftShift(numberExpr: ScalarExpr): BitLeftShift; + bitLeftShift(numberExpr: number | ScalarExpr): BitLeftShift { return new BitLeftShift(this, valueToDefaultExpr(numberExpr)); } @@ -1692,8 +1735,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param numberExpr The operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ - bitRightShift(numberExpr: Expr): BitRightShift; - bitRightShift(numberExpr: number | Expr): BitRightShift { + bitRightShift(numberExpr: ScalarExpr): BitRightShift; + bitRightShift(numberExpr: number | ScalarExpr): BitRightShift { return new BitRightShift(this, valueToDefaultExpr(numberExpr)); } @@ -1733,8 +1776,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param length An expression returning the length of the substring. If not provided the * substring will end at the end of the input. */ - substr(position: Expr, length?: Expr): Substr; - substr(position: Expr | number, length?: Expr | number): Substr { + substr(position: ScalarExpr, length?: ScalarExpr): Substr; + substr(position: ScalarExpr | number, length?: ScalarExpr | number): Substr { const positionExpr = valueToDefaultExpr(position); const lengthExpr = length === undefined ? undefined : valueToDefaultExpr(length); @@ -1772,8 +1815,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param offsetExpr An Expr evaluating to the index of the element to return. * @return A new Expr representing the 'arrayOffset' operation. */ - arrayOffset(offsetExpr: Expr): ArrayOffset; - arrayOffset(offset: Expr | number): ArrayOffset { + arrayOffset(offsetExpr: ScalarExpr): ArrayOffset; + arrayOffset(offset: ScalarExpr | number): ArrayOffset { return new ArrayOffset(fieldOfOrExpr(array), valueToDefaultExpr(offset)); } @@ -1809,7 +1852,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * returned if this expression produces an error. * @return A new {@code Expr} representing the 'ifError' operation. */ - ifError(catchExpr: Expr): IfError; + ifError(catchExpr: ScalarExpr): IfError; /** * @beta @@ -1906,8 +1949,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * * @param keyExpr An expression that produces the name of the key to remove from the input map. */ - mapRemove(keyExpr: Expr): MapRemove; - mapRemove(stringExpr: Expr | string): MapRemove { + mapRemove(keyExpr: ScalarExpr): MapRemove; + mapRemove(stringExpr: ScalarExpr | string): MapRemove { return new MapRemove(this, valueToDefaultExpr(stringExpr)); } @@ -1928,8 +1971,8 @@ export abstract class Expr implements ProtoSerializable, UserData { * as a literal or an expression that returns a map. */ mapMerge( - secondMap: Record | Expr, - ...otherMaps: Array | Expr> + secondMap: Record | ScalarExpr, + ...otherMaps: Array | ScalarExpr> ): MapMerge { const secondMapExpr = valueToDefaultExpr(secondMap); const otherMapExprs = otherMaps.map(valueToDefaultExpr); @@ -1979,9 +2022,11 @@ export abstract class Expr implements ProtoSerializable, UserData { * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ - manhattanDistance(other: Expr): ManhattanDistance; - manhattanDistance(other: Expr | number[] | VectorValue): ManhattanDistance { - const expr2 = other instanceof Expr ? other : Constant.vector(other); + manhattanDistance(other: ScalarExpr): ManhattanDistance; + manhattanDistance( + other: ScalarExpr | number[] | VectorValue + ): ManhattanDistance { + const expr2 = other instanceof ScalarExpr ? other : Constant.vector(other); return new ManhattanDistance(this, expr2); } @@ -2034,18 +2079,6 @@ export abstract class Expr implements ProtoSerializable, UserData { as(name: string): ExprWithAlias { return new ExprWithAlias(this, name); } - - /** - * @private - * @internal - */ - abstract _toProto(serializer: JsonProtoSerializer): ProtoValue; - - /** - * @private - * @internal - */ - abstract _readUserData(dataReader: UserDataReader): void; } /** @@ -2056,7 +2089,7 @@ export abstract class Expr implements ProtoSerializable, UserData { export interface Selectable { selectable: true; readonly alias: string; - readonly expr: Expr; + readonly expr: ScalarExpr; } /** @@ -2064,12 +2097,12 @@ export interface Selectable { * * An class that represents an aggregate function. */ -export class AggregateFunction - implements ProtoSerializable, UserData -{ - aggregateFunction: true = true; +export class AggregateFunction extends Expr { + exprType: ExprType = 'AggregateFunction'; - constructor(private name: string, private params: Expr[]) {} + constructor(private name: string, private params: ScalarExpr[]) { + super(); + } /** * Assigns an alias to this AggregateFunction. The alias specifies the name that @@ -2143,7 +2176,9 @@ export class AggregateFunctionWithAlias /** * @beta */ -export class ExprWithAlias implements Selectable, UserData { +export class ExprWithAlias + implements Selectable, UserData +{ exprType: ExprType = 'ExprWithAlias'; selectable = true as const; @@ -2161,10 +2196,10 @@ export class ExprWithAlias implements Selectable, UserData { /** * @internal */ -class ListOfExprs extends Expr { +class ListOfExprs extends ScalarExpr { exprType: ExprType = 'ListOfExprs'; - constructor(private exprs: Expr[]) { + constructor(private exprs: ScalarExpr[]) { super(); } @@ -2185,7 +2220,7 @@ class ListOfExprs extends Expr { * @internal */ _readUserData(dataReader: UserDataReader): void { - this.exprs.forEach((expr: Expr) => expr._readUserData(dataReader)); + this.exprs.forEach((expr: ScalarExpr) => expr._readUserData(dataReader)); } } @@ -2207,7 +2242,7 @@ class ListOfExprs extends Expr { * const cityField = Field.of("address.city"); * ``` */ -export class Field extends Expr implements Selectable { +export class Field extends ScalarExpr implements Selectable { exprType: ExprType = 'Field'; selectable = true as const; @@ -2256,7 +2291,7 @@ export class Field extends Expr implements Selectable { return this.fieldName(); } - get expr(): Expr { + get expr(): ScalarExpr { return this; } @@ -2292,7 +2327,7 @@ export class Field extends Expr implements Selectable { * const hello = Constant.of("hello"); * ``` */ -export class Constant extends Expr { +export class Constant extends ScalarExpr { exprType: ExprType = 'Constant'; private _protoValue?: ProtoValue; @@ -2488,8 +2523,8 @@ export class Constant extends Expr { * @internal * @private */ -export class MapValue extends Expr { - constructor(private plainObject: Map) { +export class MapValue extends ScalarExpr { + constructor(private plainObject: Map) { super(); } @@ -2513,12 +2548,12 @@ export class MapValue extends Expr { * execution. * * Typically, you would not use this class or its children directly. Use either the functions like {@link and}, {@link eq}, - * or the methods on {@link Expr} ({@link Expr#eq}, {@link Expr#lt}, etc) to construct new Function instances. + * or the methods on {@link ScalarExpr} ({@link ScalarExpr#eq}, {@link ScalarExpr#lt}, etc) to construct new Function instances. */ -export class FirestoreFunction extends Expr { +export class FirestoreFunction extends ScalarExpr { exprType: ExprType = 'Function'; - constructor(private name: string, private params: Expr[]) { + constructor(private name: string, private params: ScalarExpr[]) { super(); } @@ -2588,7 +2623,7 @@ export class BooleanExpr extends FirestoreFunction { * @beta */ export class Add extends FirestoreFunction { - constructor(left: Expr, others: Expr[]) { + constructor(left: ScalarExpr, others: ScalarExpr[]) { super('add', [left, ...others]); } } @@ -2597,7 +2632,7 @@ export class Add extends FirestoreFunction { * @beta */ export class Subtract extends FirestoreFunction { - constructor(private left: Expr, private right: Expr) { + constructor(private left: ScalarExpr, private right: ScalarExpr) { super('subtract', [left, right]); } } @@ -2606,7 +2641,7 @@ export class Subtract extends FirestoreFunction { * @beta */ export class Multiply extends FirestoreFunction { - constructor(left: Expr, others: Expr[]) { + constructor(left: ScalarExpr, others: ScalarExpr[]) { super('multiply', [left, ...others]); } } @@ -2615,7 +2650,7 @@ export class Multiply extends FirestoreFunction { * @beta */ export class Divide extends FirestoreFunction { - constructor(private left: Expr, private right: Expr) { + constructor(private left: ScalarExpr, private right: ScalarExpr) { super('divide', [left, right]); } } @@ -2624,19 +2659,19 @@ export class Divide extends FirestoreFunction { * @beta */ export class Mod extends FirestoreFunction { - constructor(private left: Expr, private right: Expr) { + constructor(private left: ScalarExpr, private right: ScalarExpr) { super('mod', [left, right]); } } export class MapFunction extends FirestoreFunction { - constructor(private elements: Expr[]) { + constructor(private elements: ScalarExpr[]) { super('map', elements); } } export class ArrayFunction extends FirestoreFunction { - constructor(private elements: Expr[]) { + constructor(private elements: ScalarExpr[]) { super('array', elements); } } @@ -2645,7 +2680,7 @@ export class ArrayFunction extends FirestoreFunction { * @beta */ export class Eq extends BooleanExpr { - constructor(private left: Expr, private right: Expr) { + constructor(private left: ScalarExpr, private right: ScalarExpr) { super('eq', [left, right]); } @@ -2656,7 +2691,7 @@ export class Eq extends BooleanExpr { * @beta */ export class Neq extends BooleanExpr { - constructor(private left: Expr, private right: Expr) { + constructor(private left: ScalarExpr, private right: ScalarExpr) { super('neq', [left, right]); } @@ -2667,7 +2702,7 @@ export class Neq extends BooleanExpr { * @beta */ export class Lt extends BooleanExpr { - constructor(private left: Expr, private right: Expr) { + constructor(private left: ScalarExpr, private right: ScalarExpr) { super('lt', [left, right]); } @@ -2678,7 +2713,7 @@ export class Lt extends BooleanExpr { * @beta */ export class Lte extends BooleanExpr { - constructor(private left: Expr, private right: Expr) { + constructor(private left: ScalarExpr, private right: ScalarExpr) { super('lte', [left, right]); } @@ -2689,7 +2724,7 @@ export class Lte extends BooleanExpr { * @beta */ export class Gt extends BooleanExpr { - constructor(private left: Expr, private right: Expr) { + constructor(private left: ScalarExpr, private right: ScalarExpr) { super('gt', [left, right]); } @@ -2700,7 +2735,7 @@ export class Gt extends BooleanExpr { * @beta */ export class Gte extends BooleanExpr { - constructor(private left: Expr, private right: Expr) { + constructor(private left: ScalarExpr, private right: ScalarExpr) { super('gte', [left, right]); } @@ -2711,7 +2746,7 @@ export class Gte extends BooleanExpr { * @beta */ export class ArrayConcat extends FirestoreFunction { - constructor(array: Expr, elements: Expr[]) { + constructor(array: ScalarExpr, elements: ScalarExpr[]) { super('array_concat', [array, ...elements]); } } @@ -2720,7 +2755,7 @@ export class ArrayConcat extends FirestoreFunction { * @beta */ export class ArrayReverse extends FirestoreFunction { - constructor(private array: Expr) { + constructor(private array: ScalarExpr) { super('array_reverse', [array]); } } @@ -2729,7 +2764,7 @@ export class ArrayReverse extends FirestoreFunction { * @beta */ export class ArrayContains extends BooleanExpr { - constructor(private array: Expr, private element: Expr) { + constructor(private array: ScalarExpr, private element: ScalarExpr) { super('array_contains', [array, element]); } @@ -2740,7 +2775,7 @@ export class ArrayContains extends BooleanExpr { * @beta */ export class ArrayContainsAll extends BooleanExpr { - constructor(private array: Expr, private values: Expr[]) { + constructor(private array: ScalarExpr, private values: ScalarExpr[]) { super('array_contains_all', [array, new ListOfExprs(values)]); } @@ -2751,7 +2786,7 @@ export class ArrayContainsAll extends BooleanExpr { * @beta */ export class ArrayContainsAny extends BooleanExpr { - constructor(private array: Expr, private values: Expr[]) { + constructor(private array: ScalarExpr, private values: ScalarExpr[]) { super('array_contains_any', [array, new ListOfExprs(values)]); } @@ -2762,7 +2797,7 @@ export class ArrayContainsAny extends BooleanExpr { * @beta */ export class ArrayLength extends FirestoreFunction { - constructor(private array: Expr) { + constructor(private array: ScalarExpr) { super('array_length', [array]); } } @@ -2780,7 +2815,7 @@ export class ArrayElement extends FirestoreFunction { * @beta */ export class EqAny extends BooleanExpr { - constructor(private left: Expr, private others: Expr[]) { + constructor(private left: ScalarExpr, private others: ScalarExpr[]) { super('eq_any', [left, new ListOfExprs(others)]); } @@ -2791,7 +2826,7 @@ export class EqAny extends BooleanExpr { * @beta */ export class NotEqAny extends BooleanExpr { - constructor(private left: Expr, private others: Expr[]) { + constructor(private left: ScalarExpr, private others: ScalarExpr[]) { super('not_eq_any', [left, new ListOfExprs(others)]); } @@ -2802,7 +2837,7 @@ export class NotEqAny extends BooleanExpr { * @beta */ export class IsNan extends BooleanExpr { - constructor(private expr: Expr) { + constructor(private expr: ScalarExpr) { super('is_nan', [expr]); } @@ -2813,7 +2848,7 @@ export class IsNan extends BooleanExpr { * @beta */ export class Exists extends BooleanExpr { - constructor(private expr: Expr) { + constructor(private expr: ScalarExpr) { super('exists', [expr]); } @@ -2824,7 +2859,7 @@ export class Exists extends BooleanExpr { * @beta */ export class Not extends BooleanExpr { - constructor(private expr: Expr) { + constructor(private expr: ScalarExpr) { super('not', [expr]); } @@ -2870,8 +2905,8 @@ export class Xor extends BooleanExpr { export class Cond extends FirestoreFunction { constructor( private condition: BooleanExpr, - private thenExpr: Expr, - private elseExpr: Expr + private thenExpr: ScalarExpr, + private elseExpr: ScalarExpr ) { super('cond', [condition, thenExpr, elseExpr]); } @@ -2883,7 +2918,7 @@ export class Cond extends FirestoreFunction { * @beta */ export class LogicalMaximum extends FirestoreFunction { - constructor(first: Expr, others: Expr[]) { + constructor(first: ScalarExpr, others: ScalarExpr[]) { super('logical_maximum', [first, ...others]); } } @@ -2892,7 +2927,7 @@ export class LogicalMaximum extends FirestoreFunction { * @beta */ export class LogicalMinimum extends FirestoreFunction { - constructor(first: Expr, others: Expr[]) { + constructor(first: ScalarExpr, others: ScalarExpr[]) { super('logical_min', [first, ...others]); } } @@ -2901,7 +2936,7 @@ export class LogicalMinimum extends FirestoreFunction { * @beta */ export class Reverse extends FirestoreFunction { - constructor(private value: Expr) { + constructor(private value: ScalarExpr) { super('reverse', [value]); } } @@ -2910,7 +2945,11 @@ export class Reverse extends FirestoreFunction { * @beta */ export class ReplaceFirst extends FirestoreFunction { - constructor(private value: Expr, private find: Expr, private replace: Expr) { + constructor( + private value: ScalarExpr, + private find: ScalarExpr, + private replace: ScalarExpr + ) { super('replace_first', [value, find, replace]); } } @@ -2919,7 +2958,11 @@ export class ReplaceFirst extends FirestoreFunction { * @beta */ export class ReplaceAll extends FirestoreFunction { - constructor(private value: Expr, private find: Expr, private replace: Expr) { + constructor( + private value: ScalarExpr, + private find: ScalarExpr, + private replace: ScalarExpr + ) { super('replace_all', [value, find, replace]); } } @@ -2928,7 +2971,7 @@ export class ReplaceAll extends FirestoreFunction { * @beta */ export class CharLength extends FirestoreFunction { - constructor(private value: Expr) { + constructor(private value: ScalarExpr) { super('char_length', [value]); } } @@ -2937,7 +2980,7 @@ export class CharLength extends FirestoreFunction { * @beta */ export class ByteLength extends FirestoreFunction { - constructor(private value: Expr) { + constructor(private value: ScalarExpr) { super('byte_length', [value]); } } @@ -2946,7 +2989,7 @@ export class ByteLength extends FirestoreFunction { * @beta */ export class Like extends BooleanExpr { - constructor(private expr: Expr, private pattern: Expr) { + constructor(private expr: ScalarExpr, private pattern: ScalarExpr) { super('like', [expr, pattern]); } @@ -2957,7 +3000,7 @@ export class Like extends BooleanExpr { * @beta */ export class RegexContains extends BooleanExpr { - constructor(private expr: Expr, private pattern: Expr) { + constructor(private expr: ScalarExpr, private pattern: ScalarExpr) { super('regex_contains', [expr, pattern]); } @@ -2968,7 +3011,7 @@ export class RegexContains extends BooleanExpr { * @beta */ export class RegexMatch extends BooleanExpr { - constructor(private expr: Expr, private pattern: Expr) { + constructor(private expr: ScalarExpr, private pattern: ScalarExpr) { super('regex_match', [expr, pattern]); } @@ -2979,7 +3022,7 @@ export class RegexMatch extends BooleanExpr { * @beta */ export class StrContains extends BooleanExpr { - constructor(private expr: Expr, private substring: Expr) { + constructor(private expr: ScalarExpr, private substring: ScalarExpr) { super('str_contains', [expr, substring]); } @@ -2990,7 +3033,7 @@ export class StrContains extends BooleanExpr { * @beta */ export class StartsWith extends BooleanExpr { - constructor(private expr: Expr, private prefix: Expr) { + constructor(private expr: ScalarExpr, private prefix: ScalarExpr) { super('starts_with', [expr, prefix]); } @@ -3001,7 +3044,7 @@ export class StartsWith extends BooleanExpr { * @beta */ export class EndsWith extends BooleanExpr { - constructor(private expr: Expr, private suffix: Expr) { + constructor(private expr: ScalarExpr, private suffix: ScalarExpr) { super('ends_with', [expr, suffix]); } @@ -3012,7 +3055,7 @@ export class EndsWith extends BooleanExpr { * @beta */ export class ToLower extends FirestoreFunction { - constructor(private expr: Expr) { + constructor(private expr: ScalarExpr) { super('to_lower', [expr]); } } @@ -3021,7 +3064,7 @@ export class ToLower extends FirestoreFunction { * @beta */ export class ToUpper extends FirestoreFunction { - constructor(private expr: Expr) { + constructor(private expr: ScalarExpr) { super('to_upper', [expr]); } } @@ -3030,7 +3073,7 @@ export class ToUpper extends FirestoreFunction { * @beta */ export class Trim extends FirestoreFunction { - constructor(private expr: Expr) { + constructor(private expr: ScalarExpr) { super('trim', [expr]); } } @@ -3039,7 +3082,7 @@ export class Trim extends FirestoreFunction { * @beta */ export class StrConcat extends FirestoreFunction { - constructor(private first: Expr, private rest: Expr[]) { + constructor(private first: ScalarExpr, private rest: ScalarExpr[]) { super('str_concat', [first, ...rest]); } } @@ -3048,7 +3091,7 @@ export class StrConcat extends FirestoreFunction { * @beta */ export class MapGet extends FirestoreFunction { - constructor(map: Expr, name: string) { + constructor(map: ScalarExpr, name: string) { super('map_get', [map, Constant.of(name)]); } } @@ -3059,7 +3102,10 @@ export class MapGet extends FirestoreFunction { export class Count extends AggregateFunction { aggregateFunction = true as const; - constructor(private value: Expr | undefined, private distinct: boolean) { + constructor( + private value: ScalarExpr | undefined, + private distinct: boolean + ) { super('count', value === undefined ? [] : [value]); } } @@ -3070,7 +3116,7 @@ export class Count extends AggregateFunction { export class Sum extends AggregateFunction { aggregateFunction = true as const; - constructor(private value: Expr, private distinct: boolean) { + constructor(private value: ScalarExpr, private distinct: boolean) { super('sum', [value]); } } @@ -3081,7 +3127,7 @@ export class Sum extends AggregateFunction { export class Avg extends AggregateFunction { aggregateFunction = true as const; - constructor(private value: Expr, private distinct: boolean) { + constructor(private value: ScalarExpr, private distinct: boolean) { super('avg', [value]); } } @@ -3092,7 +3138,7 @@ export class Avg extends AggregateFunction { export class Minimum extends AggregateFunction { aggregateFunction = true as const; - constructor(private value: Expr, private distinct: boolean) { + constructor(private value: ScalarExpr, private distinct: boolean) { super('minimum', [value]); } } @@ -3103,7 +3149,7 @@ export class Minimum extends AggregateFunction { export class Maximum extends AggregateFunction { aggregateFunction = true as const; - constructor(private value: Expr, private distinct: boolean) { + constructor(private value: ScalarExpr, private distinct: boolean) { super('maximum', [value]); } } @@ -3112,7 +3158,7 @@ export class Maximum extends AggregateFunction { * @beta */ export class CosineDistance extends FirestoreFunction { - constructor(private vector1: Expr, private vector2: Expr) { + constructor(private vector1: ScalarExpr, private vector2: ScalarExpr) { super('cosine_distance', [vector1, vector2]); } } @@ -3121,7 +3167,7 @@ export class CosineDistance extends FirestoreFunction { * @beta */ export class DotProduct extends FirestoreFunction { - constructor(private vector1: Expr, private vector2: Expr) { + constructor(private vector1: ScalarExpr, private vector2: ScalarExpr) { super('dot_product', [vector1, vector2]); } } @@ -3130,7 +3176,7 @@ export class DotProduct extends FirestoreFunction { * @beta */ export class EuclideanDistance extends FirestoreFunction { - constructor(private vector1: Expr, private vector2: Expr) { + constructor(private vector1: ScalarExpr, private vector2: ScalarExpr) { super('euclidean_distance', [vector1, vector2]); } } @@ -3139,7 +3185,7 @@ export class EuclideanDistance extends FirestoreFunction { * @beta */ export class VectorLength extends FirestoreFunction { - constructor(private value: Expr) { + constructor(private value: ScalarExpr) { super('vector_length', [value]); } } @@ -3148,7 +3194,7 @@ export class VectorLength extends FirestoreFunction { * @beta */ export class UnixMicrosToTimestamp extends FirestoreFunction { - constructor(private input: Expr) { + constructor(private input: ScalarExpr) { super('unix_micros_to_timestamp', [input]); } } @@ -3157,7 +3203,7 @@ export class UnixMicrosToTimestamp extends FirestoreFunction { * @beta */ export class TimestampToUnixMicros extends FirestoreFunction { - constructor(private input: Expr) { + constructor(private input: ScalarExpr) { super('timestamp_to_unix_micros', [input]); } } @@ -3166,7 +3212,7 @@ export class TimestampToUnixMicros extends FirestoreFunction { * @beta */ export class UnixMillisToTimestamp extends FirestoreFunction { - constructor(private input: Expr) { + constructor(private input: ScalarExpr) { super('unix_millis_to_timestamp', [input]); } } @@ -3175,7 +3221,7 @@ export class UnixMillisToTimestamp extends FirestoreFunction { * @beta */ export class TimestampToUnixMillis extends FirestoreFunction { - constructor(private input: Expr) { + constructor(private input: ScalarExpr) { super('timestamp_to_unix_millis', [input]); } } @@ -3184,7 +3230,7 @@ export class TimestampToUnixMillis extends FirestoreFunction { * @beta */ export class UnixSecondsToTimestamp extends FirestoreFunction { - constructor(private input: Expr) { + constructor(private input: ScalarExpr) { super('unix_seconds_to_timestamp', [input]); } } @@ -3193,7 +3239,7 @@ export class UnixSecondsToTimestamp extends FirestoreFunction { * @beta */ export class TimestampToUnixSeconds extends FirestoreFunction { - constructor(private input: Expr) { + constructor(private input: ScalarExpr) { super('timestamp_to_unix_seconds', [input]); } } @@ -3203,9 +3249,9 @@ export class TimestampToUnixSeconds extends FirestoreFunction { */ export class TimestampAdd extends FirestoreFunction { constructor( - private timestamp: Expr, - private unit: Expr, - private amount: Expr + private timestamp: ScalarExpr, + private unit: ScalarExpr, + private amount: ScalarExpr ) { super('timestamp_add', [timestamp, unit, amount]); } @@ -3216,9 +3262,9 @@ export class TimestampAdd extends FirestoreFunction { */ export class TimestampSub extends FirestoreFunction { constructor( - private timestamp: Expr, - private unit: Expr, - private amount: Expr + private timestamp: ScalarExpr, + private unit: ScalarExpr, + private amount: ScalarExpr ) { super('timestamp_sub', [timestamp, unit, amount]); } @@ -3276,7 +3322,7 @@ export function rand(): Rand { * @beta */ export class BitAnd extends FirestoreFunction { - constructor(private left: Expr, private right: Expr) { + constructor(private left: ScalarExpr, private right: ScalarExpr) { super('bit_and', [left, right]); } } @@ -3310,7 +3356,7 @@ export function bitAnd(field: string, otherBits: number | Bytes): BitAnd; * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise AND operation. */ -export function bitAnd(field: string, bitsExpression: Expr): BitAnd; +export function bitAnd(field: string, bitsExpression: ScalarExpr): BitAnd; /** * @beta * @@ -3325,7 +3371,10 @@ export function bitAnd(field: string, bitsExpression: Expr): BitAnd; * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise AND operation. */ -export function bitAnd(bitsExpression: Expr, otherBits: number | Bytes): BitAnd; +export function bitAnd( + bitsExpression: ScalarExpr, + otherBits: number | Bytes +): BitAnd; /** * @beta * @@ -3340,10 +3389,13 @@ export function bitAnd(bitsExpression: Expr, otherBits: number | Bytes): BitAnd; * @param otherBitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise AND operation. */ -export function bitAnd(bitsExpression: Expr, otherBitsExpression: Expr): BitAnd; export function bitAnd( - fieldOrExpression: string | Expr, - bitsOrExpression: number | Expr | Bytes + bitsExpression: ScalarExpr, + otherBitsExpression: ScalarExpr +): BitAnd; +export function bitAnd( + fieldOrExpression: string | ScalarExpr, + bitsOrExpression: number | ScalarExpr | Bytes ): BitAnd { return new BitAnd( fieldOfOrExpr(fieldOrExpression), @@ -3355,7 +3407,7 @@ export function bitAnd( * @beta */ export class BitOr extends FirestoreFunction { - constructor(private left: Expr, private right: Expr) { + constructor(private left: ScalarExpr, private right: ScalarExpr) { super('bit_or', [left, right]); } } @@ -3389,7 +3441,7 @@ export function bitOr(field: string, otherBits: number | Bytes): BitOr; * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise OR operation. */ -export function bitOr(field: string, bitsExpression: Expr): BitOr; +export function bitOr(field: string, bitsExpression: ScalarExpr): BitOr; /** * @beta * @@ -3404,7 +3456,10 @@ export function bitOr(field: string, bitsExpression: Expr): BitOr; * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise OR operation. */ -export function bitOr(bitsExpression: Expr, otherBits: number | Bytes): BitOr; +export function bitOr( + bitsExpression: ScalarExpr, + otherBits: number | Bytes +): BitOr; /** * @beta * @@ -3419,10 +3474,13 @@ export function bitOr(bitsExpression: Expr, otherBits: number | Bytes): BitOr; * @param otherBitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise OR operation. */ -export function bitOr(bitsExpression: Expr, otherBitsExpression: Expr): BitOr; export function bitOr( - fieldOrExpression: string | Expr, - bitsOrExpression: number | Expr | Bytes + bitsExpression: ScalarExpr, + otherBitsExpression: ScalarExpr +): BitOr; +export function bitOr( + fieldOrExpression: string | ScalarExpr, + bitsOrExpression: number | ScalarExpr | Bytes ): BitOr { return new BitOr( fieldOfOrExpr(fieldOrExpression), @@ -3434,7 +3492,7 @@ export function bitOr( * @beta */ export class BitXor extends FirestoreFunction { - constructor(private left: Expr, private right: Expr) { + constructor(private left: ScalarExpr, private right: ScalarExpr) { super('bit_xor', [left, right]); } } @@ -3468,7 +3526,7 @@ export function bitXor(field: string, otherBits: number | Bytes): BitXor; * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise XOR operation. */ -export function bitXor(field: string, bitsExpression: Expr): BitXor; +export function bitXor(field: string, bitsExpression: ScalarExpr): BitXor; /** * @beta * @@ -3483,7 +3541,10 @@ export function bitXor(field: string, bitsExpression: Expr): BitXor; * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise XOR operation. */ -export function bitXor(bitsExpression: Expr, otherBits: number | Bytes): BitXor; +export function bitXor( + bitsExpression: ScalarExpr, + otherBits: number | Bytes +): BitXor; /** * @beta * @@ -3498,10 +3559,13 @@ export function bitXor(bitsExpression: Expr, otherBits: number | Bytes): BitXor; * @param otherBitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise XOR operation. */ -export function bitXor(bitsExpression: Expr, otherBitsExpression: Expr): BitXor; export function bitXor( - fieldOrExpression: string | Expr, - bitsOrExpression: number | Expr | Bytes + bitsExpression: ScalarExpr, + otherBitsExpression: ScalarExpr +): BitXor; +export function bitXor( + fieldOrExpression: string | ScalarExpr, + bitsOrExpression: number | ScalarExpr | Bytes ): BitXor { return new BitXor( fieldOfOrExpr(fieldOrExpression), @@ -3513,7 +3577,7 @@ export function bitXor( * @beta */ export class BitNot extends FirestoreFunction { - constructor(private value: Expr) { + constructor(private value: ScalarExpr) { super('bit_not', [value]); } } @@ -3545,8 +3609,8 @@ export function bitNot(field: string): BitNot; * @param bitsValueExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise NOT operation. */ -export function bitNot(bitsValueExpression: Expr): BitNot; -export function bitNot(bits: string | Expr): BitNot { +export function bitNot(bitsValueExpression: ScalarExpr): BitNot; +export function bitNot(bits: string | ScalarExpr): BitNot { return new BitNot(fieldOfOrExpr(bits)); } @@ -3554,7 +3618,7 @@ export function bitNot(bits: string | Expr): BitNot { * @beta */ export class BitLeftShift extends FirestoreFunction { - constructor(value: Expr, y: Expr) { + constructor(value: ScalarExpr, y: ScalarExpr) { super('bit_left_shift', [value, y]); } } @@ -3588,7 +3652,10 @@ export function bitLeftShift(field: string, y: number): BitLeftShift; * @param numberExpr The right operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ -export function bitLeftShift(field: string, numberExpr: Expr): BitLeftShift; +export function bitLeftShift( + field: string, + numberExpr: ScalarExpr +): BitLeftShift; /** * @beta * @@ -3603,7 +3670,7 @@ export function bitLeftShift(field: string, numberExpr: Expr): BitLeftShift; * @param y The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ -export function bitLeftShift(xValue: Expr, y: number): BitLeftShift; +export function bitLeftShift(xValue: ScalarExpr, y: number): BitLeftShift; /** * @beta * @@ -3618,10 +3685,13 @@ export function bitLeftShift(xValue: Expr, y: number): BitLeftShift; * @param right The right operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ -export function bitLeftShift(xValue: Expr, numberExpr: Expr): BitLeftShift; export function bitLeftShift( - xValue: string | Expr, - numberExpr: number | Expr + xValue: ScalarExpr, + numberExpr: ScalarExpr +): BitLeftShift; +export function bitLeftShift( + xValue: string | ScalarExpr, + numberExpr: number | ScalarExpr ): BitLeftShift { return new BitLeftShift( fieldOfOrExpr(xValue), @@ -3633,7 +3703,7 @@ export function bitLeftShift( * @beta */ export class BitRightShift extends FirestoreFunction { - constructor(value: Expr, y: Expr) { + constructor(value: ScalarExpr, y: ScalarExpr) { super('bit_right_shift', [value, y]); } } @@ -3667,7 +3737,10 @@ export function bitRightShift(field: string, y: number): BitRightShift; * @param numberExpr The right operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ -export function bitRightShift(field: string, numberExpr: Expr): BitRightShift; +export function bitRightShift( + field: string, + numberExpr: ScalarExpr +): BitRightShift; /** * @beta * @@ -3682,7 +3755,7 @@ export function bitRightShift(field: string, numberExpr: Expr): BitRightShift; * @param y The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ -export function bitRightShift(xValue: Expr, y: number): BitRightShift; +export function bitRightShift(xValue: ScalarExpr, y: number): BitRightShift; /** * @beta * @@ -3697,10 +3770,13 @@ export function bitRightShift(xValue: Expr, y: number): BitRightShift; * @param right The right operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ -export function bitRightShift(xValue: Expr, numberExpr: Expr): BitRightShift; export function bitRightShift( - xValue: string | Expr, - numberExpr: number | Expr + xValue: ScalarExpr, + numberExpr: ScalarExpr +): BitRightShift; +export function bitRightShift( + xValue: string | ScalarExpr, + numberExpr: number | ScalarExpr ): BitRightShift { return new BitRightShift( fieldOfOrExpr(xValue), @@ -3712,7 +3788,7 @@ export function bitRightShift( * @beta */ export class ArrayOffset extends FirestoreFunction { - constructor(private arrayExpression: Expr, private offset: Expr) { + constructor(private arrayExpression: ScalarExpr, private offset: ScalarExpr) { super('array_offset', [arrayExpression, offset]); } } @@ -3750,7 +3826,10 @@ export function arrayOffset(arrayField: string, offset: number): ArrayOffset; * @param offsetExpr An Expr evaluating to the index of the element to return. * @return A new Expr representing the 'arrayOffset' operation. */ -export function arrayOffset(arrayField: string, offsetExpr: Expr): ArrayOffset; +export function arrayOffset( + arrayField: string, + offsetExpr: ScalarExpr +): ArrayOffset; /** * @beta @@ -3767,7 +3846,10 @@ export function arrayOffset(arrayField: string, offsetExpr: Expr): ArrayOffset; * @param offset The index of the element to return. * @return A new Expr representing the 'arrayOffset' operation. */ -export function arrayOffset(arrayExpression: Expr, offset: number): ArrayOffset; +export function arrayOffset( + arrayExpression: ScalarExpr, + offset: number +): ArrayOffset; /** * @beta @@ -3786,12 +3868,12 @@ export function arrayOffset(arrayExpression: Expr, offset: number): ArrayOffset; * @return A new Expr representing the 'arrayOffset' operation. */ export function arrayOffset( - arrayExpression: Expr, - offsetExpr: Expr + arrayExpression: ScalarExpr, + offsetExpr: ScalarExpr ): ArrayOffset; export function arrayOffset( - array: Expr | string, - offset: Expr | number + array: ScalarExpr | string, + offset: ScalarExpr | number ): ArrayOffset { return new ArrayOffset(fieldOfOrExpr(array), valueToDefaultExpr(offset)); } @@ -3819,7 +3901,7 @@ export function currentContext(): CurrentContext { * @beta */ export class IsError extends BooleanExpr { - constructor(private expr: Expr) { + constructor(private expr: ScalarExpr) { super('is_error', [expr]); } @@ -3839,7 +3921,7 @@ export class IsError extends BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isError' check. */ -export function isError(value: Expr): IsError { +export function isError(value: ScalarExpr): IsError { return new IsError(value); } @@ -3847,7 +3929,7 @@ export function isError(value: Expr): IsError { * @beta */ export class IfError extends FirestoreFunction { - constructor(private tryExpr: Expr, private catchExpr: Expr) { + constructor(private tryExpr: ScalarExpr, private catchExpr: ScalarExpr) { super('if_error', [tryExpr, catchExpr]); } } @@ -3869,7 +3951,7 @@ export class IfError extends FirestoreFunction { * returned if the tryExpr produces an error. * @return A new {@code Expr} representing the 'ifError' operation. */ -export function ifError(tryExpr: Expr, catchExpr: Expr): IfError; +export function ifError(tryExpr: ScalarExpr, catchExpr: ScalarExpr): IfError; /** * @beta @@ -3888,8 +3970,8 @@ export function ifError(tryExpr: Expr, catchExpr: Expr): IfError; * error. * @return A new {@code Expr} representing the 'ifError' operation. */ -export function ifError(tryExpr: Expr, catchValue: any): IfError; -export function ifError(tryExpr: Expr, catchValue: any): IfError { +export function ifError(tryExpr: ScalarExpr, catchValue: any): IfError; +export function ifError(tryExpr: ScalarExpr, catchValue: any): IfError { return new IfError(tryExpr, valueToDefaultExpr(catchValue)); } @@ -3897,7 +3979,7 @@ export function ifError(tryExpr: Expr, catchValue: any): IfError { * @beta */ export class IsAbsent extends BooleanExpr { - constructor(private expr: Expr) { + constructor(private expr: ScalarExpr) { super('is_absent', [expr]); } @@ -3918,7 +4000,7 @@ export class IsAbsent extends BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isAbsent' check. */ -export function isAbsent(value: Expr): IsAbsent; +export function isAbsent(value: ScalarExpr): IsAbsent; /** * @beta @@ -3935,7 +4017,7 @@ export function isAbsent(value: Expr): IsAbsent; * @return A new {@code Expr} representing the 'isAbsent' check. */ export function isAbsent(field: string): IsAbsent; -export function isAbsent(value: Expr | string): IsAbsent { +export function isAbsent(value: ScalarExpr | string): IsAbsent { return new IsAbsent(fieldOfOrExpr(value)); } @@ -3943,7 +4025,7 @@ export function isAbsent(value: Expr | string): IsAbsent { * @beta */ export class IsNull extends BooleanExpr { - constructor(private expr: Expr) { + constructor(private expr: ScalarExpr) { super('is_null', [expr]); } @@ -3963,7 +4045,7 @@ export class IsNull extends BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNull(value: Expr): IsNull; +export function isNull(value: ScalarExpr): IsNull; /** * @beta @@ -3979,7 +4061,7 @@ export function isNull(value: Expr): IsNull; * @return A new {@code Expr} representing the 'isNaN' check. */ export function isNull(value: string): IsNull; -export function isNull(value: Expr | string): IsNull { +export function isNull(value: ScalarExpr | string): IsNull { return new IsNull(fieldOfOrExpr(value)); } @@ -3987,7 +4069,7 @@ export function isNull(value: Expr | string): IsNull { * @beta */ export class IsNotNull extends BooleanExpr { - constructor(private expr: Expr) { + constructor(private expr: ScalarExpr) { super('is_not_null', [expr]); } @@ -4007,7 +4089,7 @@ export class IsNotNull extends BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNotNull(value: Expr): IsNotNull; +export function isNotNull(value: ScalarExpr): IsNotNull; /** * @beta @@ -4023,7 +4105,7 @@ export function isNotNull(value: Expr): IsNotNull; * @return A new {@code Expr} representing the 'isNaN' check. */ export function isNotNull(value: string): IsNotNull; -export function isNotNull(value: Expr | string): IsNotNull { +export function isNotNull(value: ScalarExpr | string): IsNotNull { return new IsNotNull(fieldOfOrExpr(value)); } @@ -4031,7 +4113,7 @@ export function isNotNull(value: Expr | string): IsNotNull { * @beta */ export class IsNotNan extends BooleanExpr { - constructor(private expr: Expr) { + constructor(private expr: ScalarExpr) { super('is_not_nan', [expr]); } @@ -4051,7 +4133,7 @@ export class IsNotNan extends BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isNotNaN' check. */ -export function isNotNan(value: Expr): IsNotNan; +export function isNotNan(value: ScalarExpr): IsNotNan; /** * @beta @@ -4067,7 +4149,7 @@ export function isNotNan(value: Expr): IsNotNan; * @return A new {@code Expr} representing the 'isNotNaN' check. */ export function isNotNan(value: string): IsNotNan; -export function isNotNan(value: Expr | string): IsNotNan { +export function isNotNan(value: ScalarExpr | string): IsNotNan { return new IsNotNan(fieldOfOrExpr(value)); } @@ -4075,7 +4157,7 @@ export function isNotNan(value: Expr | string): IsNotNan { * @beta */ export class MapRemove extends FirestoreFunction { - constructor(map: Expr, nameExpr: Expr) { + constructor(map: ScalarExpr, nameExpr: ScalarExpr) { super('map_remove', [map, nameExpr]); } } @@ -4106,7 +4188,7 @@ export function mapRemove(mapField: string, key: string): MapRemove; * @param mapExpr An expression return a map value. * @param key The name of the key to remove from the input map. */ -export function mapRemove(mapExpr: Expr, key: string): MapRemove; +export function mapRemove(mapExpr: ScalarExpr, key: string): MapRemove; /** * @beta * @@ -4120,7 +4202,7 @@ export function mapRemove(mapExpr: Expr, key: string): MapRemove; * @param mapField The name of a field containing a map value. * @param keyExpr An expression that produces the name of the key to remove from the input map. */ -export function mapRemove(mapField: string, keyExpr: Expr): MapRemove; +export function mapRemove(mapField: string, keyExpr: ScalarExpr): MapRemove; /** * @beta * @@ -4134,11 +4216,11 @@ export function mapRemove(mapField: string, keyExpr: Expr): MapRemove; * @param mapExpr An expression return a map value. * @param keyExpr An expression that produces the name of the key to remove from the input map. */ -export function mapRemove(mapExpr: Expr, keyExpr: Expr): MapRemove; +export function mapRemove(mapExpr: ScalarExpr, keyExpr: ScalarExpr): MapRemove; export function mapRemove( - mapExpr: Expr | string, - stringExpr: Expr | string + mapExpr: ScalarExpr | string, + stringExpr: ScalarExpr | string ): MapRemove { return new MapRemove(fieldOfOrExpr(mapExpr), valueToDefaultExpr(stringExpr)); } @@ -4147,7 +4229,7 @@ export function mapRemove( * @beta */ export class MapMerge extends FirestoreFunction { - constructor(maps: Expr[]) { + constructor(maps: ScalarExpr[]) { super('map_merge', maps); } } @@ -4171,8 +4253,8 @@ export class MapMerge extends FirestoreFunction { */ export function mapMerge( mapField: string, - secondMap: Record | Expr, - ...otherMaps: Array | Expr> + secondMap: Record | ScalarExpr, + ...otherMaps: Array | ScalarExpr> ): MapMerge; /** @@ -4193,15 +4275,15 @@ export function mapMerge( * as a literal or an expression that returns a map. */ export function mapMerge( - firstMap: Record | Expr, - secondMap: Record | Expr, - ...otherMaps: Array | Expr> + firstMap: Record | ScalarExpr, + secondMap: Record | ScalarExpr, + ...otherMaps: Array | ScalarExpr> ): MapMerge; export function mapMerge( - firstMap: string | Record | Expr, - secondMap: Record | Expr, - ...otherMaps: Array | Expr> + firstMap: string | Record | ScalarExpr, + secondMap: Record | ScalarExpr, + ...otherMaps: Array | ScalarExpr> ): MapMerge { const firstMapExpr = typeof firstMap === 'string' @@ -4216,17 +4298,17 @@ export function mapMerge( * @beta */ export class Parent extends FirestoreFunction { - constructor(pathExpr: Expr) { + constructor(pathExpr: ScalarExpr) { super('parent', [pathExpr]); } } export function parentFunction(path: string | DocumentReference): Parent; -export function parentFunction(pathExpr: Expr): Parent; +export function parentFunction(pathExpr: ScalarExpr): Parent; export function parentFunction( - path: Expr | string | DocumentReference + path: ScalarExpr | string | DocumentReference ): Parent { // @ts-ignore const pathExpr = valueToDefaultExpr(path); @@ -4237,17 +4319,17 @@ export function parentFunction( * @beta */ export class CollectionId extends FirestoreFunction { - constructor(pathExpr: Expr) { + constructor(pathExpr: ScalarExpr) { super('collection_id', [pathExpr]); } } export function collectionId(path: string | DocumentReference): CollectionId; -export function collectionId(pathExpr: Expr): CollectionId; +export function collectionId(pathExpr: ScalarExpr): CollectionId; export function collectionId( - path: Expr | string | DocumentReference + path: ScalarExpr | string | DocumentReference ): CollectionId { // @ts-ignore const pathExpr = valueToDefaultExpr(path); @@ -4258,7 +4340,7 @@ export function collectionId( * @beta */ export class DocumentId extends FirestoreFunction { - constructor(pathExpr: Expr) { + constructor(pathExpr: ScalarExpr) { super('document_id', [pathExpr]); } } @@ -4291,10 +4373,10 @@ export function documentIdFunction( * * @return A new {@code Expr} representing the documentId operation. */ -export function documentIdFunction(documentPathExpr: Expr): DocumentId; +export function documentIdFunction(documentPathExpr: ScalarExpr): DocumentId; export function documentIdFunction( - documentPath: Expr | string | DocumentReference + documentPath: ScalarExpr | string | DocumentReference ): DocumentId { // @ts-ignore const documentPathExpr = valueToDefaultExpr(documentPath); @@ -4305,18 +4387,21 @@ export function documentIdFunction( * @beta */ export class Key extends FirestoreFunction { - constructor(namespaceExpr: Expr, pathExpr: Expr) { + constructor(namespaceExpr: ScalarExpr, pathExpr: ScalarExpr) { super('key', [namespaceExpr, pathExpr]); } } export function key(namespace: string, path: string): Key; -export function key(namespaceExpr: Expr, pathExpr: Expr): Key; +export function key(namespaceExpr: ScalarExpr, pathExpr: ScalarExpr): Key; -export function key(namespace: Expr | string, path: Expr | string): Key { +export function key( + namespace: ScalarExpr | string, + path: ScalarExpr | string +): Key { const namespaceExpr = valueToDefaultExpr(namespace); - const pathExpr = path instanceof Expr ? path : Constant.of(path); + const pathExpr = path instanceof ScalarExpr ? path : Constant.of(path); return new Key(namespaceExpr, pathExpr); } @@ -4324,7 +4409,11 @@ export function key(namespace: Expr | string, path: Expr | string): Key { * @beta */ export class Substr extends FirestoreFunction { - constructor(inputExpr: Expr, position: Expr, length: Expr | undefined) { + constructor( + inputExpr: ScalarExpr, + position: ScalarExpr, + length: ScalarExpr | undefined + ) { if (length) { super('substr', [inputExpr, position, length]); } else { @@ -4357,7 +4446,11 @@ export function substr( * @param position Index of the first character of the substring. * @param length Length of the substring. */ -export function substr(input: Expr, position: number, length?: number): Substr; +export function substr( + input: ScalarExpr, + position: number, + length?: number +): Substr; /** * @beta @@ -4368,7 +4461,11 @@ export function substr(input: Expr, position: number, length?: number): Substr; * @param position An expression that returns the index of the first character of the substring. * @param length An expression that returns the length of the substring. */ -export function substr(field: string, position: Expr, length?: Expr): Substr; +export function substr( + field: string, + position: ScalarExpr, + length?: ScalarExpr +): Substr; /** * @beta @@ -4379,12 +4476,16 @@ export function substr(field: string, position: Expr, length?: Expr): Substr; * @param position An expression that returns the index of the first character of the substring. * @param length An expression that returns the length of the substring. */ -export function substr(input: Expr, position: Expr, length?: Expr): Substr; +export function substr( + input: ScalarExpr, + position: ScalarExpr, + length?: ScalarExpr +): Substr; export function substr( - field: Expr | string, - position: Expr | number, - length?: Expr | number + field: ScalarExpr | string, + position: ScalarExpr | number, + length?: ScalarExpr | number ): Substr { const fieldExpr = fieldOfOrExpr(field); const positionExpr = valueToDefaultExpr(position); @@ -4397,7 +4498,7 @@ export function substr( * @beta */ export class ManhattanDistance extends FirestoreFunction { - constructor(vector1: Expr, vector2: Expr) { + constructor(vector1: ScalarExpr, vector2: ScalarExpr) { super('manhattan_distance', [vector1, vector2]); } } @@ -4454,7 +4555,10 @@ export function manhattanDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ -export function manhattanDistance(expr: string, other: Expr): ManhattanDistance; +export function manhattanDistance( + expr: string, + other: ScalarExpr +): ManhattanDistance; /** * @beta @@ -4472,7 +4576,7 @@ export function manhattanDistance(expr: string, other: Expr): ManhattanDistance; * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ export function manhattanDistance( - expr: Expr, + expr: ScalarExpr, other: number[] ): ManhattanDistance; @@ -4491,7 +4595,7 @@ export function manhattanDistance( * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ export function manhattanDistance( - expr: Expr, + expr: ScalarExpr, other: VectorValue ): ManhattanDistance; @@ -4509,13 +4613,16 @@ export function manhattanDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ -export function manhattanDistance(expr: Expr, other: Expr): ManhattanDistance; export function manhattanDistance( - fieldOrExpr: Expr | string, - other: Expr | number[] | VectorValue + expr: ScalarExpr, + other: ScalarExpr +): ManhattanDistance; +export function manhattanDistance( + fieldOrExpr: ScalarExpr | string, + other: ScalarExpr | number[] | VectorValue ): ManhattanDistance { const expr1 = fieldOfOrExpr(fieldOrExpr); - const expr2 = other instanceof Expr ? other : Constant.vector(other); + const expr2 = other instanceof ScalarExpr ? other : Constant.vector(other); return new ManhattanDistance(expr1, expr2); } @@ -4535,9 +4642,9 @@ export function manhattanDistance( * @return A new {@code Expr} representing the addition operation. */ export function add( - first: Expr, - second: Expr | any, - ...others: Array + first: ScalarExpr, + second: ScalarExpr | any, + ...others: Array ): Add; /** @@ -4557,11 +4664,14 @@ export function add( */ export function add( fieldName: string, - second: Expr | any, - ...others: Array + second: ScalarExpr | any, + ...others: Array ): Add; -export function add(first: Expr | string, ...others: Array): Add { +export function add( + first: ScalarExpr | string, + ...others: Array +): Add { const normalizedLeft = fieldOfOrExpr(first); const normalizedRight = others.map(value => valueToDefaultExpr(value)); return new Add(normalizedLeft, normalizedRight); @@ -4581,7 +4691,7 @@ export function add(first: Expr | string, ...others: Array): Add { * @param right The expression to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: Expr, right: Expr): Subtract; +export function subtract(left: ScalarExpr, right: ScalarExpr): Subtract; /** * @beta @@ -4597,7 +4707,7 @@ export function subtract(left: Expr, right: Expr): Subtract; * @param right The constant value to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: Expr, right: any): Subtract; +export function subtract(left: ScalarExpr, right: any): Subtract; /** * @beta @@ -4613,7 +4723,7 @@ export function subtract(left: Expr, right: any): Subtract; * @param right The expression to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: string, right: Expr): Subtract; +export function subtract(left: string, right: ScalarExpr): Subtract; /** * @beta @@ -4630,10 +4740,13 @@ export function subtract(left: string, right: Expr): Subtract; * @return A new {@code Expr} representing the subtraction operation. */ export function subtract(left: string, right: any): Subtract; -export function subtract(left: Expr | string, right: Expr | any): Subtract { +export function subtract( + left: ScalarExpr | string, + right: ScalarExpr | any +): Subtract { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; const normalizedRight = - right instanceof Expr ? right : valueToDefaultExpr(right); + right instanceof ScalarExpr ? right : valueToDefaultExpr(right); return new Subtract(normalizedLeft, normalizedRight); } @@ -4653,9 +4766,9 @@ export function subtract(left: Expr | string, right: Expr | any): Subtract { * @return A new {@code Expr} representing the multiplication operation. */ export function multiply( - first: Expr, - second: Expr | any, - ...others: Array + first: ScalarExpr, + second: ScalarExpr | any, + ...others: Array ): Multiply; /** @@ -4675,13 +4788,13 @@ export function multiply( */ export function multiply( fieldName: string, - second: Expr | any, - ...others: Array + second: ScalarExpr | any, + ...others: Array ): Multiply; export function multiply( - left: Expr | string, - ...others: Array + left: ScalarExpr | string, + ...others: Array ): Multiply { const normalizedLeft = fieldOfOrExpr(left); const normalizedRight = others.map(value => valueToDefaultExpr(value)); @@ -4702,7 +4815,7 @@ export function multiply( * @param right The expression to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: Expr, right: Expr): Divide; +export function divide(left: ScalarExpr, right: ScalarExpr): Divide; /** * @beta @@ -4718,7 +4831,7 @@ export function divide(left: Expr, right: Expr): Divide; * @param right The constant value to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: Expr, right: any): Divide; +export function divide(left: ScalarExpr, right: any): Divide; /** * @beta @@ -4734,7 +4847,7 @@ export function divide(left: Expr, right: any): Divide; * @param right The expression to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: string, right: Expr): Divide; +export function divide(left: string, right: ScalarExpr): Divide; /** * @beta @@ -4751,10 +4864,13 @@ export function divide(left: string, right: Expr): Divide; * @return A new {@code Expr} representing the division operation. */ export function divide(left: string, right: any): Divide; -export function divide(left: Expr | string, right: Expr | any): Divide { +export function divide( + left: ScalarExpr | string, + right: ScalarExpr | any +): Divide { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; const normalizedRight = - right instanceof Expr ? right : valueToDefaultExpr(right); + right instanceof ScalarExpr ? right : valueToDefaultExpr(right); return new Divide(normalizedLeft, normalizedRight); } @@ -4772,7 +4888,7 @@ export function divide(left: Expr | string, right: Expr | any): Divide { * @param right The divisor expression. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: Expr, right: Expr): Mod; +export function mod(left: ScalarExpr, right: ScalarExpr): Mod; /** * @beta @@ -4788,7 +4904,7 @@ export function mod(left: Expr, right: Expr): Mod; * @param right The divisor constant. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: Expr, right: any): Mod; +export function mod(left: ScalarExpr, right: any): Mod; /** * @beta @@ -4804,7 +4920,7 @@ export function mod(left: Expr, right: any): Mod; * @param right The divisor expression. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: string, right: Expr): Mod; +export function mod(left: string, right: ScalarExpr): Mod; /** * @beta @@ -4821,10 +4937,10 @@ export function mod(left: string, right: Expr): Mod; * @return A new {@code Expr} representing the modulo operation. */ export function mod(left: string, right: any): Mod; -export function mod(left: Expr | string, right: Expr | any): Mod { +export function mod(left: ScalarExpr | string, right: ScalarExpr | any): Mod { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; const normalizedRight = - right instanceof Expr ? right : valueToDefaultExpr(right); + right instanceof ScalarExpr ? right : valueToDefaultExpr(right); return new Mod(normalizedLeft, normalizedRight); } @@ -4852,7 +4968,7 @@ export function map(elements: Record): MapFunction { * @param plainObject */ export function _mapValue(plainObject: Record): MapValue { - const result: Map = new Map(); + const result: Map = new Map(); for (const key in plainObject) { if (Object.prototype.hasOwnProperty.call(plainObject, key)) { const value = plainObject[key]; @@ -5268,7 +5384,7 @@ export function array(elements: any[]): ArrayFunction { * @param right The second expression to compare. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: Expr, right: Expr): Eq; +export function eq(left: ScalarExpr, right: ScalarExpr): Eq; /** * @beta @@ -5284,7 +5400,7 @@ export function eq(left: Expr, right: Expr): Eq; * @param right The constant value to compare to. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: Expr, right: any): Eq; +export function eq(left: ScalarExpr, right: any): Eq; /** * @beta @@ -5300,7 +5416,7 @@ export function eq(left: Expr, right: any): Eq; * @param right The expression to compare to. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: string, right: Expr): Eq; +export function eq(left: string, right: ScalarExpr): Eq; /** * @beta @@ -5317,9 +5433,10 @@ export function eq(left: string, right: Expr): Eq; * @return A new `Expr` representing the equality comparison. */ export function eq(left: string, right: any): Eq; -export function eq(left: Expr | string, right: any): Eq { - const leftExpr = left instanceof Expr ? left : Field.of(left); - const rightExpr = right instanceof Expr ? right : valueToDefaultExpr(right); +export function eq(left: ScalarExpr | string, right: any): Eq { + const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); + const rightExpr = + right instanceof ScalarExpr ? right : valueToDefaultExpr(right); return new Eq(leftExpr, rightExpr); } @@ -5337,7 +5454,7 @@ export function eq(left: Expr | string, right: any): Eq { * @param right The second expression to compare. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: Expr, right: Expr): Neq; +export function neq(left: ScalarExpr, right: ScalarExpr): Neq; /** * @beta @@ -5353,7 +5470,7 @@ export function neq(left: Expr, right: Expr): Neq; * @param right The constant value to compare to. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: Expr, right: any): Neq; +export function neq(left: ScalarExpr, right: any): Neq; /** * @beta @@ -5369,7 +5486,7 @@ export function neq(left: Expr, right: any): Neq; * @param right The expression to compare to. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: string, right: Expr): Neq; +export function neq(left: string, right: ScalarExpr): Neq; /** * @beta @@ -5386,9 +5503,10 @@ export function neq(left: string, right: Expr): Neq; * @return A new `Expr` representing the inequality comparison. */ export function neq(left: string, right: any): Neq; -export function neq(left: Expr | string, right: any): Neq { - const leftExpr = left instanceof Expr ? left : Field.of(left); - const rightExpr = right instanceof Expr ? right : valueToDefaultExpr(right); +export function neq(left: ScalarExpr | string, right: any): Neq { + const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); + const rightExpr = + right instanceof ScalarExpr ? right : valueToDefaultExpr(right); return new Neq(leftExpr, rightExpr); } @@ -5406,7 +5524,7 @@ export function neq(left: Expr | string, right: any): Neq { * @param right The second expression to compare. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: Expr, right: Expr): Lt; +export function lt(left: ScalarExpr, right: ScalarExpr): Lt; /** * @beta @@ -5422,7 +5540,7 @@ export function lt(left: Expr, right: Expr): Lt; * @param right The constant value to compare to. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: Expr, right: any): Lt; +export function lt(left: ScalarExpr, right: any): Lt; /** * @beta @@ -5438,7 +5556,7 @@ export function lt(left: Expr, right: any): Lt; * @param right The expression to compare to. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: string, right: Expr): Lt; +export function lt(left: string, right: ScalarExpr): Lt; /** * @beta @@ -5455,9 +5573,10 @@ export function lt(left: string, right: Expr): Lt; * @return A new `Expr` representing the less than comparison. */ export function lt(left: string, right: any): Lt; -export function lt(left: Expr | string, right: any): Lt { - const leftExpr = left instanceof Expr ? left : Field.of(left); - const rightExpr = right instanceof Expr ? right : valueToDefaultExpr(right); +export function lt(left: ScalarExpr | string, right: any): Lt { + const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); + const rightExpr = + right instanceof ScalarExpr ? right : valueToDefaultExpr(right); return new Lt(leftExpr, rightExpr); } @@ -5476,7 +5595,7 @@ export function lt(left: Expr | string, right: any): Lt { * @param right The second expression to compare. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: Expr, right: Expr): Lte; +export function lte(left: ScalarExpr, right: ScalarExpr): Lte; /** * @beta @@ -5492,7 +5611,7 @@ export function lte(left: Expr, right: Expr): Lte; * @param right The constant value to compare to. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: Expr, right: any): Lte; +export function lte(left: ScalarExpr, right: any): Lte; /** * Creates an expression that checks if a field's value is less than or equal to an expression. @@ -5506,7 +5625,7 @@ export function lte(left: Expr, right: any): Lte; * @param right The expression to compare to. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: string, right: Expr): Lte; +export function lte(left: string, right: ScalarExpr): Lte; /** * @beta @@ -5523,9 +5642,10 @@ export function lte(left: string, right: Expr): Lte; * @return A new `Expr` representing the less than or equal to comparison. */ export function lte(left: string, right: any): Lte; -export function lte(left: Expr | string, right: any): Lte { - const leftExpr = left instanceof Expr ? left : Field.of(left); - const rightExpr = right instanceof Expr ? right : valueToDefaultExpr(right); +export function lte(left: ScalarExpr | string, right: any): Lte { + const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); + const rightExpr = + right instanceof ScalarExpr ? right : valueToDefaultExpr(right); return new Lte(leftExpr, rightExpr); } @@ -5544,7 +5664,7 @@ export function lte(left: Expr | string, right: any): Lte { * @param right The second expression to compare. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: Expr, right: Expr): Gt; +export function gt(left: ScalarExpr, right: ScalarExpr): Gt; /** * @beta @@ -5560,7 +5680,7 @@ export function gt(left: Expr, right: Expr): Gt; * @param right The constant value to compare to. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: Expr, right: any): Gt; +export function gt(left: ScalarExpr, right: any): Gt; /** * @beta @@ -5576,7 +5696,7 @@ export function gt(left: Expr, right: any): Gt; * @param right The expression to compare to. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: string, right: Expr): Gt; +export function gt(left: string, right: ScalarExpr): Gt; /** * @beta @@ -5593,9 +5713,10 @@ export function gt(left: string, right: Expr): Gt; * @return A new `Expr` representing the greater than comparison. */ export function gt(left: string, right: any): Gt; -export function gt(left: Expr | string, right: any): Gt { - const leftExpr = left instanceof Expr ? left : Field.of(left); - const rightExpr = right instanceof Expr ? right : valueToDefaultExpr(right); +export function gt(left: ScalarExpr | string, right: any): Gt { + const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); + const rightExpr = + right instanceof ScalarExpr ? right : valueToDefaultExpr(right); return new Gt(leftExpr, rightExpr); } @@ -5614,7 +5735,7 @@ export function gt(left: Expr | string, right: any): Gt { * @param right The second expression to compare. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: Expr, right: Expr): Gte; +export function gte(left: ScalarExpr, right: ScalarExpr): Gte; /** * @beta @@ -5631,7 +5752,7 @@ export function gte(left: Expr, right: Expr): Gte; * @param right The constant value to compare to. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: Expr, right: any): Gte; +export function gte(left: ScalarExpr, right: any): Gte; /** * @beta @@ -5647,7 +5768,7 @@ export function gte(left: Expr, right: any): Gte; * @param right The expression to compare to. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: string, right: Expr): Gte; +export function gte(left: string, right: ScalarExpr): Gte; /** * @beta @@ -5665,9 +5786,10 @@ export function gte(left: string, right: Expr): Gte; * @return A new `Expr` representing the greater than or equal to comparison. */ export function gte(left: string, right: any): Gte; -export function gte(left: Expr | string, right: any): Gte { - const leftExpr = left instanceof Expr ? left : Field.of(left); - const rightExpr = right instanceof Expr ? right : valueToDefaultExpr(right); +export function gte(left: ScalarExpr | string, right: any): Gte { + const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); + const rightExpr = + right instanceof ScalarExpr ? right : valueToDefaultExpr(right); return new Gte(leftExpr, rightExpr); } @@ -5687,9 +5809,9 @@ export function gte(left: Expr | string, right: any): Gte { * @return A new {@code Expr} representing the concatenated array. */ export function arrayConcat( - firstArray: Expr, - secondArray: Expr | any, - ...otherArrays: Array + firstArray: ScalarExpr, + secondArray: ScalarExpr | any, + ...otherArrays: Array ): ArrayConcat; /** @@ -5709,13 +5831,13 @@ export function arrayConcat( */ export function arrayConcat( firstArrayField: string, - secondArray: Expr | any[], - ...otherArrays: Array + secondArray: ScalarExpr | any[], + ...otherArrays: Array ): ArrayConcat; export function arrayConcat( - firstArray: Expr | string, - ...otherArrays: Array + firstArray: ScalarExpr | string, + ...otherArrays: Array ): ArrayConcat { const arrayExpr = fieldOfOrExpr(firstArray); const exprValues = otherArrays.map(element => valueToDefaultExpr(element)); @@ -5736,7 +5858,10 @@ export function arrayConcat( * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains(array: Expr, element: Expr): ArrayContains; +export function arrayContains( + array: ScalarExpr, + element: ScalarExpr +): ArrayContains; /** * @beta @@ -5752,7 +5877,7 @@ export function arrayContains(array: Expr, element: Expr): ArrayContains; * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains(array: Expr, element: any): ArrayContains; +export function arrayContains(array: ScalarExpr, element: any): ArrayContains; /** * @beta @@ -5768,7 +5893,10 @@ export function arrayContains(array: Expr, element: any): ArrayContains; * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains(array: string, element: Expr): ArrayContains; +export function arrayContains( + array: string, + element: ScalarExpr +): ArrayContains; /** * @beta @@ -5786,12 +5914,12 @@ export function arrayContains(array: string, element: Expr): ArrayContains; */ export function arrayContains(array: string, element: any): ArrayContains; export function arrayContains( - array: Expr | string, + array: ScalarExpr | string, element: any ): ArrayContains { - const arrayExpr = array instanceof Expr ? array : Field.of(array); + const arrayExpr = array instanceof ScalarExpr ? array : Field.of(array); const elementExpr = - element instanceof Expr ? element : valueToDefaultExpr(element); + element instanceof ScalarExpr ? element : valueToDefaultExpr(element); return new ArrayContains(arrayExpr, elementExpr); } @@ -5810,7 +5938,10 @@ export function arrayContains( * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_any' comparison. */ -export function arrayContainsAny(array: Expr, values: Expr[]): ArrayContainsAny; +export function arrayContainsAny( + array: ScalarExpr, + values: ScalarExpr[] +): ArrayContainsAny; /** * @beta @@ -5827,7 +5958,10 @@ export function arrayContainsAny(array: Expr, values: Expr[]): ArrayContainsAny; * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_any' comparison. */ -export function arrayContainsAny(array: Expr, values: any[]): ArrayContainsAny; +export function arrayContainsAny( + array: ScalarExpr, + values: any[] +): ArrayContainsAny; /** * @beta @@ -5847,7 +5981,7 @@ export function arrayContainsAny(array: Expr, values: any[]): ArrayContainsAny; */ export function arrayContainsAny( array: string, - values: Expr[] + values: ScalarExpr[] ): ArrayContainsAny; /** @@ -5871,12 +6005,12 @@ export function arrayContainsAny( values: any[] ): ArrayContainsAny; export function arrayContainsAny( - array: Expr | string, + array: ScalarExpr | string, values: any[] ): ArrayContainsAny { - const arrayExpr = array instanceof Expr ? array : Field.of(array); + const arrayExpr = array instanceof ScalarExpr ? array : Field.of(array); const exprValues = values.map(value => - value instanceof Expr ? value : valueToDefaultExpr(value) + value instanceof ScalarExpr ? value : valueToDefaultExpr(value) ); return new ArrayContainsAny(arrayExpr, exprValues); } @@ -5895,7 +6029,10 @@ export function arrayContainsAny( * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_all' comparison. */ -export function arrayContainsAll(array: Expr, values: Expr[]): ArrayContainsAll; +export function arrayContainsAll( + array: ScalarExpr, + values: ScalarExpr[] +): ArrayContainsAll; /** * @beta @@ -5911,7 +6048,10 @@ export function arrayContainsAll(array: Expr, values: Expr[]): ArrayContainsAll; * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_all' comparison. */ -export function arrayContainsAll(array: Expr, values: any[]): ArrayContainsAll; +export function arrayContainsAll( + array: ScalarExpr, + values: any[] +): ArrayContainsAll; /** * @beta @@ -5930,7 +6070,7 @@ export function arrayContainsAll(array: Expr, values: any[]): ArrayContainsAll; */ export function arrayContainsAll( array: string, - values: Expr[] + values: ScalarExpr[] ): ArrayContainsAll; /** @@ -5953,12 +6093,12 @@ export function arrayContainsAll( values: any[] ): ArrayContainsAll; export function arrayContainsAll( - array: Expr | string, + array: ScalarExpr | string, values: any[] ): ArrayContainsAll { - const arrayExpr = array instanceof Expr ? array : Field.of(array); + const arrayExpr = array instanceof ScalarExpr ? array : Field.of(array); const exprValues = values.map(value => - value instanceof Expr ? value : valueToDefaultExpr(value) + value instanceof ScalarExpr ? value : valueToDefaultExpr(value) ); return new ArrayContainsAll(arrayExpr, exprValues); } @@ -5976,7 +6116,7 @@ export function arrayContainsAll( * @param array The array expression to calculate the length of. * @return A new {@code Expr} representing the length of the array. */ -export function arrayLength(array: Expr): ArrayLength { +export function arrayLength(array: ScalarExpr): ArrayLength { return new ArrayLength(array); } @@ -5995,7 +6135,7 @@ export function arrayLength(array: Expr): ArrayLength { * @param others The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: Expr, others: Expr[]): EqAny; +export function eqAny(element: ScalarExpr, others: ScalarExpr[]): EqAny; /** * @beta @@ -6012,7 +6152,7 @@ export function eqAny(element: Expr, others: Expr[]): EqAny; * @param others The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: Expr, others: any[]): EqAny; +export function eqAny(element: ScalarExpr, others: any[]): EqAny; /** * @beta @@ -6029,7 +6169,7 @@ export function eqAny(element: Expr, others: any[]): EqAny; * @param others The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: string, others: Expr[]): EqAny; +export function eqAny(element: string, others: ScalarExpr[]): EqAny; /** * @beta @@ -6047,10 +6187,11 @@ export function eqAny(element: string, others: Expr[]): EqAny; * @return A new {@code Expr} representing the 'IN' comparison. */ export function eqAny(element: string, others: any[]): EqAny; -export function eqAny(element: Expr | string, others: any[]): EqAny { - const elementExpr = element instanceof Expr ? element : Field.of(element); +export function eqAny(element: ScalarExpr | string, others: any[]): EqAny { + const elementExpr = + element instanceof ScalarExpr ? element : Field.of(element); const exprOthers = others.map(other => - other instanceof Expr ? other : valueToDefaultExpr(other) + other instanceof ScalarExpr ? other : valueToDefaultExpr(other) ); return new EqAny(elementExpr, exprOthers); } @@ -6070,7 +6211,7 @@ export function eqAny(element: Expr | string, others: any[]): EqAny { * @param others The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: Expr, others: Expr[]): NotEqAny; +export function notEqAny(element: ScalarExpr, others: ScalarExpr[]): NotEqAny; /** * @beta @@ -6087,7 +6228,7 @@ export function notEqAny(element: Expr, others: Expr[]): NotEqAny; * @param others The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: Expr, others: any[]): NotEqAny; +export function notEqAny(element: ScalarExpr, others: any[]): NotEqAny; /** * @beta @@ -6104,7 +6245,7 @@ export function notEqAny(element: Expr, others: any[]): NotEqAny; * @param others The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: string, others: Expr[]): NotEqAny; +export function notEqAny(element: string, others: ScalarExpr[]): NotEqAny; /** * @beta @@ -6122,10 +6263,14 @@ export function notEqAny(element: string, others: Expr[]): NotEqAny; * @return A new {@code Expr} representing the 'NOT IN' comparison. */ export function notEqAny(element: string, others: any[]): NotEqAny; -export function notEqAny(element: Expr | string, others: any[]): NotEqAny { - const elementExpr = element instanceof Expr ? element : Field.of(element); +export function notEqAny( + element: ScalarExpr | string, + others: any[] +): NotEqAny { + const elementExpr = + element instanceof ScalarExpr ? element : Field.of(element); const exprOthers = others.map(other => - other instanceof Expr ? other : valueToDefaultExpr(other) + other instanceof ScalarExpr ? other : valueToDefaultExpr(other) ); return new NotEqAny(elementExpr, exprOthers); } @@ -6177,8 +6322,8 @@ export function xor( */ export function cond( condition: BooleanExpr, - thenExpr: Expr, - elseExpr: Expr + thenExpr: ScalarExpr, + elseExpr: ScalarExpr ): Cond { return new Cond(condition, thenExpr, elseExpr); } @@ -6216,9 +6361,9 @@ export function not(filter: BooleanExpr): Not { * @return A new {@code Expr} representing the logical max operation. */ export function logicalMaximum( - first: Expr, - second: Expr | any, - ...others: Array + first: ScalarExpr, + second: ScalarExpr | any, + ...others: Array ): LogicalMaximum; /** @@ -6238,13 +6383,13 @@ export function logicalMaximum( */ export function logicalMaximum( left: string, - second: Expr | any, - ...others: Array + second: ScalarExpr | any, + ...others: Array ): LogicalMaximum; export function logicalMaximum( - first: Expr | string, - ...others: Array + first: ScalarExpr | string, + ...others: Array ): LogicalMaximum { return new LogicalMaximum( fieldOfOrExpr(first), @@ -6268,9 +6413,9 @@ export function logicalMaximum( * @return A new {@code Expr} representing the logical min operation. */ export function logicalMinimum( - first: Expr, - second: Expr | any, - ...others: Array + first: ScalarExpr, + second: ScalarExpr | any, + ...others: Array ): LogicalMinimum; /** @@ -6290,13 +6435,13 @@ export function logicalMinimum( */ export function logicalMinimum( fieldName: string, - second: Expr | any, - ...others: Array + second: ScalarExpr | any, + ...others: Array ): LogicalMinimum; export function logicalMinimum( - first: Expr | string, - ...others: Array + first: ScalarExpr | string, + ...others: Array ): LogicalMinimum { return new LogicalMinimum( fieldOfOrExpr(first), @@ -6317,7 +6462,7 @@ export function logicalMinimum( * @param value An expression evaluates to the name of the field to check. * @return A new {@code Expr} representing the 'exists' check. */ -export function exists(value: Expr): Exists; +export function exists(value: ScalarExpr): Exists; /** * @beta @@ -6333,9 +6478,9 @@ export function exists(value: Expr): Exists; * @return A new {@code Expr} representing the 'exists' check. */ export function exists(field: string): Exists; -export function exists(valueOrField: Expr | string): Exists { +export function exists(valueOrField: ScalarExpr | string): Exists { const valueExpr = - valueOrField instanceof Expr ? valueOrField : Field.of(valueOrField); + valueOrField instanceof ScalarExpr ? valueOrField : Field.of(valueOrField); return new Exists(valueExpr); } @@ -6352,7 +6497,7 @@ export function exists(valueOrField: Expr | string): Exists { * @param value The expression to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNan(value: Expr): IsNan; +export function isNan(value: ScalarExpr): IsNan; /** * @beta @@ -6368,8 +6513,8 @@ export function isNan(value: Expr): IsNan; * @return A new {@code Expr} representing the 'isNaN' check. */ export function isNan(value: string): IsNan; -export function isNan(value: Expr | string): IsNan { - const valueExpr = value instanceof Expr ? value : Field.of(value); +export function isNan(value: ScalarExpr | string): IsNan { + const valueExpr = value instanceof ScalarExpr ? value : Field.of(value); return new IsNan(valueExpr); } @@ -6386,7 +6531,7 @@ export function isNan(value: Expr | string): IsNan { * @param expr The expression representing the string to reverse. * @return A new {@code Expr} representing the reversed string. */ -export function reverse(expr: Expr): Reverse; +export function reverse(expr: ScalarExpr): Reverse; /** * @beta @@ -6402,7 +6547,7 @@ export function reverse(expr: Expr): Reverse; * @return A new {@code Expr} representing the reversed string. */ export function reverse(field: string): Reverse; -export function reverse(expr: Expr | string): Reverse { +export function reverse(expr: ScalarExpr | string): Reverse { const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; return new Reverse(normalizedExpr); } @@ -6423,7 +6568,7 @@ export function reverse(expr: Expr | string): Reverse { * @return A new {@code Expr} representing the string with the first occurrence replaced. */ export function replaceFirst( - value: Expr, + value: ScalarExpr, find: string, replace: string ): ReplaceFirst; @@ -6445,9 +6590,9 @@ export function replaceFirst( * @return A new {@code Expr} representing the string with the first occurrence replaced. */ export function replaceFirst( - value: Expr, - find: Expr, - replace: Expr + value: ScalarExpr, + find: ScalarExpr, + replace: ScalarExpr ): ReplaceFirst; /** @@ -6471,9 +6616,9 @@ export function replaceFirst( replace: string ): ReplaceFirst; export function replaceFirst( - value: Expr | string, - find: Expr | string, - replace: Expr | string + value: ScalarExpr | string, + find: ScalarExpr | string, + replace: ScalarExpr | string ): ReplaceFirst { const normalizedValue = typeof value === 'string' ? Field.of(value) : value; const normalizedFind = typeof find === 'string' ? Constant.of(find) : find; @@ -6498,7 +6643,7 @@ export function replaceFirst( * @return A new {@code Expr} representing the string with all occurrences replaced. */ export function replaceAll( - value: Expr, + value: ScalarExpr, find: string, replace: string ): ReplaceAll; @@ -6519,7 +6664,11 @@ export function replaceAll( * @param replace The expression representing the substring to replace all occurrences of 'find' with. * @return A new {@code Expr} representing the string with all occurrences replaced. */ -export function replaceAll(value: Expr, find: Expr, replace: Expr): ReplaceAll; +export function replaceAll( + value: ScalarExpr, + find: ScalarExpr, + replace: ScalarExpr +): ReplaceAll; /** * @beta @@ -6542,9 +6691,9 @@ export function replaceAll( replace: string ): ReplaceAll; export function replaceAll( - value: Expr | string, - find: Expr | string, - replace: Expr | string + value: ScalarExpr | string, + find: ScalarExpr | string, + replace: ScalarExpr | string ): ReplaceAll { const normalizedValue = typeof value === 'string' ? Field.of(value) : value; const normalizedFind = typeof find === 'string' ? Constant.of(find) : find; @@ -6566,7 +6715,7 @@ export function replaceAll( * @param expr The expression representing the string. * @return A new {@code Expr} representing the length of the string in bytes. */ -export function byteLength(expr: Expr): ByteLength; +export function byteLength(expr: ScalarExpr): ByteLength; /** * @beta @@ -6582,7 +6731,7 @@ export function byteLength(expr: Expr): ByteLength; * @return A new {@code Expr} representing the length of the string in bytes. */ export function byteLength(field: string): ByteLength; -export function byteLength(expr: Expr | string): ByteLength { +export function byteLength(expr: ScalarExpr | string): ByteLength { const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; return new ByteLength(normalizedExpr); } @@ -6615,9 +6764,9 @@ export function charLength(field: string): CharLength; * @param expr The expression representing the string to calculate the length of. * @return A new {@code Expr} representing the length of the string. */ -export function charLength(expr: Expr): CharLength; -export function charLength(value: Expr | string): CharLength { - const valueExpr = value instanceof Expr ? value : Field.of(value); +export function charLength(expr: ScalarExpr): CharLength; +export function charLength(value: ScalarExpr | string): CharLength { + const valueExpr = value instanceof ScalarExpr ? value : Field.of(value); return new CharLength(valueExpr); } @@ -6653,7 +6802,7 @@ export function like(left: string, pattern: string): Like; * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: string, pattern: Expr): Like; +export function like(left: string, pattern: ScalarExpr): Like; /** * @beta @@ -6669,7 +6818,7 @@ export function like(left: string, pattern: Expr): Like; * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: Expr, pattern: string): Like; +export function like(left: ScalarExpr, pattern: string): Like; /** * @beta @@ -6685,11 +6834,14 @@ export function like(left: Expr, pattern: string): Like; * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: Expr, pattern: Expr): Like; -export function like(left: Expr | string, pattern: Expr | string): Like { - const leftExpr = left instanceof Expr ? left : Field.of(left); +export function like(left: ScalarExpr, pattern: ScalarExpr): Like; +export function like( + left: ScalarExpr | string, + pattern: ScalarExpr | string +): Like { + const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); const patternExpr = - pattern instanceof Expr ? pattern : valueToDefaultExpr(pattern); + pattern instanceof ScalarExpr ? pattern : valueToDefaultExpr(pattern); return new Like(leftExpr, patternExpr); } @@ -6725,7 +6877,7 @@ export function regexContains(left: string, pattern: string): RegexContains; * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function regexContains(left: string, pattern: Expr): RegexContains; +export function regexContains(left: string, pattern: ScalarExpr): RegexContains; /** * @beta @@ -6742,7 +6894,7 @@ export function regexContains(left: string, pattern: Expr): RegexContains; * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function regexContains(left: Expr, pattern: string): RegexContains; +export function regexContains(left: ScalarExpr, pattern: string): RegexContains; /** * @beta @@ -6759,14 +6911,17 @@ export function regexContains(left: Expr, pattern: string): RegexContains; * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function regexContains(left: Expr, pattern: Expr): RegexContains; export function regexContains( - left: Expr | string, - pattern: Expr | string + left: ScalarExpr, + pattern: ScalarExpr +): RegexContains; +export function regexContains( + left: ScalarExpr | string, + pattern: ScalarExpr | string ): RegexContains { - const leftExpr = left instanceof Expr ? left : Field.of(left); + const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); const patternExpr = - pattern instanceof Expr ? pattern : valueToDefaultExpr(pattern); + pattern instanceof ScalarExpr ? pattern : valueToDefaultExpr(pattern); return new RegexContains(leftExpr, patternExpr); } @@ -6800,7 +6955,7 @@ export function regexMatch(left: string, pattern: string): RegexMatch; * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: string, pattern: Expr): RegexMatch; +export function regexMatch(left: string, pattern: ScalarExpr): RegexMatch; /** * @beta @@ -6817,7 +6972,7 @@ export function regexMatch(left: string, pattern: Expr): RegexMatch; * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: Expr, pattern: string): RegexMatch; +export function regexMatch(left: ScalarExpr, pattern: string): RegexMatch; /** * @beta @@ -6834,14 +6989,14 @@ export function regexMatch(left: Expr, pattern: string): RegexMatch; * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: Expr, pattern: Expr): RegexMatch; +export function regexMatch(left: ScalarExpr, pattern: ScalarExpr): RegexMatch; export function regexMatch( - left: Expr | string, - pattern: Expr | string + left: ScalarExpr | string, + pattern: ScalarExpr | string ): RegexMatch { - const leftExpr = left instanceof Expr ? left : Field.of(left); + const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); const patternExpr = - pattern instanceof Expr ? pattern : valueToDefaultExpr(pattern); + pattern instanceof ScalarExpr ? pattern : valueToDefaultExpr(pattern); return new RegexMatch(leftExpr, patternExpr); } @@ -6875,7 +7030,7 @@ export function strContains(left: string, substring: string): StrContains; * @param substring The expression representing the substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function strContains(left: string, substring: Expr): StrContains; +export function strContains(left: string, substring: ScalarExpr): StrContains; /** * @beta @@ -6891,7 +7046,7 @@ export function strContains(left: string, substring: Expr): StrContains; * @param substring The substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function strContains(left: Expr, substring: string): StrContains; +export function strContains(left: ScalarExpr, substring: string): StrContains; /** * @beta @@ -6907,14 +7062,17 @@ export function strContains(left: Expr, substring: string): StrContains; * @param substring The expression representing the substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function strContains(left: Expr, substring: Expr): StrContains; export function strContains( - left: Expr | string, - substring: Expr | string + left: ScalarExpr, + substring: ScalarExpr +): StrContains; +export function strContains( + left: ScalarExpr | string, + substring: ScalarExpr | string ): StrContains { - const leftExpr = left instanceof Expr ? left : Field.of(left); + const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); const substringExpr = - substring instanceof Expr ? substring : valueToDefaultExpr(substring); + substring instanceof ScalarExpr ? substring : valueToDefaultExpr(substring); return new StrContains(leftExpr, substringExpr); } @@ -6948,7 +7106,7 @@ export function startsWith(expr: string, prefix: string): StartsWith; * @param prefix The expression representing the prefix. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: string, prefix: Expr): StartsWith; +export function startsWith(expr: string, prefix: ScalarExpr): StartsWith; /** * @beta @@ -6964,7 +7122,7 @@ export function startsWith(expr: string, prefix: Expr): StartsWith; * @param prefix The prefix to check for. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: Expr, prefix: string): StartsWith; +export function startsWith(expr: ScalarExpr, prefix: string): StartsWith; /** * @beta @@ -6980,14 +7138,14 @@ export function startsWith(expr: Expr, prefix: string): StartsWith; * @param prefix The prefix to check for. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: Expr, prefix: Expr): StartsWith; +export function startsWith(expr: ScalarExpr, prefix: ScalarExpr): StartsWith; export function startsWith( - expr: Expr | string, - prefix: Expr | string + expr: ScalarExpr | string, + prefix: ScalarExpr | string ): StartsWith { - const exprLeft = expr instanceof Expr ? expr : Field.of(expr); + const exprLeft = expr instanceof ScalarExpr ? expr : Field.of(expr); const prefixExpr = - prefix instanceof Expr ? prefix : valueToDefaultExpr(prefix); + prefix instanceof ScalarExpr ? prefix : valueToDefaultExpr(prefix); return new StartsWith(exprLeft, prefixExpr); } @@ -7021,7 +7179,7 @@ export function endsWith(expr: string, suffix: string): EndsWith; * @param suffix The expression representing the postfix. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: string, suffix: Expr): EndsWith; +export function endsWith(expr: string, suffix: ScalarExpr): EndsWith; /** * @beta @@ -7037,7 +7195,7 @@ export function endsWith(expr: string, suffix: Expr): EndsWith; * @param suffix The postfix to check for. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: Expr, suffix: string): EndsWith; +export function endsWith(expr: ScalarExpr, suffix: string): EndsWith; /** * @beta @@ -7053,11 +7211,14 @@ export function endsWith(expr: Expr, suffix: string): EndsWith; * @param suffix The postfix to check for. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: Expr, suffix: Expr): EndsWith; -export function endsWith(expr: Expr | string, suffix: Expr | string): EndsWith { - const exprLeft = expr instanceof Expr ? expr : Field.of(expr); +export function endsWith(expr: ScalarExpr, suffix: ScalarExpr): EndsWith; +export function endsWith( + expr: ScalarExpr | string, + suffix: ScalarExpr | string +): EndsWith { + const exprLeft = expr instanceof ScalarExpr ? expr : Field.of(expr); const suffixExpr = - suffix instanceof Expr ? suffix : valueToDefaultExpr(suffix); + suffix instanceof ScalarExpr ? suffix : valueToDefaultExpr(suffix); return new EndsWith(exprLeft, suffixExpr); } @@ -7089,9 +7250,9 @@ export function toLower(expr: string): ToLower; * @param expr The expression representing the string to convert to lowercase. * @return A new {@code Expr} representing the lowercase string. */ -export function toLower(expr: Expr): ToLower; -export function toLower(expr: Expr | string): ToLower { - return new ToLower(expr instanceof Expr ? expr : Field.of(expr)); +export function toLower(expr: ScalarExpr): ToLower; +export function toLower(expr: ScalarExpr | string): ToLower { + return new ToLower(expr instanceof ScalarExpr ? expr : Field.of(expr)); } /** @@ -7122,9 +7283,9 @@ export function toUpper(expr: string): ToUpper; * @param expr The expression representing the string to convert to uppercase. * @return A new {@code Expr} representing the uppercase string. */ -export function toUpper(expr: Expr): ToUpper; -export function toUpper(expr: Expr | string): ToUpper { - return new ToUpper(expr instanceof Expr ? expr : Field.of(expr)); +export function toUpper(expr: ScalarExpr): ToUpper; +export function toUpper(expr: ScalarExpr | string): ToUpper { + return new ToUpper(expr instanceof ScalarExpr ? expr : Field.of(expr)); } /** @@ -7155,9 +7316,9 @@ export function trim(expr: string): Trim; * @param expr The expression representing the string to trim. * @return A new {@code Expr} representing the trimmed string. */ -export function trim(expr: Expr): Trim; -export function trim(expr: Expr | string): Trim { - return new Trim(expr instanceof Expr ? expr : Field.of(expr)); +export function trim(expr: ScalarExpr): Trim; +export function trim(expr: ScalarExpr | string): Trim { + return new Trim(expr instanceof ScalarExpr ? expr : Field.of(expr)); } /** @@ -7177,8 +7338,8 @@ export function trim(expr: Expr | string): Trim { */ export function strConcat( fieldName: string, - secondString: Expr | string, - ...otherStrings: Array + secondString: ScalarExpr | string, + ...otherStrings: Array ): StrConcat; /** @@ -7196,16 +7357,16 @@ export function strConcat( * @return A new {@code Expr} representing the concatenated string. */ export function strConcat( - firstString: Expr, - secondString: Expr | string, - ...otherStrings: Array + firstString: ScalarExpr, + secondString: ScalarExpr | string, + ...otherStrings: Array ): StrConcat; export function strConcat( - first: string | Expr, - ...elements: Array + first: string | ScalarExpr, + ...elements: Array ): StrConcat { const exprs = elements.map(e => - e instanceof Expr ? e : valueToDefaultExpr(e) + e instanceof ScalarExpr ? e : valueToDefaultExpr(e) ); return new StrConcat(valueToDefaultExpr(first), exprs); } @@ -7240,8 +7401,11 @@ export function mapGet(mapField: string, subField: string): MapGet; * @param subField The key to access in the map. * @return A new {@code Expr} representing the value associated with the given key in the map. */ -export function mapGet(mapExpr: Expr, subField: string): MapGet; -export function mapGet(fieldOrExpr: string | Expr, subField: string): MapGet { +export function mapGet(mapExpr: ScalarExpr, subField: string): MapGet; +export function mapGet( + fieldOrExpr: string | ScalarExpr, + subField: string +): MapGet { return new MapGet( typeof fieldOrExpr === 'string' ? Field.of(fieldOrExpr) : fieldOrExpr, subField @@ -7278,7 +7442,7 @@ export function countAll(): Count { * @param value The expression to count. * @return A new {@code AggregateFunction} representing the 'count' aggregation. */ -export function countFunction(value: Expr): Count; +export function countFunction(value: ScalarExpr): Count; /** * Creates an aggregation that counts the number of stage inputs with valid evaluations of the @@ -7293,8 +7457,8 @@ export function countFunction(value: Expr): Count; * @return A new {@code AggregateFunction} representing the 'count' aggregation. */ export function countFunction(value: string): Count; -export function countFunction(value: Expr | string): Count { - const exprValue = value instanceof Expr ? value : Field.of(value); +export function countFunction(value: ScalarExpr | string): Count { + const exprValue = value instanceof ScalarExpr ? value : Field.of(value); return new Count(exprValue, false); } @@ -7312,7 +7476,7 @@ export function countFunction(value: Expr | string): Count { * @param value The expression to sum up. * @return A new {@code AggregateFunction} representing the 'sum' aggregation. */ -export function sumFunction(value: Expr): Sum; +export function sumFunction(value: ScalarExpr): Sum; /** * @beta @@ -7329,8 +7493,8 @@ export function sumFunction(value: Expr): Sum; * @return A new {@code AggregateFunction} representing the 'sum' aggregation. */ export function sumFunction(value: string): Sum; -export function sumFunction(value: Expr | string): Sum { - const exprValue = value instanceof Expr ? value : Field.of(value); +export function sumFunction(value: ScalarExpr | string): Sum { + const exprValue = value instanceof ScalarExpr ? value : Field.of(value); return new Sum(exprValue, false); } @@ -7348,7 +7512,7 @@ export function sumFunction(value: Expr | string): Sum { * @param value The expression representing the values to average. * @return A new {@code AggregateFunction} representing the 'avg' aggregation. */ -export function avgFunction(value: Expr): Avg; +export function avgFunction(value: ScalarExpr): Avg; /** * @beta @@ -7365,8 +7529,8 @@ export function avgFunction(value: Expr): Avg; * @return A new {@code AggregateFunction} representing the 'avg' aggregation. */ export function avgFunction(value: string): Avg; -export function avgFunction(value: Expr | string): Avg { - const exprValue = value instanceof Expr ? value : Field.of(value); +export function avgFunction(value: ScalarExpr | string): Avg { + const exprValue = value instanceof ScalarExpr ? value : Field.of(value); return new Avg(exprValue, false); } @@ -7384,7 +7548,7 @@ export function avgFunction(value: Expr | string): Avg { * @param value The expression to find the minimum value of. * @return A new {@code AggregateFunction} representing the 'min' aggregation. */ -export function minimum(value: Expr): Minimum; +export function minimum(value: ScalarExpr): Minimum; /** * @beta @@ -7400,8 +7564,8 @@ export function minimum(value: Expr): Minimum; * @return A new {@code AggregateFunction} representing the 'min' aggregation. */ export function minimum(value: string): Minimum; -export function minimum(value: Expr | string): Minimum { - const exprValue = value instanceof Expr ? value : Field.of(value); +export function minimum(value: ScalarExpr | string): Minimum { + const exprValue = value instanceof ScalarExpr ? value : Field.of(value); return new Minimum(exprValue, false); } @@ -7419,7 +7583,7 @@ export function minimum(value: Expr | string): Minimum { * @param value The expression to find the maximum value of. * @return A new {@code AggregateFunction} representing the 'max' aggregation. */ -export function maximum(value: Expr): Maximum; +export function maximum(value: ScalarExpr): Maximum; /** * @beta @@ -7435,8 +7599,8 @@ export function maximum(value: Expr): Maximum; * @return A new {@code AggregateFunction} representing the 'max' aggregation. */ export function maximum(value: string): Maximum; -export function maximum(value: Expr | string): Maximum { - const exprValue = value instanceof Expr ? value : Field.of(value); +export function maximum(value: ScalarExpr | string): Maximum { + const exprValue = value instanceof ScalarExpr ? value : Field.of(value); return new Maximum(exprValue, false); } @@ -7489,7 +7653,7 @@ export function cosineDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance(expr: string, other: Expr): CosineDistance; +export function cosineDistance(expr: string, other: ScalarExpr): CosineDistance; /** * @beta @@ -7505,7 +7669,10 @@ export function cosineDistance(expr: string, other: Expr): CosineDistance; * @param other The other vector (as an array of doubles) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance(expr: Expr, other: number[]): CosineDistance; +export function cosineDistance( + expr: ScalarExpr, + other: number[] +): CosineDistance; /** * @beta @@ -7521,7 +7688,10 @@ export function cosineDistance(expr: Expr, other: number[]): CosineDistance; * @param other The other vector (as a VectorValue) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance(expr: Expr, other: VectorValue): CosineDistance; +export function cosineDistance( + expr: ScalarExpr, + other: VectorValue +): CosineDistance; /** * @beta @@ -7537,13 +7707,16 @@ export function cosineDistance(expr: Expr, other: VectorValue): CosineDistance; * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance(expr: Expr, other: Expr): CosineDistance; export function cosineDistance( - expr: Expr | string, - other: Expr | number[] | VectorValue + expr: ScalarExpr, + other: ScalarExpr +): CosineDistance; +export function cosineDistance( + expr: ScalarExpr | string, + other: ScalarExpr | number[] | VectorValue ): CosineDistance { - const expr1 = expr instanceof Expr ? expr : Field.of(expr); - const expr2 = other instanceof Expr ? other : Constant.vector(other); + const expr1 = expr instanceof ScalarExpr ? expr : Field.of(expr); + const expr2 = other instanceof ScalarExpr ? other : Constant.vector(other); return new CosineDistance(expr1, expr2); } @@ -7593,7 +7766,7 @@ export function dotProduct(expr: string, other: VectorValue): DotProduct; * @param other The other vector (represented as an Expr) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: string, other: Expr): DotProduct; +export function dotProduct(expr: string, other: ScalarExpr): DotProduct; /** * @beta @@ -7609,7 +7782,7 @@ export function dotProduct(expr: string, other: Expr): DotProduct; * @param other The other vector (as an array of doubles) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: Expr, other: number[]): DotProduct; +export function dotProduct(expr: ScalarExpr, other: number[]): DotProduct; /** * @beta @@ -7625,7 +7798,7 @@ export function dotProduct(expr: Expr, other: number[]): DotProduct; * @param other The other vector (as a VectorValue) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: Expr, other: VectorValue): DotProduct; +export function dotProduct(expr: ScalarExpr, other: VectorValue): DotProduct; /** * @beta @@ -7641,13 +7814,13 @@ export function dotProduct(expr: Expr, other: VectorValue): DotProduct; * @param other The other vector (represented as an Expr) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: Expr, other: Expr): DotProduct; +export function dotProduct(expr: ScalarExpr, other: ScalarExpr): DotProduct; export function dotProduct( - expr: Expr | string, - other: Expr | number[] | VectorValue + expr: ScalarExpr | string, + other: ScalarExpr | number[] | VectorValue ): DotProduct { - const expr1 = expr instanceof Expr ? expr : Field.of(expr); - const expr2 = other instanceof Expr ? other : Constant.vector(other); + const expr1 = expr instanceof ScalarExpr ? expr : Field.of(expr); + const expr2 = other instanceof ScalarExpr ? other : Constant.vector(other); return new DotProduct(expr1, expr2); } @@ -7703,7 +7876,10 @@ export function euclideanDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ -export function euclideanDistance(expr: string, other: Expr): EuclideanDistance; +export function euclideanDistance( + expr: string, + other: ScalarExpr +): EuclideanDistance; /** * @beta @@ -7721,7 +7897,7 @@ export function euclideanDistance(expr: string, other: Expr): EuclideanDistance; * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ export function euclideanDistance( - expr: Expr, + expr: ScalarExpr, other: number[] ): EuclideanDistance; @@ -7740,7 +7916,7 @@ export function euclideanDistance( * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ export function euclideanDistance( - expr: Expr, + expr: ScalarExpr, other: VectorValue ): EuclideanDistance; @@ -7758,13 +7934,16 @@ export function euclideanDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ -export function euclideanDistance(expr: Expr, other: Expr): EuclideanDistance; export function euclideanDistance( - expr: Expr | string, - other: Expr | number[] | VectorValue + expr: ScalarExpr, + other: ScalarExpr +): EuclideanDistance; +export function euclideanDistance( + expr: ScalarExpr | string, + other: ScalarExpr | number[] | VectorValue ): EuclideanDistance { - const expr1 = expr instanceof Expr ? expr : Field.of(expr); - const expr2 = other instanceof Expr ? other : Constant.vector(other); + const expr1 = expr instanceof ScalarExpr ? expr : Field.of(expr); + const expr2 = other instanceof ScalarExpr ? other : Constant.vector(other); return new EuclideanDistance(expr1, expr2); } @@ -7781,7 +7960,7 @@ export function euclideanDistance( * @param expr The expression representing the Firestore Vector. * @return A new {@code Expr} representing the length of the array. */ -export function vectorLength(expr: Expr): VectorLength; +export function vectorLength(expr: ScalarExpr): VectorLength; /** * @beta @@ -7797,7 +7976,7 @@ export function vectorLength(expr: Expr): VectorLength; * @return A new {@code Expr} representing the length of the array. */ export function vectorLength(field: string): VectorLength; -export function vectorLength(expr: Expr | string): VectorLength { +export function vectorLength(expr: ScalarExpr | string): VectorLength { const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; return new VectorLength(normalizedExpr); } @@ -7816,7 +7995,7 @@ export function vectorLength(expr: Expr | string): VectorLength { * @param expr The expression representing the number of microseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMicrosToTimestamp(expr: Expr): UnixMicrosToTimestamp; +export function unixMicrosToTimestamp(expr: ScalarExpr): UnixMicrosToTimestamp; /** * @beta @@ -7834,7 +8013,7 @@ export function unixMicrosToTimestamp(expr: Expr): UnixMicrosToTimestamp; */ export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; export function unixMicrosToTimestamp( - expr: Expr | string + expr: ScalarExpr | string ): UnixMicrosToTimestamp { const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; return new UnixMicrosToTimestamp(normalizedExpr); @@ -7853,7 +8032,7 @@ export function unixMicrosToTimestamp( * @param expr The expression representing the timestamp. * @return A new {@code Expr} representing the number of microseconds since epoch. */ -export function timestampToUnixMicros(expr: Expr): TimestampToUnixMicros; +export function timestampToUnixMicros(expr: ScalarExpr): TimestampToUnixMicros; /** * @beta @@ -7870,7 +8049,7 @@ export function timestampToUnixMicros(expr: Expr): TimestampToUnixMicros; */ export function timestampToUnixMicros(field: string): TimestampToUnixMicros; export function timestampToUnixMicros( - expr: Expr | string + expr: ScalarExpr | string ): TimestampToUnixMicros { const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; return new TimestampToUnixMicros(normalizedExpr); @@ -7890,7 +8069,7 @@ export function timestampToUnixMicros( * @param expr The expression representing the number of milliseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMillisToTimestamp(expr: Expr): UnixMillisToTimestamp; +export function unixMillisToTimestamp(expr: ScalarExpr): UnixMillisToTimestamp; /** * @beta @@ -7908,7 +8087,7 @@ export function unixMillisToTimestamp(expr: Expr): UnixMillisToTimestamp; */ export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; export function unixMillisToTimestamp( - expr: Expr | string + expr: ScalarExpr | string ): UnixMillisToTimestamp { const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; return new UnixMillisToTimestamp(normalizedExpr); @@ -7927,7 +8106,7 @@ export function unixMillisToTimestamp( * @param expr The expression representing the timestamp. * @return A new {@code Expr} representing the number of milliseconds since epoch. */ -export function timestampToUnixMillis(expr: Expr): TimestampToUnixMillis; +export function timestampToUnixMillis(expr: ScalarExpr): TimestampToUnixMillis; /** * @beta @@ -7944,7 +8123,7 @@ export function timestampToUnixMillis(expr: Expr): TimestampToUnixMillis; */ export function timestampToUnixMillis(field: string): TimestampToUnixMillis; export function timestampToUnixMillis( - expr: Expr | string + expr: ScalarExpr | string ): TimestampToUnixMillis { const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; return new TimestampToUnixMillis(normalizedExpr); @@ -7964,7 +8143,9 @@ export function timestampToUnixMillis( * @param expr The expression representing the number of seconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixSecondsToTimestamp(expr: Expr): UnixSecondsToTimestamp; +export function unixSecondsToTimestamp( + expr: ScalarExpr +): UnixSecondsToTimestamp; /** * @beta @@ -7982,7 +8163,7 @@ export function unixSecondsToTimestamp(expr: Expr): UnixSecondsToTimestamp; */ export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; export function unixSecondsToTimestamp( - expr: Expr | string + expr: ScalarExpr | string ): UnixSecondsToTimestamp { const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; return new UnixSecondsToTimestamp(normalizedExpr); @@ -8001,7 +8182,9 @@ export function unixSecondsToTimestamp( * @param expr The expression representing the timestamp. * @return A new {@code Expr} representing the number of seconds since epoch. */ -export function timestampToUnixSeconds(expr: Expr): TimestampToUnixSeconds; +export function timestampToUnixSeconds( + expr: ScalarExpr +): TimestampToUnixSeconds; /** * @beta @@ -8018,7 +8201,7 @@ export function timestampToUnixSeconds(expr: Expr): TimestampToUnixSeconds; */ export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; export function timestampToUnixSeconds( - expr: Expr | string + expr: ScalarExpr | string ): TimestampToUnixSeconds { const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; return new TimestampToUnixSeconds(normalizedExpr); @@ -8040,9 +8223,9 @@ export function timestampToUnixSeconds( * @return A new {@code Expr} representing the resulting timestamp. */ export function timestampAdd( - timestamp: Expr, - unit: Expr, - amount: Expr + timestamp: ScalarExpr, + unit: ScalarExpr, + amount: ScalarExpr ): TimestampAdd; /** @@ -8061,7 +8244,7 @@ export function timestampAdd( * @return A new {@code Expr} representing the resulting timestamp. */ export function timestampAdd( - timestamp: Expr, + timestamp: ScalarExpr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number ): TimestampAdd; @@ -8087,20 +8270,21 @@ export function timestampAdd( amount: number ): TimestampAdd; export function timestampAdd( - timestamp: Expr | string, + timestamp: ScalarExpr | string, unit: - | Expr + | ScalarExpr | 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', - amount: Expr | number + amount: ScalarExpr | number ): TimestampAdd { const normalizedTimestamp = typeof timestamp === 'string' ? Field.of(timestamp) : timestamp; - const normalizedUnit = unit instanceof Expr ? unit : valueToDefaultExpr(unit); + const normalizedUnit = + unit instanceof ScalarExpr ? unit : valueToDefaultExpr(unit); const normalizedAmount = typeof amount === 'number' ? Constant.of(amount) : amount; return new TimestampAdd( @@ -8126,9 +8310,9 @@ export function timestampAdd( * @return A new {@code Expr} representing the resulting timestamp. */ export function timestampSub( - timestamp: Expr, - unit: Expr, - amount: Expr + timestamp: ScalarExpr, + unit: ScalarExpr, + amount: ScalarExpr ): TimestampSub; /** @@ -8147,7 +8331,7 @@ export function timestampSub( * @return A new {@code Expr} representing the resulting timestamp. */ export function timestampSub( - timestamp: Expr, + timestamp: ScalarExpr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number ): TimestampSub; @@ -8173,20 +8357,21 @@ export function timestampSub( amount: number ): TimestampSub; export function timestampSub( - timestamp: Expr | string, + timestamp: ScalarExpr | string, unit: - | Expr + | ScalarExpr | 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', - amount: Expr | number + amount: ScalarExpr | number ): TimestampSub { const normalizedTimestamp = typeof timestamp === 'string' ? Field.of(timestamp) : timestamp; - const normalizedUnit = unit instanceof Expr ? unit : valueToDefaultExpr(unit); + const normalizedUnit = + unit instanceof ScalarExpr ? unit : valueToDefaultExpr(unit); const normalizedAmount = typeof amount === 'number' ? Constant.of(amount) : amount; return new TimestampSub( @@ -8321,7 +8506,7 @@ export function orFunction( * @param expr The expression to create an ascending ordering for. * @return A new `Ordering` for ascending sorting. */ -export function ascending(expr: Expr): Ordering { +export function ascending(expr: ScalarExpr): Ordering { return new Ordering(expr, 'ascending'); } @@ -8339,9 +8524,9 @@ export function ascending(expr: Expr): Ordering { * @param expr The expression to create a descending ordering for. * @return A new `Ordering` for descending sorting. */ -export function descending(expr: Expr): Ordering; +export function descending(expr: ScalarExpr): Ordering; export function descending(fieldName: string): Ordering; -export function descending(field: Expr | string): Ordering { +export function descending(field: ScalarExpr | string): Ordering { return new Ordering(fieldOfOrExpr(field), 'descending'); } @@ -8354,7 +8539,7 @@ export function descending(field: Expr | string): Ordering { */ export class Ordering { constructor( - readonly expr: Expr, + readonly expr: ScalarExpr, readonly direction: 'ascending' | 'descending' ) {} diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index d642df22739..5b6c6d578fe 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -20,8 +20,7 @@ import { ObjectValue } from '../model/object_value'; import { Pipeline as ProtoPipeline, - Stage as ProtoStage, - Value as ProtoValue + Stage as ProtoStage } from '../protos/firestore_proto_api'; import { invokeExecutePipeline } from '../remote/datastore'; import { JsonProtoSerializer, ProtoSerializable } from '../remote/serializer'; @@ -34,12 +33,13 @@ import { AggregateFunction, AggregateFunctionWithAlias, Constant, - Expr, + ScalarExpr, ExprWithAlias, Field, BooleanExpr, Ordering, - Selectable + Selectable, + Expr } from './expressions'; import { PipelineResult } from './pipeline-result'; import { DocumentReference } from './reference'; @@ -158,7 +158,7 @@ export class Pipeline implements ProtoSerializable { * * - {@link Field}: References an existing document field. * - {@link Function}: Performs a calculation using functions like `add`, `multiply` with - * assigned aliases using {@link Expr#as}. + * assigned aliases using {@link ScalarExpr#as}. * * Example: * @@ -215,7 +215,7 @@ export class Pipeline implements ProtoSerializable { *
  • {@code string}: Name of an existing field
  • *
  • {@link Field}: References an existing field.
  • *
  • {@link Function}: Represents the result of a function with an assigned alias name using - * {@link Expr#as}
  • + * {@link ScalarExpr#as} * * *

    If no selections are provided, the output of this stage is empty. Use {@link @@ -238,7 +238,8 @@ export class Pipeline implements ProtoSerializable { * @return A new Pipeline object with this stage appended to the stage list. */ select(...selections: Array): Pipeline { - let projections: Map = this.selectablesToMap(selections); + let projections: Map = + this.selectablesToMap(selections); projections = this.readUserData('select', projections); return this._addStage(new Select(projections)); } @@ -347,10 +348,10 @@ export class Pipeline implements ProtoSerializable { } /** - * Returns a set of distinct {@link Expr} values from the inputs to this stage. + * Returns a set of distinct {@link ScalarExpr} values from the inputs to this stage. * *

    This stage run through the results from previous stages to include only results with unique - * combinations of {@link Expr} values ({@link Field}, {@link Function}, etc). + * combinations of {@link ScalarExpr} values ({@link Field}, {@link Function}, etc). * *

    The parameters to this stage are defined using {@link Selectable} expressions or {@code string}s: * @@ -358,7 +359,7 @@ export class Pipeline implements ProtoSerializable { *

  • {@code string}: Name of an existing field
  • *
  • {@link Field}: References an existing document field.
  • *
  • {@link Function}: Represents the result of a function with an assigned alias name using - * {@link Expr#as}
  • + * {@link ScalarExpr#as} * * *

    Example: @@ -387,7 +388,7 @@ export class Pipeline implements ProtoSerializable { * *

    This stage allows you to calculate aggregate values over a set of documents. You define the * aggregations to perform using {@link AggregateFunctionWithAlias} expressions which are typically results of - * calling {@link Expr#as} on {@link AggregateFunction} instances. + * calling {@link ScalarExpr#as} on {@link AggregateFunction} instances. * *

    Example: * @@ -418,7 +419,7 @@ export class Pipeline implements ProtoSerializable { * specifying groups is the same as putting the entire inputs into one group. *

  • **Accumulators:** One or more accumulation operations to perform within each group. These * are defined using {@link AggregateFunctionWithAlias} expressions, which are typically created by - * calling {@link Expr#as} on {@link AggregateFunction} instances. Each aggregation + * calling {@link ScalarExpr#as} on {@link AggregateFunction} instances. Each aggregation * calculates a value (e.g., sum, average, count) based on the documents within its group.
  • * * @@ -483,7 +484,7 @@ export class Pipeline implements ProtoSerializable { ) ]) ), - new Map() + new Map() ) ); } @@ -743,7 +744,7 @@ export class Pipeline implements ProtoSerializable { // this is unlike the default conversion for objects and arrays // passed to an expression. const expressionParams = params.map((value: any) => { - if (value instanceof Expr || value instanceof AggregateFunction) { + if (value instanceof Expr) { return value; } else if (isPlainObject(value)) { return _mapValue(value); @@ -840,15 +841,15 @@ export class Pipeline implements ProtoSerializable { private selectablesToMap( selectables: Array - ): Map { - const result = new Map(); + ): Map { + const result = new Map(); for (const selectable of selectables) { if (typeof selectable === 'string') { result.set(selectable as string, Field.of(selectable)); } else if (selectable instanceof Field) { result.set((selectable as Field).fieldName(), selectable); } else if (selectable instanceof ExprWithAlias) { - const expr = selectable as ExprWithAlias; + const expr = selectable as ExprWithAlias; result.set(expr.alias, expr.expr); } } diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index de18556b730..112753ffd74 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -32,10 +32,10 @@ import { hardAssert } from '../util/assert'; import { AggregateFunction, - Expr, + ScalarExpr, Field, BooleanExpr, - Ordering + Ordering, Expr } from './expressions'; import { Pipeline } from './pipeline'; import { DocumentReference } from './reference'; @@ -54,7 +54,7 @@ export interface Stage extends ProtoSerializable { export class AddFields implements Stage { name = 'add_fields'; - constructor(private fields: Map) {} + constructor(private fields: Map) {} /** * @internal @@ -96,7 +96,7 @@ export class Aggregate implements Stage { constructor( private accumulators: Map, - private groups: Map + private groups: Map ) {} /** @@ -120,7 +120,7 @@ export class Aggregate implements Stage { export class Distinct implements Stage { name = 'distinct'; - constructor(private groups: Map) {} + constructor(private groups: Map) {} /** * @internal @@ -244,7 +244,7 @@ export class Where implements Stage { _toProto(serializer: JsonProtoSerializer): ProtoStage { return { name: this.name, - args: [(this.condition as unknown as Expr)._toProto(serializer)] + args: [(this.condition as unknown as ScalarExpr)._toProto(serializer)] }; } } @@ -368,7 +368,7 @@ export class Offset implements Stage { export class Select implements Stage { name = 'select'; - constructor(private projections: Map) {} + constructor(private projections: Map) {} /** * @internal @@ -440,7 +440,7 @@ export class Union implements Stage { export class Unnest implements Stage { name = 'unnest'; constructor( - private expr: Expr, + private expr: ScalarExpr, private alias: Field, private indexField?: string ) {} @@ -493,7 +493,7 @@ export class GenericStage implements Stage { */ constructor( public name: string, - private params: Array> + private params: Array ) {} /** diff --git a/packages/firestore/src/lite-api/user_data_reader.ts b/packages/firestore/src/lite-api/user_data_reader.ts index d6f4093f882..7d24482c95e 100644 --- a/packages/firestore/src/lite-api/user_data_reader.ts +++ b/packages/firestore/src/lite-api/user_data_reader.ts @@ -65,7 +65,7 @@ import { Dict, forEach, isEmpty } from '../util/obj'; import { Bytes } from './bytes'; import { Firestore } from './database'; -import { Expr, AggregateFunction } from './expressions'; +import { Expr } from './expressions'; import { FieldPath } from './field_path'; import { FieldValue } from './field_value'; import { GeoPoint } from './geo_point'; @@ -910,7 +910,7 @@ export function parseScalarValue( }; } else if (value instanceof VectorValue) { return parseVectorValue(value, context); - } else if (value instanceof Expr || value instanceof AggregateFunction) { + } else if (value instanceof Expr) { return value._toProto(context.serializer); } else { throw context.createError( @@ -970,8 +970,7 @@ export function looksLikeJsonObject(input: unknown): boolean { !(input instanceof DocumentReference) && !(input instanceof FieldValue) && !(input instanceof VectorValue) && - !(input instanceof Expr) && - !(input instanceof AggregateFunction) + !(input instanceof Expr) ); } From db9ee0afd3d70aae413b78115b078a0368202921 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:01:12 -0700 Subject: [PATCH 33/75] fixing missing imports and renames --- packages/firestore/lite/pipelines/pipelines.ts | 4 ++-- packages/firestore/src/api_pipelines.ts | 10 ++++++---- .../test/integration/api/pipeline.test.ts | 14 ++++++++------ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index 4a27618da48..1109b41755d 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -202,8 +202,8 @@ export { TimestampSub, Ordering, ExprType, - AccumulatorTarget, + AggregateFunctionWithAlias, Selectable, BooleanExpr, - Accumulator + AggregateFunction } from '../../src/lite-api/expressions'; diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index 589694dd106..aab25707d0c 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -105,6 +105,8 @@ export { timestampAdd, timestampSub, genericFunction, + genericBooleanExpr, + genericAggregateFunction, ascending, descending, countIf, @@ -127,7 +129,7 @@ export { map, mapRemove, mapMerge, - parent, + parentFunction, collectionId, documentIdFunction, key, @@ -159,7 +161,7 @@ export { Key, Substr, ManhattanDistance, - Expr, + ScalarExpr, ExprWithAlias, Field, Constant, @@ -231,8 +233,8 @@ export { export type { ExprType, - AccumulatorTarget, + AggregateFunctionWithAlias, Selectable, BooleanExpr, - Accumulator + AggregateFunction } from './lite-api/expressions'; diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 7abb7f0c7cf..17d4aa08865 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -26,6 +26,8 @@ import { array, descending, genericFunction, + genericAggregateFunction, + genericBooleanExpr, isNan, map, Bytes, @@ -1628,7 +1630,7 @@ apiDescribe.only('Pipelines', persistence => { const results = await randomCol .pipeline() .where( - genericFunction('and', [ + genericBooleanExpr('and', [ Field.of('rating').gt(0), Field.of('title').charLength().lt(5), Field.of('tags').arrayContains('propaganda') @@ -1645,7 +1647,7 @@ apiDescribe.only('Pipelines', persistence => { const results = await randomCol .pipeline() .where( - genericFunction('array_contains_any', [ + genericBooleanExpr('array_contains_any', [ Field.of('tags'), ['politics'] ]) @@ -1661,9 +1663,9 @@ apiDescribe.only('Pipelines', persistence => { const results = await randomCol .pipeline() .aggregate( - genericFunction('count_if', [Field.of('rating').gte(4.5)]).as( - 'countOfBest' - ) + genericAggregateFunction('count_if', [ + Field.of('rating').gte(4.5) + ]).as('countOfBest') ) .execute(); expectResults(results, { @@ -1880,7 +1882,7 @@ apiDescribe.only('Pipelines', persistence => { }); }); - it.only('supports Substr without length', async () => { + it('supports Substr without length', async () => { let results = await randomCol .pipeline() .sort(Field.of('rating').descending()) From ef1e42e53d56def7d97c1ee19a7eaa776a77149b Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Tue, 25 Feb 2025 15:19:23 -0700 Subject: [PATCH 34/75] Remove classes for individual function types --- packages/firestore/src/core/pipeline-util.ts | 22 +- .../firestore/src/lite-api/expressions.ts | 3563 ++++++----------- packages/firestore/src/lite-api/stage.ts | 8 +- .../test/integration/api/pipeline.test.ts | 2 +- 4 files changed, 1156 insertions(+), 2439 deletions(-) diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index 727f05f6836..06b14a6306e 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -24,13 +24,11 @@ import { andFunction, orFunction, Ordering, - And, lt, gt, lte, gte, - eq, - Or + eq } from '../lite-api/expressions'; import { Pipeline } from '../lite-api/pipeline'; import { doc } from '../lite-api/reference'; @@ -61,9 +59,9 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { const field = Field.of(f.field.toString()); if (isNanValue(f.value)) { if (f.op === Operator.EQUAL) { - return andFunction(field.exists(), field.isNaN()); + return andFunction(field.exists(), field.isNan()); } else { - return andFunction(field.exists(), not(field.isNaN())); + return andFunction(field.exists(), not(field.isNan())); } } else if (isNullValue(f.value)) { if (f.op === Operator.EQUAL) { @@ -249,11 +247,11 @@ function whereConditionsFromCursor( const filterFunc = position === 'before' ? lt : gt; const filterInclusiveFunc = position === 'before' ? lte : gte; - const orConditions = []; + const orConditions: BooleanExpr[] = []; for (let i = 1; i <= orderings.length; i++) { const cursorSubset = cursors.slice(0, i); - const conditions = cursorSubset.map((cursor, index) => { + const conditions: BooleanExpr[] = cursorSubset.map((cursor, index) => { if (index < cursorSubset.length - 1) { return eq(orderings[index].expr as Field, cursor); } else if (!!bound.inclusive && i === orderings.length) { @@ -266,13 +264,19 @@ function whereConditionsFromCursor( if (conditions.length === 1) { orConditions.push(conditions[0]); } else { - orConditions.push(new And(conditions)); + orConditions.push( + andFunction(conditions[0], conditions[1], ...conditions.slice(2)) + ); } } if (orConditions.length === 1) { return orConditions[0]; } else { - return new Or(orConditions); + return orFunction( + orConditions[0], + orConditions[1], + ...orConditions.slice(2) + ); } } diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index f1e31a3ed4d..a8be6ad60ed 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -79,6 +79,21 @@ function valueToDefaultExpr(value: any): ScalarExpr { return Constant.of(value); } } +/** + * Converts a value to an Expr, Returning either a Constant, MapFunction, + * ArrayFunction, or the input itself (if it's already an expression). + * + * @private + * @internal + * @param value + */ +function vectorToExpr(value: VectorValue | number[] | ScalarExpr): ScalarExpr { + if (value instanceof ScalarExpr) { + return value; + } else { + return Constant.vector(value); + } +} /** * Converts a value to an Expr, Returning either a Constant, MapFunction, @@ -161,12 +176,15 @@ export abstract class ScalarExpr extends Expr { * @param others Optional additional expressions or literals to add to this expression. * @return A new `Expr` representing the addition operation. */ - add(second: ScalarExpr | any, ...others: Array): Add { + add( + second: ScalarExpr | any, + ...others: Array + ): FirestoreFunction { const values = [second, ...others]; - return new Add( + return new FirestoreFunction('add', [ this, - values.map(value => valueToDefaultExpr(value)) - ); + ...values.map(value => valueToDefaultExpr(value)) + ]); } /** @@ -180,7 +198,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to subtract from this expression. * @return A new `Expr` representing the subtraction operation. */ - subtract(other: ScalarExpr): Subtract; + subtract(other: ScalarExpr): FirestoreFunction; /** * Creates an expression that subtracts a constant value from this expression. @@ -193,9 +211,9 @@ export abstract class ScalarExpr extends Expr { * @param other The constant value to subtract. * @return A new `Expr` representing the subtraction operation. */ - subtract(other: any): Subtract; - subtract(other: any): Subtract { - return new Subtract(this, valueToDefaultExpr(other)); + subtract(other: any): FirestoreFunction; + subtract(other: any): FirestoreFunction { + return new FirestoreFunction('subtract', [this, valueToDefaultExpr(other)]); } /** @@ -213,12 +231,12 @@ export abstract class ScalarExpr extends Expr { multiply( second: ScalarExpr | any, ...others: Array - ): Multiply { - const values = [second, ...others]; - return new Multiply( + ): FirestoreFunction { + return new FirestoreFunction('multiply', [ this, - values.map(value => valueToDefaultExpr(value)) - ); + valueToDefaultExpr(second), + ...others.map(value => valueToDefaultExpr(value)) + ]); } /** @@ -232,7 +250,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to divide by. * @return A new `Expr` representing the division operation. */ - divide(other: ScalarExpr): Divide; + divide(other: ScalarExpr): FirestoreFunction; /** * Creates an expression that divides this expression by a constant value. @@ -245,9 +263,9 @@ export abstract class ScalarExpr extends Expr { * @param other The constant value to divide by. * @return A new `Expr` representing the division operation. */ - divide(other: any): Divide; - divide(other: any): Divide { - return new Divide(this, valueToDefaultExpr(other)); + divide(other: any): FirestoreFunction; + divide(other: any): FirestoreFunction { + return new FirestoreFunction('divide', [this, valueToDefaultExpr(other)]); } /** @@ -261,7 +279,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to divide by. * @return A new `Expr` representing the modulo operation. */ - mod(other: ScalarExpr): Mod; + mod(other: ScalarExpr): FirestoreFunction; /** * Creates an expression that calculates the modulo (remainder) of dividing this expression by a constant value. @@ -274,9 +292,9 @@ export abstract class ScalarExpr extends Expr { * @param other The constant value to divide by. * @return A new `Expr` representing the modulo operation. */ - mod(other: any): Mod; - mod(other: any): Mod { - return new Mod(this, valueToDefaultExpr(other)); + mod(other: any): FirestoreFunction; + mod(other: any): FirestoreFunction { + return new FirestoreFunction('mod', [this, valueToDefaultExpr(other)]); } /** @@ -290,7 +308,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to compare for equality. * @return A new `Expr` representing the equality comparison. */ - eq(other: ScalarExpr): Eq; + eq(other: ScalarExpr): BooleanExpr; /** * Creates an expression that checks if this expression is equal to a constant value. @@ -303,9 +321,9 @@ export abstract class ScalarExpr extends Expr { * @param other The constant value to compare for equality. * @return A new `Expr` representing the equality comparison. */ - eq(other: any): Eq; - eq(other: any): Eq { - return new Eq(this, valueToDefaultExpr(other)); + eq(other: any): BooleanExpr; + eq(other: any): BooleanExpr { + return new BooleanExpr('eq', [this, valueToDefaultExpr(other)]); } /** @@ -319,7 +337,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to compare for inequality. * @return A new `Expr` representing the inequality comparison. */ - neq(other: ScalarExpr): Neq; + neq(other: ScalarExpr): BooleanExpr; /** * Creates an expression that checks if this expression is not equal to a constant value. @@ -332,9 +350,9 @@ export abstract class ScalarExpr extends Expr { * @param other The constant value to compare for inequality. * @return A new `Expr` representing the inequality comparison. */ - neq(other: any): Neq; - neq(other: any): Neq { - return new Neq(this, valueToDefaultExpr(other)); + neq(other: any): BooleanExpr; + neq(other: any): BooleanExpr { + return new BooleanExpr('neq', [this, valueToDefaultExpr(other)]); } /** @@ -348,7 +366,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to compare for less than. * @return A new `Expr` representing the less than comparison. */ - lt(other: ScalarExpr): Lt; + lt(other: ScalarExpr): BooleanExpr; /** * Creates an expression that checks if this expression is less than a constant value. @@ -361,9 +379,9 @@ export abstract class ScalarExpr extends Expr { * @param other The constant value to compare for less than. * @return A new `Expr` representing the less than comparison. */ - lt(other: any): Lt; - lt(other: any): Lt { - return new Lt(this, valueToDefaultExpr(other)); + lt(other: any): BooleanExpr; + lt(other: any): BooleanExpr { + return new BooleanExpr('lt', [this, valueToDefaultExpr(other)]); } /** @@ -378,7 +396,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to compare for less than or equal to. * @return A new `Expr` representing the less than or equal to comparison. */ - lte(other: ScalarExpr): Lte; + lte(other: ScalarExpr): BooleanExpr; /** * Creates an expression that checks if this expression is less than or equal to a constant value. @@ -391,9 +409,9 @@ export abstract class ScalarExpr extends Expr { * @param other The constant value to compare for less than or equal to. * @return A new `Expr` representing the less than or equal to comparison. */ - lte(other: any): Lte; - lte(other: any): Lte { - return new Lte(this, valueToDefaultExpr(other)); + lte(other: any): BooleanExpr; + lte(other: any): BooleanExpr { + return new BooleanExpr('lte', [this, valueToDefaultExpr(other)]); } /** @@ -407,7 +425,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to compare for greater than. * @return A new `Expr` representing the greater than comparison. */ - gt(other: ScalarExpr): Gt; + gt(other: ScalarExpr): BooleanExpr; /** * Creates an expression that checks if this expression is greater than a constant value. @@ -420,9 +438,9 @@ export abstract class ScalarExpr extends Expr { * @param other The constant value to compare for greater than. * @return A new `Expr` representing the greater than comparison. */ - gt(other: any): Gt; - gt(other: any): Gt { - return new Gt(this, valueToDefaultExpr(other)); + gt(other: any): BooleanExpr; + gt(other: any): BooleanExpr { + return new BooleanExpr('gt', [this, valueToDefaultExpr(other)]); } /** @@ -437,7 +455,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to compare for greater than or equal to. * @return A new `Expr` representing the greater than or equal to comparison. */ - gte(other: ScalarExpr): Gte; + gte(other: ScalarExpr): BooleanExpr; /** * Creates an expression that checks if this expression is greater than or equal to a constant @@ -451,9 +469,9 @@ export abstract class ScalarExpr extends Expr { * @param other The constant value to compare for greater than or equal to. * @return A new `Expr` representing the greater than or equal to comparison. */ - gte(other: any): Gte; - gte(other: any): Gte { - return new Gte(this, valueToDefaultExpr(other)); + gte(other: any): BooleanExpr; + gte(other: any): BooleanExpr { + return new BooleanExpr('gte', [this, valueToDefaultExpr(other)]); } /** @@ -470,10 +488,10 @@ export abstract class ScalarExpr extends Expr { arrayConcat( secondArray: ScalarExpr | any[], ...otherArrays: Array - ): ArrayConcat { + ): FirestoreFunction { const elements = [secondArray, ...otherArrays]; const exprValues = elements.map(value => valueToDefaultExpr(value)); - return new ArrayConcat(this, exprValues); + return new FirestoreFunction('array_concat', [this, ...exprValues]); } /** @@ -487,7 +505,7 @@ export abstract class ScalarExpr extends Expr { * @param element The element to search for in the array. * @return A new `Expr` representing the 'array_contains' comparison. */ - arrayContains(element: ScalarExpr): ArrayContains; + arrayContains(element: ScalarExpr): BooleanExpr; /** * Creates an expression that checks if an array contains a specific value. @@ -500,9 +518,12 @@ export abstract class ScalarExpr extends Expr { * @param element The element to search for in the array. * @return A new `Expr` representing the 'array_contains' comparison. */ - arrayContains(element: any): ArrayContains; - arrayContains(element: any): ArrayContains { - return new ArrayContains(this, valueToDefaultExpr(element)); + arrayContains(element: any): BooleanExpr; + arrayContains(element: any): BooleanExpr { + return new BooleanExpr('array_contains', [ + this, + valueToDefaultExpr(element) + ]); } /** @@ -516,7 +537,7 @@ export abstract class ScalarExpr extends Expr { * @param values The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_all' comparison. */ - arrayContainsAll(...values: ScalarExpr[]): ArrayContainsAll; + arrayContainsAll(...values: ScalarExpr[]): BooleanExpr; /** * Creates an expression that checks if an array contains all the specified elements. @@ -529,12 +550,13 @@ export abstract class ScalarExpr extends Expr { * @param values The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_all' comparison. */ - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll { - const exprValues = values.map(value => - value instanceof ScalarExpr ? value : valueToDefaultExpr(value) - ); - return new ArrayContainsAll(this, exprValues); + arrayContainsAll(...values: any[]): BooleanExpr; + arrayContainsAll(...values: any[]): BooleanExpr { + const exprValues = values.map(value => valueToDefaultExpr(value)); + return new BooleanExpr('array_contains_all', [ + this, + new ListOfExprs(exprValues) + ]); } /** @@ -548,7 +570,7 @@ export abstract class ScalarExpr extends Expr { * @param values The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_any' comparison. */ - arrayContainsAny(...values: ScalarExpr[]): ArrayContainsAny; + arrayContainsAny(...values: ScalarExpr[]): BooleanExpr; /** * Creates an expression that checks if an array contains any of the specified elements. @@ -562,12 +584,13 @@ export abstract class ScalarExpr extends Expr { * @param values The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_any' comparison. */ - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny { - const exprValues = values.map(value => - value instanceof ScalarExpr ? value : valueToDefaultExpr(value) - ); - return new ArrayContainsAny(this, exprValues); + arrayContainsAny(...values: any[]): BooleanExpr; + arrayContainsAny(...values: any[]): BooleanExpr { + const exprValues = values.map(value => valueToDefaultExpr(value)); + return new BooleanExpr('array_contains_any', [ + this, + new ListOfExprs(exprValues) + ]); } /** @@ -580,8 +603,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `Expr` representing the length of the array. */ - arrayLength(): ArrayLength { - return new ArrayLength(this); + arrayLength(): FirestoreFunction { + return new FirestoreFunction('array_length', [this]); } /** @@ -596,7 +619,7 @@ export abstract class ScalarExpr extends Expr { * @param others The values or expressions to check against. * @return A new `Expr` representing the 'IN' comparison. */ - eqAny(...others: ScalarExpr[]): EqAny; + eqAny(...others: ScalarExpr[]): BooleanExpr; /** * Creates an expression that checks if this expression is equal to any of the provided values or @@ -610,12 +633,10 @@ export abstract class ScalarExpr extends Expr { * @param others The values or expressions to check against. * @return A new `Expr` representing the 'IN' comparison. */ - eqAny(...others: any[]): EqAny; - eqAny(...others: any[]): EqAny { - const exprOthers = others.map(other => - other instanceof ScalarExpr ? other : valueToDefaultExpr(other) - ); - return new EqAny(this, exprOthers); + eqAny(...others: any[]): BooleanExpr; + eqAny(...others: any[]): BooleanExpr { + const exprOthers = others.map(other => valueToDefaultExpr(other)); + return new BooleanExpr('eq_any', [this, new ListOfExprs(exprOthers)]); } /** @@ -630,7 +651,7 @@ export abstract class ScalarExpr extends Expr { * @param others The values or expressions to check against. * @return A new `Expr` representing the 'NotEqAny' comparison. */ - notEqAny(...others: ScalarExpr[]): NotEqAny; + notEqAny(...others: ScalarExpr[]): BooleanExpr; /** * Creates an expression that checks if this expression is not equal to any of the provided values or @@ -644,12 +665,10 @@ export abstract class ScalarExpr extends Expr { * @param others The values or expressions to check against. * @return A new `Expr` representing the 'NotEqAny' comparison. */ - notEqAny(...others: any[]): NotEqAny; - notEqAny(...others: any[]): NotEqAny { - const exprOthers = others.map(other => - other instanceof ScalarExpr ? other : valueToDefaultExpr(other) - ); - return new NotEqAny(this, exprOthers); + notEqAny(...others: any[]): BooleanExpr; + notEqAny(...others: any[]): BooleanExpr { + const exprOthers = others.map(other => valueToDefaultExpr(other)); + return new BooleanExpr('not_eq_any', [this, new ListOfExprs(exprOthers)]); } /** @@ -662,8 +681,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `Expr` representing the 'isNaN' check. */ - isNaN(): IsNan { - return new IsNan(this); + isNan(): BooleanExpr { + return new BooleanExpr('is_nan', [this]); } /** @@ -676,8 +695,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `Expr` representing the 'isNull' check. */ - isNull(): IsNull { - return new IsNull(this); + isNull(): BooleanExpr { + return new BooleanExpr('is_null', [this]); } /** @@ -690,8 +709,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `Expr` representing the 'exists' check. */ - exists(): Exists { - return new Exists(this); + exists(): BooleanExpr { + return new BooleanExpr('exists', [this]); } /** @@ -704,8 +723,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `Expr` representing the length of the string. */ - charLength(): CharLength { - return new CharLength(this); + charLength(): FirestoreFunction { + return new FirestoreFunction('char_length', [this]); } /** @@ -719,7 +738,7 @@ export abstract class ScalarExpr extends Expr { * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new `Expr` representing the 'like' comparison. */ - like(pattern: string): Like; + like(pattern: string): FirestoreFunction; /** * Creates an expression that performs a case-sensitive string comparison. @@ -732,12 +751,12 @@ export abstract class ScalarExpr extends Expr { * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new `Expr` representing the 'like' comparison. */ - like(pattern: ScalarExpr): Like; - like(stringOrExpr: string | ScalarExpr): Like { - if (typeof stringOrExpr === 'string') { - return new Like(this, Constant.of(stringOrExpr)); - } - return new Like(this, stringOrExpr as ScalarExpr); + like(pattern: ScalarExpr): FirestoreFunction; + like(stringOrExpr: string | ScalarExpr): FirestoreFunction { + return new FirestoreFunction('like', [ + this, + valueToDefaultExpr(stringOrExpr) + ]); } /** @@ -752,7 +771,7 @@ export abstract class ScalarExpr extends Expr { * @param pattern The regular expression to use for the search. * @return A new `Expr` representing the 'contains' comparison. */ - regexContains(pattern: string): RegexContains; + regexContains(pattern: string): BooleanExpr; /** * Creates an expression that checks if a string contains a specified regular expression as a @@ -766,12 +785,12 @@ export abstract class ScalarExpr extends Expr { * @param pattern The regular expression to use for the search. * @return A new `Expr` representing the 'contains' comparison. */ - regexContains(pattern: ScalarExpr): RegexContains; - regexContains(stringOrExpr: string | ScalarExpr): RegexContains { - if (typeof stringOrExpr === 'string') { - return new RegexContains(this, Constant.of(stringOrExpr)); - } - return new RegexContains(this, stringOrExpr as ScalarExpr); + regexContains(pattern: ScalarExpr): BooleanExpr; + regexContains(stringOrExpr: string | ScalarExpr): BooleanExpr { + return new BooleanExpr('regex_contains', [ + this, + valueToDefaultExpr(stringOrExpr) + ]); } /** @@ -785,7 +804,7 @@ export abstract class ScalarExpr extends Expr { * @param pattern The regular expression to use for the match. * @return A new `Expr` representing the regular expression match. */ - regexMatch(pattern: string): RegexMatch; + regexMatch(pattern: string): BooleanExpr; /** * Creates an expression that checks if a string matches a specified regular expression. @@ -798,12 +817,12 @@ export abstract class ScalarExpr extends Expr { * @param pattern The regular expression to use for the match. * @return A new `Expr` representing the regular expression match. */ - regexMatch(pattern: ScalarExpr): RegexMatch; - regexMatch(stringOrExpr: string | ScalarExpr): RegexMatch { - if (typeof stringOrExpr === 'string') { - return new RegexMatch(this, Constant.of(stringOrExpr)); - } - return new RegexMatch(this, stringOrExpr as ScalarExpr); + regexMatch(pattern: ScalarExpr): BooleanExpr; + regexMatch(stringOrExpr: string | ScalarExpr): BooleanExpr { + return new BooleanExpr('regex_match', [ + this, + valueToDefaultExpr(stringOrExpr) + ]); } /** @@ -817,7 +836,7 @@ export abstract class ScalarExpr extends Expr { * @param substring The substring to search for. * @return A new `Expr` representing the 'contains' comparison. */ - strContains(substring: string): StrContains; + strContains(substring: string): BooleanExpr; /** * Creates an expression that checks if a string contains the string represented by another expression. @@ -830,12 +849,12 @@ export abstract class ScalarExpr extends Expr { * @param expr The expression representing the substring to search for. * @return A new `Expr` representing the 'contains' comparison. */ - strContains(expr: ScalarExpr): StrContains; - strContains(stringOrExpr: string | ScalarExpr): StrContains { - if (typeof stringOrExpr === 'string') { - return new StrContains(this, Constant.of(stringOrExpr)); - } - return new StrContains(this, stringOrExpr as ScalarExpr); + strContains(expr: ScalarExpr): BooleanExpr; + strContains(stringOrExpr: string | ScalarExpr): BooleanExpr { + return new BooleanExpr('str_contains', [ + this, + valueToDefaultExpr(stringOrExpr) + ]); } /** @@ -849,7 +868,7 @@ export abstract class ScalarExpr extends Expr { * @param prefix The prefix to check for. * @return A new `Expr` representing the 'starts with' comparison. */ - startsWith(prefix: string): StartsWith; + startsWith(prefix: string): BooleanExpr; /** * Creates an expression that checks if a string starts with a given prefix (represented as an @@ -863,12 +882,12 @@ export abstract class ScalarExpr extends Expr { * @param prefix The prefix expression to check for. * @return A new `Expr` representing the 'starts with' comparison. */ - startsWith(prefix: ScalarExpr): StartsWith; - startsWith(stringOrExpr: string | ScalarExpr): StartsWith { - if (typeof stringOrExpr === 'string') { - return new StartsWith(this, Constant.of(stringOrExpr)); - } - return new StartsWith(this, stringOrExpr as ScalarExpr); + startsWith(prefix: ScalarExpr): BooleanExpr; + startsWith(stringOrExpr: string | ScalarExpr): BooleanExpr { + return new BooleanExpr('starts_with', [ + this, + valueToDefaultExpr(stringOrExpr) + ]); } /** @@ -882,7 +901,7 @@ export abstract class ScalarExpr extends Expr { * @param suffix The postfix to check for. * @return A new `Expr` representing the 'ends with' comparison. */ - endsWith(suffix: string): EndsWith; + endsWith(suffix: string): BooleanExpr; /** * Creates an expression that checks if a string ends with a given postfix (represented as an @@ -896,12 +915,12 @@ export abstract class ScalarExpr extends Expr { * @param suffix The postfix expression to check for. * @return A new `Expr` representing the 'ends with' comparison. */ - endsWith(suffix: ScalarExpr): EndsWith; - endsWith(stringOrExpr: string | ScalarExpr): EndsWith { - if (typeof stringOrExpr === 'string') { - return new EndsWith(this, Constant.of(stringOrExpr)); - } - return new EndsWith(this, stringOrExpr as ScalarExpr); + endsWith(suffix: ScalarExpr): BooleanExpr; + endsWith(stringOrExpr: string | ScalarExpr): BooleanExpr { + return new BooleanExpr('ends_with', [ + this, + valueToDefaultExpr(stringOrExpr) + ]); } /** @@ -914,8 +933,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `Expr` representing the lowercase string. */ - toLower(): ToLower { - return new ToLower(this); + toLower(): FirestoreFunction { + return new FirestoreFunction('to_lower', [this]); } /** @@ -928,8 +947,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `Expr` representing the uppercase string. */ - toUpper(): ToUpper { - return new ToUpper(this); + toUpper(): FirestoreFunction { + return new FirestoreFunction('to_upper', [this]); } /** @@ -942,8 +961,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `Expr` representing the trimmed string. */ - trim(): Trim { - return new Trim(this); + trim(): FirestoreFunction { + return new FirestoreFunction('trim', [this]); } /** @@ -961,12 +980,10 @@ export abstract class ScalarExpr extends Expr { strConcat( secondString: ScalarExpr | string, ...otherStrings: Array - ): StrConcat { + ): FirestoreFunction { const elements = [secondString, ...otherStrings]; - const exprs = elements.map(e => - typeof e === 'string' ? Constant.of(e) : (e as ScalarExpr) - ); - return new StrConcat(this, exprs); + const exprs = elements.map(valueToDefaultExpr); + return new FirestoreFunction('str_concat', [this, ...exprs]); } /** @@ -979,8 +996,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new {@code Expr} representing the reversed string. */ - reverse(): Reverse { - return new Reverse(this); + reverse(): FirestoreFunction { + return new FirestoreFunction('reverse', [this]); } /** @@ -995,7 +1012,7 @@ export abstract class ScalarExpr extends Expr { * @param replace The substring to replace the first occurrence of 'find' with. * @return A new {@code Expr} representing the string with the first occurrence replaced. */ - replaceFirst(find: string, replace: string): ReplaceFirst; + replaceFirst(find: string, replace: string): FirestoreFunction; /** * Creates an expression that replaces the first occurrence of a substring within this string expression with another substring, @@ -1010,19 +1027,16 @@ export abstract class ScalarExpr extends Expr { * @param replace The expression representing the substring to replace the first occurrence of 'find' with. * @return A new {@code Expr} representing the string with the first occurrence replaced. */ - replaceFirst(find: ScalarExpr, replace: ScalarExpr): ReplaceFirst; + replaceFirst(find: ScalarExpr, replace: ScalarExpr): FirestoreFunction; replaceFirst( find: ScalarExpr | string, replace: ScalarExpr | string - ): ReplaceFirst { - const normalizedFind = typeof find === 'string' ? Constant.of(find) : find; - const normalizedReplace = - typeof replace === 'string' ? Constant.of(replace) : replace; - return new ReplaceFirst( + ): FirestoreFunction { + return new FirestoreFunction('replace_first', [ this, - normalizedFind as ScalarExpr, - normalizedReplace as ScalarExpr - ); + valueToDefaultExpr(find), + valueToDefaultExpr(replace) + ]); } /** @@ -1037,7 +1051,7 @@ export abstract class ScalarExpr extends Expr { * @param replace The substring to replace all occurrences of 'find' with. * @return A new {@code Expr} representing the string with all occurrences replaced. */ - replaceAll(find: string, replace: string): ReplaceAll; + replaceAll(find: string, replace: string): FirestoreFunction; /** * Creates an expression that replaces all occurrences of a substring within this string expression with another substring, @@ -1052,19 +1066,16 @@ export abstract class ScalarExpr extends Expr { * @param replace The expression representing the substring to replace all occurrences of 'find' with. * @return A new {@code Expr} representing the string with all occurrences replaced. */ - replaceAll(find: ScalarExpr, replace: ScalarExpr): ReplaceAll; + replaceAll(find: ScalarExpr, replace: ScalarExpr): FirestoreFunction; replaceAll( find: ScalarExpr | string, replace: ScalarExpr | string - ): ReplaceAll { - const normalizedFind = typeof find === 'string' ? Constant.of(find) : find; - const normalizedReplace = - typeof replace === 'string' ? Constant.of(replace) : replace; - return new ReplaceAll( + ): FirestoreFunction { + return new FirestoreFunction('replace_all', [ this, - normalizedFind as ScalarExpr, - normalizedReplace as ScalarExpr - ); + valueToDefaultExpr(find), + valueToDefaultExpr(replace) + ]); } /** @@ -1077,8 +1088,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new {@code Expr} representing the length of the string in bytes. */ - byteLength(): ByteLength { - return new ByteLength(this); + byteLength(): FirestoreFunction { + return new FirestoreFunction('byte_length', [this]); } /** @@ -1092,8 +1103,8 @@ export abstract class ScalarExpr extends Expr { * @param subfield The key to access in the map. * @return A new `Expr` representing the value associated with the given key in the map. */ - mapGet(subfield: string): MapGet { - return new MapGet(this, subfield); + mapGet(subfield: string): FirestoreFunction { + return new FirestoreFunction('map_get', [this, Constant.of(subfield)]); } /** @@ -1107,8 +1118,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `AggregateFunction` representing the 'count' aggregation. */ - count(): Count { - return new Count(this, false); + count(): AggregateFunction { + return new AggregateFunction('count', [this]); } /** @@ -1121,8 +1132,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `AggregateFunction` representing the 'sum' aggregation. */ - sum(): Sum { - return new Sum(this, false); + sum(): AggregateFunction { + return new AggregateFunction('sum', [this]); } /** @@ -1136,8 +1147,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `AggregateFunction` representing the 'avg' aggregation. */ - avg(): Avg { - return new Avg(this, false); + avg(): AggregateFunction { + return new AggregateFunction('avg', [this]); } /** @@ -1150,8 +1161,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `AggregateFunction` representing the 'min' aggregation. */ - minimum(): Minimum { - return new Minimum(this, false); + minimum(): AggregateFunction { + return new AggregateFunction('minimum', [this]); } /** @@ -1164,8 +1175,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new `AggregateFunction` representing the 'max' aggregation. */ - maximum(): Maximum { - return new Maximum(this, false); + maximum(): AggregateFunction { + return new AggregateFunction('maximum', [this]); } /** @@ -1183,12 +1194,12 @@ export abstract class ScalarExpr extends Expr { logicalMaximum( second: ScalarExpr | any, ...others: Array - ): LogicalMaximum { + ): FirestoreFunction { const values = [second, ...others]; - return new LogicalMaximum( + return new FirestoreFunction('logical_maximum', [ this, - values.map(value => valueToDefaultExpr(value)) - ); + ...values.map(valueToDefaultExpr) + ]); } /** @@ -1206,12 +1217,12 @@ export abstract class ScalarExpr extends Expr { logicalMinimum( second: ScalarExpr | any, ...others: Array - ): LogicalMinimum { + ): FirestoreFunction { const values = [second, ...others]; - return new LogicalMinimum( + return new FirestoreFunction('logical_min', [ this, - values.map(value => valueToDefaultExpr(value)) - ); + ...values.map(valueToDefaultExpr) + ]); } /** @@ -1224,8 +1235,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new {@code Expr} representing the length of the vector. */ - vectorLength(): VectorLength { - return new VectorLength(this); + vectorLength(): FirestoreFunction { + return new FirestoreFunction('vector_length', [this]); } /** @@ -1239,7 +1250,7 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (represented as an Expr) to compare against. * @return A new `Expr` representing the cosine distance between the two vectors. */ - cosineDistance(other: ScalarExpr): CosineDistance; + cosineDistance(other: ScalarExpr): FirestoreFunction; /** * Calculates the Cosine distance between two vectors. * @@ -1251,7 +1262,7 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (as a VectorValue) to compare against. * @return A new `Expr` representing the Cosine* distance between the two vectors. */ - cosineDistance(other: VectorValue): CosineDistance; + cosineDistance(other: VectorValue): FirestoreFunction; /** * Calculates the Cosine distance between two vectors. * @@ -1263,16 +1274,14 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (as an array of numbers) to compare against. * @return A new `Expr` representing the Cosine distance between the two vectors. */ - cosineDistance(other: number[]): CosineDistance; - cosineDistance(other: ScalarExpr | VectorValue | number[]): CosineDistance { - if (other instanceof ScalarExpr) { - return new CosineDistance(this, other as ScalarExpr); - } else { - return new CosineDistance( - this, - Constant.vector(other as VectorValue | number[]) - ); - } + cosineDistance(other: number[]): FirestoreFunction; + cosineDistance( + other: ScalarExpr | VectorValue | number[] + ): FirestoreFunction { + return new FirestoreFunction('cosine_distance', [ + this, + vectorToExpr(other) + ]); } /** @@ -1286,7 +1295,7 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the dot product between the two vectors. */ - dotProduct(other: ScalarExpr): DotProduct; + dotProduct(other: ScalarExpr): FirestoreFunction; /** * Calculates the dot product between two vectors. @@ -1299,7 +1308,7 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the dot product between the two vectors. */ - dotProduct(other: VectorValue): DotProduct; + dotProduct(other: VectorValue): FirestoreFunction; /** * Calculates the dot product between two vectors. @@ -1312,16 +1321,9 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the dot product between the two vectors. */ - dotProduct(other: number[]): DotProduct; - dotProduct(other: ScalarExpr | VectorValue | number[]): DotProduct { - if (other instanceof ScalarExpr) { - return new DotProduct(this, other as ScalarExpr); - } else { - return new DotProduct( - this, - Constant.vector(other as VectorValue | number[]) - ); - } + dotProduct(other: number[]): FirestoreFunction; + dotProduct(other: ScalarExpr | VectorValue | number[]): FirestoreFunction { + return new FirestoreFunction('dot_product', [this, vectorToExpr(other)]); } /** @@ -1335,7 +1337,7 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the Euclidean distance between the two vectors. */ - euclideanDistance(other: ScalarExpr): EuclideanDistance; + euclideanDistance(other: ScalarExpr): FirestoreFunction; /** * Calculates the Euclidean distance between two vectors. @@ -1348,7 +1350,7 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (as a VectorValue) to compare against. * @return A new `Expr` representing the Euclidean distance between the two vectors. */ - euclideanDistance(other: VectorValue): EuclideanDistance; + euclideanDistance(other: VectorValue): FirestoreFunction; /** * Calculates the Euclidean distance between two vectors. @@ -1361,18 +1363,66 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (as an array of numbers) to compare against. * @return A new `Expr` representing the Euclidean distance between the two vectors. */ - euclideanDistance(other: number[]): EuclideanDistance; + euclideanDistance(other: number[]): FirestoreFunction; euclideanDistance( other: ScalarExpr | VectorValue | number[] - ): EuclideanDistance { - if (other instanceof ScalarExpr) { - return new EuclideanDistance(this, other as ScalarExpr); - } else { - return new EuclideanDistance( - this, - Constant.vector(other as VectorValue | number[]) - ); - } + ): FirestoreFunction { + return new FirestoreFunction('euclidean_distance', [ + this, + vectorToExpr(other) + ]); + } + /** + * @beta + * + * Calculates the Manhattan distance between the result of this expression and another VectorValue. + * + * ```typescript + * // Calculate the Manhattan distance between the 'location' field and a target location + * Field.of("location").manhattanDistance(new VectorValue([37.7749, -122.4194])); + * ``` + * + * @param other The other vector (as a VectorValue) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ + manhattanDistance(other: VectorValue): FirestoreFunction; + + /** + * @beta + * + * Calculates the Manhattan distance between the result of this expression and a double array. + * + * ```typescript + * // Calculate the Manhattan distance between the 'location' field and a target location + * Field.of("location").manhattanDistance([37.7749, -122.4194]); + * ``` + * + * @param other The other vector (as an array of doubles) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ + manhattanDistance(other: number[]): FirestoreFunction; + + /** + * @beta + * + * Calculates the Manhattan distance between two vector expressions. + * + * ```typescript + * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' + * Field.of("pointA").manhattanDistance(Field.of("pointB")); + * ``` + * + * @param other The other vector (represented as an Expr) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ + manhattanDistance(other: ScalarExpr): FirestoreFunction; + manhattanDistance( + other: ScalarExpr | number[] | VectorValue + ): FirestoreFunction { + return new FirestoreFunction('manhattan_distance', [ + this, + vectorToExpr(other) + ]); } /** @@ -1386,8 +1436,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new {@code Expr} representing the timestamp. */ - unixMicrosToTimestamp(): UnixMicrosToTimestamp { - return new UnixMicrosToTimestamp(this); + unixMicrosToTimestamp(): FirestoreFunction { + return new FirestoreFunction('unix_micros_to_timestamp', [this]); } /** @@ -1400,8 +1450,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new {@code Expr} representing the number of microseconds since epoch. */ - timestampToUnixMicros(): TimestampToUnixMicros { - return new TimestampToUnixMicros(this); + timestampToUnixMicros(): FirestoreFunction { + return new FirestoreFunction('timestamp_to_unix_micros', [this]); } /** @@ -1415,8 +1465,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new {@code Expr} representing the timestamp. */ - unixMillisToTimestamp(): UnixMillisToTimestamp { - return new UnixMillisToTimestamp(this); + unixMillisToTimestamp(): FirestoreFunction { + return new FirestoreFunction('unix_millis_to_timestamp', [this]); } /** @@ -1429,8 +1479,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new {@code Expr} representing the number of milliseconds since epoch. */ - timestampToUnixMillis(): TimestampToUnixMillis { - return new TimestampToUnixMillis(this); + timestampToUnixMillis(): FirestoreFunction { + return new FirestoreFunction('timestamp_to_unix_millis', [this]); } /** @@ -1444,8 +1494,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new {@code Expr} representing the timestamp. */ - unixSecondsToTimestamp(): UnixSecondsToTimestamp { - return new UnixSecondsToTimestamp(this); + unixSecondsToTimestamp(): FirestoreFunction { + return new FirestoreFunction('unix_seconds_to_timestamp', [this]); } /** @@ -1458,8 +1508,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new {@code Expr} representing the number of seconds since epoch. */ - timestampToUnixSeconds(): TimestampToUnixSeconds { - return new TimestampToUnixSeconds(this); + timestampToUnixSeconds(): FirestoreFunction { + return new FirestoreFunction('timestamp_to_unix_seconds', [this]); } /** @@ -1474,7 +1524,7 @@ export abstract class ScalarExpr extends Expr { * @param amount The expression evaluates to amount of the unit. * @return A new {@code Expr} representing the resulting timestamp. */ - timestampAdd(unit: ScalarExpr, amount: ScalarExpr): TimestampAdd; + timestampAdd(unit: ScalarExpr, amount: ScalarExpr): FirestoreFunction; /** * Creates an expression that adds a specified amount of time to this timestamp expression. @@ -1491,7 +1541,7 @@ export abstract class ScalarExpr extends Expr { timestampAdd( unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number - ): TimestampAdd; + ): FirestoreFunction; timestampAdd( unit: | ScalarExpr @@ -1502,15 +1552,12 @@ export abstract class ScalarExpr extends Expr { | 'hour' | 'day', amount: ScalarExpr | number - ): TimestampAdd { - const normalizedUnit = typeof unit === 'string' ? Constant.of(unit) : unit; - const normalizedAmount = - typeof amount === 'number' ? Constant.of(amount) : amount; - return new TimestampAdd( + ): FirestoreFunction { + return new FirestoreFunction('timestamp_add', [ this, - normalizedUnit as ScalarExpr, - normalizedAmount as ScalarExpr - ); + valueToDefaultExpr(unit), + valueToDefaultExpr(amount) + ]); } /** @@ -1525,7 +1572,7 @@ export abstract class ScalarExpr extends Expr { * @param amount The expression evaluates to amount of the unit. * @return A new {@code Expr} representing the resulting timestamp. */ - timestampSub(unit: ScalarExpr, amount: ScalarExpr): TimestampSub; + timestampSub(unit: ScalarExpr, amount: ScalarExpr): FirestoreFunction; /** * Creates an expression that subtracts a specified amount of time from this timestamp expression. @@ -1542,7 +1589,7 @@ export abstract class ScalarExpr extends Expr { timestampSub( unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number - ): TimestampSub; + ): FirestoreFunction; timestampSub( unit: | ScalarExpr @@ -1553,15 +1600,12 @@ export abstract class ScalarExpr extends Expr { | 'hour' | 'day', amount: ScalarExpr | number - ): TimestampSub { - const normalizedUnit = typeof unit === 'string' ? Constant.of(unit) : unit; - const normalizedAmount = - typeof amount === 'number' ? Constant.of(amount) : amount; - return new TimestampSub( + ): FirestoreFunction { + return new FirestoreFunction('timestamp_sub', [ this, - normalizedUnit as ScalarExpr, - normalizedAmount as ScalarExpr - ); + valueToDefaultExpr(unit), + valueToDefaultExpr(amount) + ]); } /** @@ -1577,7 +1621,7 @@ export abstract class ScalarExpr extends Expr { * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise AND operation. */ - bitAnd(otherBits: number | Bytes): BitAnd; + bitAnd(otherBits: number | Bytes): FirestoreFunction; /** * @beta * @@ -1591,9 +1635,12 @@ export abstract class ScalarExpr extends Expr { * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise AND operation. */ - bitAnd(bitsExpression: ScalarExpr): BitAnd; - bitAnd(bitsOrExpression: number | ScalarExpr | Bytes): BitAnd { - return new BitAnd(this, valueToDefaultExpr(bitsOrExpression)); + bitAnd(bitsExpression: ScalarExpr): FirestoreFunction; + bitAnd(bitsOrExpression: number | ScalarExpr | Bytes): FirestoreFunction { + return new FirestoreFunction('bit_and', [ + this, + valueToDefaultExpr(bitsOrExpression) + ]); } /** @@ -1609,7 +1656,7 @@ export abstract class ScalarExpr extends Expr { * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise OR operation. */ - bitOr(otherBits: number | Bytes): BitOr; + bitOr(otherBits: number | Bytes): FirestoreFunction; /** * @beta * @@ -1623,9 +1670,12 @@ export abstract class ScalarExpr extends Expr { * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise OR operation. */ - bitOr(bitsExpression: ScalarExpr): BitOr; - bitOr(bitsOrExpression: number | ScalarExpr | Bytes): BitOr { - return new BitOr(this, valueToDefaultExpr(bitsOrExpression)); + bitOr(bitsExpression: ScalarExpr): FirestoreFunction; + bitOr(bitsOrExpression: number | ScalarExpr | Bytes): FirestoreFunction { + return new FirestoreFunction('bit_or', [ + this, + valueToDefaultExpr(bitsOrExpression) + ]); } /** @@ -1641,7 +1691,7 @@ export abstract class ScalarExpr extends Expr { * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise XOR operation. */ - bitXor(otherBits: number | Bytes): BitXor; + bitXor(otherBits: number | Bytes): FirestoreFunction; /** * @beta * @@ -1655,9 +1705,12 @@ export abstract class ScalarExpr extends Expr { * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise XOR operation. */ - bitXor(bitsExpression: ScalarExpr): BitXor; - bitXor(bitsOrExpression: number | ScalarExpr | Bytes): BitXor { - return new BitXor(this, valueToDefaultExpr(bitsOrExpression)); + bitXor(bitsExpression: ScalarExpr): FirestoreFunction; + bitXor(bitsOrExpression: number | ScalarExpr | Bytes): FirestoreFunction { + return new FirestoreFunction('bit_xor', [ + this, + valueToDefaultExpr(bitsOrExpression) + ]); } /** @@ -1672,8 +1725,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new {@code Expr} representing the bitwise NOT operation. */ - bitNot(): BitNot { - return new BitNot(this); + bitNot(): FirestoreFunction { + return new FirestoreFunction('bit_not', [this]); } /** @@ -1689,7 +1742,7 @@ export abstract class ScalarExpr extends Expr { * @param y The operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ - bitLeftShift(y: number): BitLeftShift; + bitLeftShift(y: number): FirestoreFunction; /** * @beta * @@ -1703,9 +1756,12 @@ export abstract class ScalarExpr extends Expr { * @param numberExpr The operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ - bitLeftShift(numberExpr: ScalarExpr): BitLeftShift; - bitLeftShift(numberExpr: number | ScalarExpr): BitLeftShift { - return new BitLeftShift(this, valueToDefaultExpr(numberExpr)); + bitLeftShift(numberExpr: ScalarExpr): FirestoreFunction; + bitLeftShift(numberExpr: number | ScalarExpr): FirestoreFunction { + return new FirestoreFunction('bit_left_shift', [ + this, + valueToDefaultExpr(numberExpr) + ]); } /** @@ -1721,7 +1777,7 @@ export abstract class ScalarExpr extends Expr { * @param right The operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ - bitRightShift(y: number): BitRightShift; + bitRightShift(y: number): FirestoreFunction; /** * @beta * @@ -1735,9 +1791,12 @@ export abstract class ScalarExpr extends Expr { * @param numberExpr The operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ - bitRightShift(numberExpr: ScalarExpr): BitRightShift; - bitRightShift(numberExpr: number | ScalarExpr): BitRightShift { - return new BitRightShift(this, valueToDefaultExpr(numberExpr)); + bitRightShift(numberExpr: ScalarExpr): FirestoreFunction; + bitRightShift(numberExpr: number | ScalarExpr): FirestoreFunction { + return new FirestoreFunction('bit_right_shift', [ + this, + valueToDefaultExpr(numberExpr) + ]); } /** @@ -1752,8 +1811,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new {@code Expr} representing the documentId operation. */ - documentId(): DocumentId { - return new DocumentId(this); + documentId(): FirestoreFunction { + return new FirestoreFunction('document_id', [this]); } /** @@ -1765,7 +1824,7 @@ export abstract class ScalarExpr extends Expr { * @param length Length of the substring. If not provided, the substring will * end at the end of the input. */ - substr(position: number, length?: number): Substr; + substr(position: number, length?: number): FirestoreFunction; /** * @beta @@ -1776,12 +1835,21 @@ export abstract class ScalarExpr extends Expr { * @param length An expression returning the length of the substring. If not provided the * substring will end at the end of the input. */ - substr(position: ScalarExpr, length?: ScalarExpr): Substr; - substr(position: ScalarExpr | number, length?: ScalarExpr | number): Substr { + substr(position: ScalarExpr, length?: ScalarExpr): FirestoreFunction; + substr( + position: ScalarExpr | number, + length?: ScalarExpr | number + ): FirestoreFunction { const positionExpr = valueToDefaultExpr(position); - const lengthExpr = - length === undefined ? undefined : valueToDefaultExpr(length); - return new Substr(this, positionExpr, lengthExpr); + if (length === undefined) { + return new FirestoreFunction('substr', [this, positionExpr]); + } else { + return new FirestoreFunction('substr', [ + this, + positionExpr, + valueToDefaultExpr(length) + ]); + } } /** @@ -1798,7 +1866,7 @@ export abstract class ScalarExpr extends Expr { * @param offset The index of the element to return. * @return A new Expr representing the 'arrayOffset' operation. */ - arrayOffset(offset: number): ArrayOffset; + arrayOffset(offset: number): FirestoreFunction; /** * @beta @@ -1815,9 +1883,12 @@ export abstract class ScalarExpr extends Expr { * @param offsetExpr An Expr evaluating to the index of the element to return. * @return A new Expr representing the 'arrayOffset' operation. */ - arrayOffset(offsetExpr: ScalarExpr): ArrayOffset; - arrayOffset(offset: ScalarExpr | number): ArrayOffset { - return new ArrayOffset(fieldOfOrExpr(array), valueToDefaultExpr(offset)); + arrayOffset(offsetExpr: ScalarExpr): FirestoreFunction; + arrayOffset(offset: ScalarExpr | number): FirestoreFunction { + return new FirestoreFunction('array_offset', [ + this, + valueToDefaultExpr(offset) + ]); } /** @@ -1830,10 +1901,10 @@ export abstract class ScalarExpr extends Expr { * Field.of("title").arrayContains(1).isError(); * ``` * - * @return A new {@code Expr} representing the 'isError' check. + * @return A new {@code BooleanExpr} representing the 'isError' check. */ - isError(): IsError { - return new IsError(this); + isError(): BooleanExpr { + return new BooleanExpr('is_error', [this]); } /** @@ -1852,7 +1923,7 @@ export abstract class ScalarExpr extends Expr { * returned if this expression produces an error. * @return A new {@code Expr} representing the 'ifError' operation. */ - ifError(catchExpr: ScalarExpr): IfError; + ifError(catchExpr: ScalarExpr): FirestoreFunction; /** * @beta @@ -1870,9 +1941,12 @@ export abstract class ScalarExpr extends Expr { * produces an error. * @return A new {@code Expr} representing the 'ifError' operation. */ - ifError(catchValue: any): IfError; - ifError(catchValue: any): IfError { - return new IfError(this, valueToDefaultExpr(catchValue)); + ifError(catchValue: any): FirestoreFunction; + ifError(catchValue: any): FirestoreFunction { + return new FirestoreFunction('if_error', [ + this, + valueToDefaultExpr(catchValue) + ]); } /** @@ -1886,10 +1960,10 @@ export abstract class ScalarExpr extends Expr { * Field.of("value").isAbsent(); * ``` * - * @return A new {@code Expr} representing the 'isAbsent' check. + * @return A new {@code BooleanExpr} representing the 'isAbsent' check. */ - isAbsent(): IsAbsent { - return new IsAbsent(this); + isAbsent(): BooleanExpr { + return new BooleanExpr('is_absent', [this]); } /** @@ -1902,10 +1976,10 @@ export abstract class ScalarExpr extends Expr { * Field.of("name").isNotNull(); * ``` * - * @return A new {@code Expr} representing the 'isNotNull' check. + * @return A new {@code BooleanExpr} representing the 'isNotNull' check. */ - isNotNull(): IsNotNull { - return new IsNotNull(this); + isNotNull(): BooleanExpr { + return new BooleanExpr('is_not_null', [this]); } /** @@ -1920,8 +1994,8 @@ export abstract class ScalarExpr extends Expr { * * @return A new {@code Expr} representing the 'isNaN' check. */ - isNotNan(): IsNotNan { - return new IsNotNan(this); + isNotNan(): BooleanExpr { + return new BooleanExpr('is_not_nan', [this]); } /** @@ -1935,8 +2009,9 @@ export abstract class ScalarExpr extends Expr { * ``` * * @param key The name of the key to remove from the input map. + * @returns A new {@code FirestoreFunction} representing the 'mapRemove' operation. */ - mapRemove(key: string): MapRemove; + mapRemove(key: string): FirestoreFunction; /** * @beta * @@ -1948,10 +2023,14 @@ export abstract class ScalarExpr extends Expr { * ``` * * @param keyExpr An expression that produces the name of the key to remove from the input map. + * @returns A new {@code FirestoreFunction} representing the 'mapRemove' operation. */ - mapRemove(keyExpr: ScalarExpr): MapRemove; - mapRemove(stringExpr: ScalarExpr | string): MapRemove { - return new MapRemove(this, valueToDefaultExpr(stringExpr)); + mapRemove(keyExpr: ScalarExpr): FirestoreFunction; + mapRemove(stringExpr: ScalarExpr | string): FirestoreFunction { + return new FirestoreFunction('map_remove', [ + this, + valueToDefaultExpr(stringExpr) + ]); } /** @@ -1969,65 +2048,20 @@ export abstract class ScalarExpr extends Expr { * an expression that returns a map. * @param otherMaps Optional additional maps to merge. Each map is represented * as a literal or an expression that returns a map. + * + * @returns A new {@code FirestoreFunction} representing the 'mapMerge' operation. */ mapMerge( secondMap: Record | ScalarExpr, ...otherMaps: Array | ScalarExpr> - ): MapMerge { + ): FirestoreFunction { const secondMapExpr = valueToDefaultExpr(secondMap); const otherMapExprs = otherMaps.map(valueToDefaultExpr); - return new MapMerge([this, secondMapExpr, ...otherMapExprs]); - } - - /** - * @beta - * - * Calculates the Manhattan distance between the result of this expression and another VectorValue. - * - * ```typescript - * // Calculate the Manhattan distance between the 'location' field and a target location - * Field.of("location").manhattanDistance(new VectorValue([37.7749, -122.4194])); - * ``` - * - * @param other The other vector (as a VectorValue) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ - manhattanDistance(other: VectorValue): ManhattanDistance; - - /** - * @beta - * - * Calculates the Manhattan distance between the result of this expression and a double array. - * - * ```typescript - * // Calculate the Manhattan distance between the 'location' field and a target location - * Field.of("location").manhattanDistance([37.7749, -122.4194]); - * ``` - * - * @param other The other vector (as an array of doubles) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ - manhattanDistance(other: number[]): ManhattanDistance; - - /** - * @beta - * - * Calculates the Manhattan distance between two vector expressions. - * - * ```typescript - * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' - * Field.of("pointA").manhattanDistance(Field.of("pointB")); - * ``` - * - * @param other The other vector (represented as an Expr) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ - manhattanDistance(other: ScalarExpr): ManhattanDistance; - manhattanDistance( - other: ScalarExpr | number[] | VectorValue - ): ManhattanDistance { - const expr2 = other instanceof ScalarExpr ? other : Constant.vector(other); - return new ManhattanDistance(this, expr2); + return new FirestoreFunction('map_merge', [ + this, + secondMapExpr, + ...otherMapExprs + ]); } /** @@ -2076,7 +2110,7 @@ export abstract class ScalarExpr extends Expr { * @return A new {@link ExprWithAlias} that wraps this * expression and associates it with the provided alias. */ - as(name: string): ExprWithAlias { + as(name: string): ExprWithAlias { return new ExprWithAlias(this, name); } } @@ -2176,13 +2210,11 @@ export class AggregateFunctionWithAlias /** * @beta */ -export class ExprWithAlias - implements Selectable, UserData -{ +export class ExprWithAlias implements Selectable, UserData { exprType: ExprType = 'ExprWithAlias'; selectable = true as const; - constructor(readonly expr: T, readonly alias: string) {} + constructor(readonly expr: ScalarExpr, readonly alias: string) {} /** * @private @@ -2601,7 +2633,7 @@ export class BooleanExpr extends FirestoreFunction { * @return A new `AggregateFunction` representing the 'countIf' aggregation. */ countIf(): AggregateFunction { - return new CountIf(this); + return new AggregateFunction('count_if', [this]); } /** @@ -2614,802 +2646,118 @@ export class BooleanExpr extends FirestoreFunction { * * @return A new {@code Expr} representing the negated filter condition. */ - not(filter: BooleanExpr): BooleanExpr { - return new Not(filter); + not(): BooleanExpr { + return new BooleanExpr('not', [this]); } } /** * @beta + * Creates an aggregation that counts the number of stage inputs where the provided + * boolean expression evaluates to true. + * + * ```typescript + * // Count the number of documents where 'is_active' field equals true + * countif(Field.of("is_active").eq(true)).as("numActiveDocuments"); + * ``` + * + * @param booleanExpr - The boolean expression to evaluate on each input. + * @returns A new `AggregateFunction` representing the 'countif' aggregation. */ -export class Add extends FirestoreFunction { - constructor(left: ScalarExpr, others: ScalarExpr[]) { - super('add', [left, ...others]); - } +export function countIf(booleanExpr: BooleanExpr): AggregateFunction { + return booleanExpr.countIf(); } /** * @beta + * Creates an expression that return a pseudo-random value of type double in the + * range of [0, 1), inclusive of 0 and exclusive of 1. + * + * @returns A new `Expr` representing the 'rand' function. */ -export class Subtract extends FirestoreFunction { - constructor(private left: ScalarExpr, private right: ScalarExpr) { - super('subtract', [left, right]); - } +export function rand(): FirestoreFunction { + return new FirestoreFunction('rand', []); } /** * @beta + * + * Creates an expression that applies a bitwise AND operation between a field and a constant. + * + * ```typescript + * // Calculate the bitwise AND of 'field1' and 0xFF. + * bitAnd("field1", 0xFF); + * ``` + * + * @param field The left operand field name. + * @param otherBits A constant representing bits. + * @return A new {@code Expr} representing the bitwise AND operation. */ -export class Multiply extends FirestoreFunction { - constructor(left: ScalarExpr, others: ScalarExpr[]) { - super('multiply', [left, ...others]); - } -} - +export function bitAnd( + field: string, + otherBits: number | Bytes +): FirestoreFunction; /** * @beta + * + * Creates an expression that applies a bitwise AND operation between a field and an expression. + * + * ```typescript + * // Calculate the bitwise AND of 'field1' and 'field2'. + * bitAnd("field1", Field.of("field2")); + * ``` + * + * @param field The left operand field name. + * @param bitsExpression An expression that returns bits when evaluated. + * @return A new {@code Expr} representing the bitwise AND operation. */ -export class Divide extends FirestoreFunction { - constructor(private left: ScalarExpr, private right: ScalarExpr) { - super('divide', [left, right]); - } -} - +export function bitAnd( + field: string, + bitsExpression: ScalarExpr +): FirestoreFunction; /** * @beta + * + * Creates an expression that applies a bitwise AND operation between an expression and a constant. + * + * ```typescript + * // Calculate the bitwise AND of 'field1' and 0xFF. + * bitAnd(Field.of("field1"), 0xFF); + * ``` + * + * @param bitsExpression An expression returning bits. + * @param otherBits A constant representing bits. + * @return A new {@code Expr} representing the bitwise AND operation. */ -export class Mod extends FirestoreFunction { - constructor(private left: ScalarExpr, private right: ScalarExpr) { - super('mod', [left, right]); - } -} - -export class MapFunction extends FirestoreFunction { - constructor(private elements: ScalarExpr[]) { - super('map', elements); - } -} - -export class ArrayFunction extends FirestoreFunction { - constructor(private elements: ScalarExpr[]) { - super('array', elements); - } -} - +export function bitAnd( + bitsExpression: ScalarExpr, + otherBits: number | Bytes +): FirestoreFunction; /** * @beta + * + * Creates an expression that applies a bitwise AND operation between two expressions. + * + * ```typescript + * // Calculate the bitwise AND of 'field1' and 'field2'. + * bitAnd(Field.of("field1"), Field.of("field2")); + * ``` + * + * @param bitsExpression An expression that returns bits when evaluated. + * @param otherBitsExpression An expression that returns bits when evaluated. + * @return A new {@code Expr} representing the bitwise AND operation. */ -export class Eq extends BooleanExpr { - constructor(private left: ScalarExpr, private right: ScalarExpr) { - super('eq', [left, right]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class Neq extends BooleanExpr { - constructor(private left: ScalarExpr, private right: ScalarExpr) { - super('neq', [left, right]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class Lt extends BooleanExpr { - constructor(private left: ScalarExpr, private right: ScalarExpr) { - super('lt', [left, right]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class Lte extends BooleanExpr { - constructor(private left: ScalarExpr, private right: ScalarExpr) { - super('lte', [left, right]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class Gt extends BooleanExpr { - constructor(private left: ScalarExpr, private right: ScalarExpr) { - super('gt', [left, right]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class Gte extends BooleanExpr { - constructor(private left: ScalarExpr, private right: ScalarExpr) { - super('gte', [left, right]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class ArrayConcat extends FirestoreFunction { - constructor(array: ScalarExpr, elements: ScalarExpr[]) { - super('array_concat', [array, ...elements]); - } -} - -/** - * @beta - */ -export class ArrayReverse extends FirestoreFunction { - constructor(private array: ScalarExpr) { - super('array_reverse', [array]); - } -} - -/** - * @beta - */ -export class ArrayContains extends BooleanExpr { - constructor(private array: ScalarExpr, private element: ScalarExpr) { - super('array_contains', [array, element]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class ArrayContainsAll extends BooleanExpr { - constructor(private array: ScalarExpr, private values: ScalarExpr[]) { - super('array_contains_all', [array, new ListOfExprs(values)]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class ArrayContainsAny extends BooleanExpr { - constructor(private array: ScalarExpr, private values: ScalarExpr[]) { - super('array_contains_any', [array, new ListOfExprs(values)]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class ArrayLength extends FirestoreFunction { - constructor(private array: ScalarExpr) { - super('array_length', [array]); - } -} - -/** - * @beta - */ -export class ArrayElement extends FirestoreFunction { - constructor() { - super('array_element', []); - } -} - -/** - * @beta - */ -export class EqAny extends BooleanExpr { - constructor(private left: ScalarExpr, private others: ScalarExpr[]) { - super('eq_any', [left, new ListOfExprs(others)]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class NotEqAny extends BooleanExpr { - constructor(private left: ScalarExpr, private others: ScalarExpr[]) { - super('not_eq_any', [left, new ListOfExprs(others)]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class IsNan extends BooleanExpr { - constructor(private expr: ScalarExpr) { - super('is_nan', [expr]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class Exists extends BooleanExpr { - constructor(private expr: ScalarExpr) { - super('exists', [expr]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class Not extends BooleanExpr { - constructor(private expr: ScalarExpr) { - super('not', [expr]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class And extends BooleanExpr { - constructor(private conditions: BooleanExpr[]) { - super('and', conditions); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class Or extends BooleanExpr { - constructor(private conditions: BooleanExpr[]) { - super('or', conditions); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class Xor extends BooleanExpr { - constructor(private conditions: BooleanExpr[]) { - super('xor', conditions); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class Cond extends FirestoreFunction { - constructor( - private condition: BooleanExpr, - private thenExpr: ScalarExpr, - private elseExpr: ScalarExpr - ) { - super('cond', [condition, thenExpr, elseExpr]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class LogicalMaximum extends FirestoreFunction { - constructor(first: ScalarExpr, others: ScalarExpr[]) { - super('logical_maximum', [first, ...others]); - } -} - -/** - * @beta - */ -export class LogicalMinimum extends FirestoreFunction { - constructor(first: ScalarExpr, others: ScalarExpr[]) { - super('logical_min', [first, ...others]); - } -} - -/** - * @beta - */ -export class Reverse extends FirestoreFunction { - constructor(private value: ScalarExpr) { - super('reverse', [value]); - } -} - -/** - * @beta - */ -export class ReplaceFirst extends FirestoreFunction { - constructor( - private value: ScalarExpr, - private find: ScalarExpr, - private replace: ScalarExpr - ) { - super('replace_first', [value, find, replace]); - } -} - -/** - * @beta - */ -export class ReplaceAll extends FirestoreFunction { - constructor( - private value: ScalarExpr, - private find: ScalarExpr, - private replace: ScalarExpr - ) { - super('replace_all', [value, find, replace]); - } -} - -/** - * @beta - */ -export class CharLength extends FirestoreFunction { - constructor(private value: ScalarExpr) { - super('char_length', [value]); - } -} - -/** - * @beta - */ -export class ByteLength extends FirestoreFunction { - constructor(private value: ScalarExpr) { - super('byte_length', [value]); - } -} - -/** - * @beta - */ -export class Like extends BooleanExpr { - constructor(private expr: ScalarExpr, private pattern: ScalarExpr) { - super('like', [expr, pattern]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class RegexContains extends BooleanExpr { - constructor(private expr: ScalarExpr, private pattern: ScalarExpr) { - super('regex_contains', [expr, pattern]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class RegexMatch extends BooleanExpr { - constructor(private expr: ScalarExpr, private pattern: ScalarExpr) { - super('regex_match', [expr, pattern]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class StrContains extends BooleanExpr { - constructor(private expr: ScalarExpr, private substring: ScalarExpr) { - super('str_contains', [expr, substring]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class StartsWith extends BooleanExpr { - constructor(private expr: ScalarExpr, private prefix: ScalarExpr) { - super('starts_with', [expr, prefix]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class EndsWith extends BooleanExpr { - constructor(private expr: ScalarExpr, private suffix: ScalarExpr) { - super('ends_with', [expr, suffix]); - } - - filterable = true as const; -} - -/** - * @beta - */ -export class ToLower extends FirestoreFunction { - constructor(private expr: ScalarExpr) { - super('to_lower', [expr]); - } -} - -/** - * @beta - */ -export class ToUpper extends FirestoreFunction { - constructor(private expr: ScalarExpr) { - super('to_upper', [expr]); - } -} - -/** - * @beta - */ -export class Trim extends FirestoreFunction { - constructor(private expr: ScalarExpr) { - super('trim', [expr]); - } -} - -/** - * @beta - */ -export class StrConcat extends FirestoreFunction { - constructor(private first: ScalarExpr, private rest: ScalarExpr[]) { - super('str_concat', [first, ...rest]); - } -} - -/** - * @beta - */ -export class MapGet extends FirestoreFunction { - constructor(map: ScalarExpr, name: string) { - super('map_get', [map, Constant.of(name)]); - } -} - -/** - * @beta - */ -export class Count extends AggregateFunction { - aggregateFunction = true as const; - - constructor( - private value: ScalarExpr | undefined, - private distinct: boolean - ) { - super('count', value === undefined ? [] : [value]); - } -} - -/** - * @beta - */ -export class Sum extends AggregateFunction { - aggregateFunction = true as const; - - constructor(private value: ScalarExpr, private distinct: boolean) { - super('sum', [value]); - } -} - -/** - * @beta - */ -export class Avg extends AggregateFunction { - aggregateFunction = true as const; - - constructor(private value: ScalarExpr, private distinct: boolean) { - super('avg', [value]); - } -} - -/** - * @beta - */ -export class Minimum extends AggregateFunction { - aggregateFunction = true as const; - - constructor(private value: ScalarExpr, private distinct: boolean) { - super('minimum', [value]); - } -} - -/** - * @beta - */ -export class Maximum extends AggregateFunction { - aggregateFunction = true as const; - - constructor(private value: ScalarExpr, private distinct: boolean) { - super('maximum', [value]); - } -} - -/** - * @beta - */ -export class CosineDistance extends FirestoreFunction { - constructor(private vector1: ScalarExpr, private vector2: ScalarExpr) { - super('cosine_distance', [vector1, vector2]); - } -} - -/** - * @beta - */ -export class DotProduct extends FirestoreFunction { - constructor(private vector1: ScalarExpr, private vector2: ScalarExpr) { - super('dot_product', [vector1, vector2]); - } -} - -/** - * @beta - */ -export class EuclideanDistance extends FirestoreFunction { - constructor(private vector1: ScalarExpr, private vector2: ScalarExpr) { - super('euclidean_distance', [vector1, vector2]); - } -} - -/** - * @beta - */ -export class VectorLength extends FirestoreFunction { - constructor(private value: ScalarExpr) { - super('vector_length', [value]); - } -} - -/** - * @beta - */ -export class UnixMicrosToTimestamp extends FirestoreFunction { - constructor(private input: ScalarExpr) { - super('unix_micros_to_timestamp', [input]); - } -} - -/** - * @beta - */ -export class TimestampToUnixMicros extends FirestoreFunction { - constructor(private input: ScalarExpr) { - super('timestamp_to_unix_micros', [input]); - } -} - -/** - * @beta - */ -export class UnixMillisToTimestamp extends FirestoreFunction { - constructor(private input: ScalarExpr) { - super('unix_millis_to_timestamp', [input]); - } -} - -/** - * @beta - */ -export class TimestampToUnixMillis extends FirestoreFunction { - constructor(private input: ScalarExpr) { - super('timestamp_to_unix_millis', [input]); - } -} - -/** - * @beta - */ -export class UnixSecondsToTimestamp extends FirestoreFunction { - constructor(private input: ScalarExpr) { - super('unix_seconds_to_timestamp', [input]); - } -} - -/** - * @beta - */ -export class TimestampToUnixSeconds extends FirestoreFunction { - constructor(private input: ScalarExpr) { - super('timestamp_to_unix_seconds', [input]); - } -} - -/** - * @beta - */ -export class TimestampAdd extends FirestoreFunction { - constructor( - private timestamp: ScalarExpr, - private unit: ScalarExpr, - private amount: ScalarExpr - ) { - super('timestamp_add', [timestamp, unit, amount]); - } -} - -/** - * @beta - */ -export class TimestampSub extends FirestoreFunction { - constructor( - private timestamp: ScalarExpr, - private unit: ScalarExpr, - private amount: ScalarExpr - ) { - super('timestamp_sub', [timestamp, unit, amount]); - } -} - -/** - * @beta - */ -export class CountIf extends AggregateFunction { - constructor(private booleanExpr: BooleanExpr) { - super('count_if', [booleanExpr]); - } - - aggregateFunction = true as const; -} - -/** - * @beta - * Creates an aggregation that counts the number of stage inputs where the provided - * boolean expression evaluates to true. - * - * ```typescript - * // Count the number of documents where 'is_active' field equals true - * countif(Field.of("is_active").eq(true)).as("numActiveDocuments"); - * ``` - * - * @param booleanExpr - The boolean expression to evaluate on each input. - * @returns A new `AggregateFunction` representing the 'countif' aggregation. - */ -export function countIf(booleanExpr: BooleanExpr): CountIf { - return new CountIf(booleanExpr); -} - -/** - * @beta - */ -export class Rand extends FirestoreFunction { - constructor() { - super('rand', []); - } -} - -/** - * @beta - * Creates an expression that return a pseudo-random value of type double in the - * range of [0, 1), inclusive of 0 and exclusive of 1. - * - * @returns A new `Expr` representing the 'rand' function. - */ -export function rand(): Rand { - return new Rand(); -} - -/** - * @beta - */ -export class BitAnd extends FirestoreFunction { - constructor(private left: ScalarExpr, private right: ScalarExpr) { - super('bit_and', [left, right]); - } -} - -/** - * @beta - * - * Creates an expression that applies a bitwise AND operation between a field and a constant. - * - * ```typescript - * // Calculate the bitwise AND of 'field1' and 0xFF. - * bitAnd("field1", 0xFF); - * ``` - * - * @param field The left operand field name. - * @param otherBits A constant representing bits. - * @return A new {@code Expr} representing the bitwise AND operation. - */ -export function bitAnd(field: string, otherBits: number | Bytes): BitAnd; -/** - * @beta - * - * Creates an expression that applies a bitwise AND operation between a field and an expression. - * - * ```typescript - * // Calculate the bitwise AND of 'field1' and 'field2'. - * bitAnd("field1", Field.of("field2")); - * ``` - * - * @param field The left operand field name. - * @param bitsExpression An expression that returns bits when evaluated. - * @return A new {@code Expr} representing the bitwise AND operation. - */ -export function bitAnd(field: string, bitsExpression: ScalarExpr): BitAnd; -/** - * @beta - * - * Creates an expression that applies a bitwise AND operation between an expression and a constant. - * - * ```typescript - * // Calculate the bitwise AND of 'field1' and 0xFF. - * bitAnd(Field.of("field1"), 0xFF); - * ``` - * - * @param bitsExpression An expression returning bits. - * @param otherBits A constant representing bits. - * @return A new {@code Expr} representing the bitwise AND operation. - */ -export function bitAnd( - bitsExpression: ScalarExpr, - otherBits: number | Bytes -): BitAnd; -/** - * @beta - * - * Creates an expression that applies a bitwise AND operation between two expressions. - * - * ```typescript - * // Calculate the bitwise AND of 'field1' and 'field2'. - * bitAnd(Field.of("field1"), Field.of("field2")); - * ``` - * - * @param bitsExpression An expression that returns bits when evaluated. - * @param otherBitsExpression An expression that returns bits when evaluated. - * @return A new {@code Expr} representing the bitwise AND operation. - */ -export function bitAnd( - bitsExpression: ScalarExpr, - otherBitsExpression: ScalarExpr -): BitAnd; -export function bitAnd( - fieldOrExpression: string | ScalarExpr, - bitsOrExpression: number | ScalarExpr | Bytes -): BitAnd { - return new BitAnd( - fieldOfOrExpr(fieldOrExpression), - valueToDefaultExpr(bitsOrExpression) - ); -} - -/** - * @beta - */ -export class BitOr extends FirestoreFunction { - constructor(private left: ScalarExpr, private right: ScalarExpr) { - super('bit_or', [left, right]); - } +export function bitAnd( + bitsExpression: ScalarExpr, + otherBitsExpression: ScalarExpr +): FirestoreFunction; +export function bitAnd( + fieldOrExpression: string | ScalarExpr, + bitsOrExpression: number | ScalarExpr | Bytes +): FirestoreFunction { + return fieldOfOrExpr(fieldOrExpression).bitAnd( + valueToDefaultExpr(bitsOrExpression) + ); } /** @@ -3426,7 +2774,10 @@ export class BitOr extends FirestoreFunction { * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise OR operation. */ -export function bitOr(field: string, otherBits: number | Bytes): BitOr; +export function bitOr( + field: string, + otherBits: number | Bytes +): FirestoreFunction; /** * @beta * @@ -3441,7 +2792,10 @@ export function bitOr(field: string, otherBits: number | Bytes): BitOr; * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise OR operation. */ -export function bitOr(field: string, bitsExpression: ScalarExpr): BitOr; +export function bitOr( + field: string, + bitsExpression: ScalarExpr +): FirestoreFunction; /** * @beta * @@ -3459,7 +2813,7 @@ export function bitOr(field: string, bitsExpression: ScalarExpr): BitOr; export function bitOr( bitsExpression: ScalarExpr, otherBits: number | Bytes -): BitOr; +): FirestoreFunction; /** * @beta * @@ -3477,26 +2831,16 @@ export function bitOr( export function bitOr( bitsExpression: ScalarExpr, otherBitsExpression: ScalarExpr -): BitOr; +): FirestoreFunction; export function bitOr( fieldOrExpression: string | ScalarExpr, bitsOrExpression: number | ScalarExpr | Bytes -): BitOr { - return new BitOr( - fieldOfOrExpr(fieldOrExpression), +): FirestoreFunction { + return fieldOfOrExpr(fieldOrExpression).bitOr( valueToDefaultExpr(bitsOrExpression) ); } -/** - * @beta - */ -export class BitXor extends FirestoreFunction { - constructor(private left: ScalarExpr, private right: ScalarExpr) { - super('bit_xor', [left, right]); - } -} - /** * @beta * @@ -3511,7 +2855,10 @@ export class BitXor extends FirestoreFunction { * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise XOR operation. */ -export function bitXor(field: string, otherBits: number | Bytes): BitXor; +export function bitXor( + field: string, + otherBits: number | Bytes +): FirestoreFunction; /** * @beta * @@ -3526,7 +2873,10 @@ export function bitXor(field: string, otherBits: number | Bytes): BitXor; * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise XOR operation. */ -export function bitXor(field: string, bitsExpression: ScalarExpr): BitXor; +export function bitXor( + field: string, + bitsExpression: ScalarExpr +): FirestoreFunction; /** * @beta * @@ -3544,7 +2894,7 @@ export function bitXor(field: string, bitsExpression: ScalarExpr): BitXor; export function bitXor( bitsExpression: ScalarExpr, otherBits: number | Bytes -): BitXor; +): FirestoreFunction; /** * @beta * @@ -3562,26 +2912,16 @@ export function bitXor( export function bitXor( bitsExpression: ScalarExpr, otherBitsExpression: ScalarExpr -): BitXor; +): FirestoreFunction; export function bitXor( fieldOrExpression: string | ScalarExpr, bitsOrExpression: number | ScalarExpr | Bytes -): BitXor { - return new BitXor( - fieldOfOrExpr(fieldOrExpression), +): FirestoreFunction { + return fieldOfOrExpr(fieldOrExpression).bitXor( valueToDefaultExpr(bitsOrExpression) ); } -/** - * @beta - */ -export class BitNot extends FirestoreFunction { - constructor(private value: ScalarExpr) { - super('bit_not', [value]); - } -} - /** * @beta * @@ -3595,7 +2935,7 @@ export class BitNot extends FirestoreFunction { * @param field The operand field name. * @return A new {@code Expr} representing the bitwise NOT operation. */ -export function bitNot(field: string): BitNot; +export function bitNot(field: string): FirestoreFunction; /** * @beta * @@ -3609,18 +2949,9 @@ export function bitNot(field: string): BitNot; * @param bitsValueExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise NOT operation. */ -export function bitNot(bitsValueExpression: ScalarExpr): BitNot; -export function bitNot(bits: string | ScalarExpr): BitNot { - return new BitNot(fieldOfOrExpr(bits)); -} - -/** - * @beta - */ -export class BitLeftShift extends FirestoreFunction { - constructor(value: ScalarExpr, y: ScalarExpr) { - super('bit_left_shift', [value, y]); - } +export function bitNot(bitsValueExpression: ScalarExpr): FirestoreFunction; +export function bitNot(bits: string | ScalarExpr): FirestoreFunction { + return fieldOfOrExpr(bits).bitNot(); } /** @@ -3637,7 +2968,7 @@ export class BitLeftShift extends FirestoreFunction { * @param y The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ -export function bitLeftShift(field: string, y: number): BitLeftShift; +export function bitLeftShift(field: string, y: number): FirestoreFunction; /** * @beta * @@ -3655,7 +2986,7 @@ export function bitLeftShift(field: string, y: number): BitLeftShift; export function bitLeftShift( field: string, numberExpr: ScalarExpr -): BitLeftShift; +): FirestoreFunction; /** * @beta * @@ -3670,7 +3001,7 @@ export function bitLeftShift( * @param y The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ -export function bitLeftShift(xValue: ScalarExpr, y: number): BitLeftShift; +export function bitLeftShift(xValue: ScalarExpr, y: number): FirestoreFunction; /** * @beta * @@ -3688,24 +3019,12 @@ export function bitLeftShift(xValue: ScalarExpr, y: number): BitLeftShift; export function bitLeftShift( xValue: ScalarExpr, numberExpr: ScalarExpr -): BitLeftShift; +): FirestoreFunction; export function bitLeftShift( xValue: string | ScalarExpr, numberExpr: number | ScalarExpr -): BitLeftShift { - return new BitLeftShift( - fieldOfOrExpr(xValue), - valueToDefaultExpr(numberExpr) - ); -} - -/** - * @beta - */ -export class BitRightShift extends FirestoreFunction { - constructor(value: ScalarExpr, y: ScalarExpr) { - super('bit_right_shift', [value, y]); - } +): FirestoreFunction { + return fieldOfOrExpr(xValue).bitLeftShift(valueToDefaultExpr(numberExpr)); } /** @@ -3722,7 +3041,7 @@ export class BitRightShift extends FirestoreFunction { * @param right The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ -export function bitRightShift(field: string, y: number): BitRightShift; +export function bitRightShift(field: string, y: number): FirestoreFunction; /** * @beta * @@ -3740,7 +3059,7 @@ export function bitRightShift(field: string, y: number): BitRightShift; export function bitRightShift( field: string, numberExpr: ScalarExpr -): BitRightShift; +): FirestoreFunction; /** * @beta * @@ -3755,7 +3074,7 @@ export function bitRightShift( * @param y The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ -export function bitRightShift(xValue: ScalarExpr, y: number): BitRightShift; +export function bitRightShift(xValue: ScalarExpr, y: number): FirestoreFunction; /** * @beta * @@ -3773,24 +3092,12 @@ export function bitRightShift(xValue: ScalarExpr, y: number): BitRightShift; export function bitRightShift( xValue: ScalarExpr, numberExpr: ScalarExpr -): BitRightShift; +): FirestoreFunction; export function bitRightShift( xValue: string | ScalarExpr, numberExpr: number | ScalarExpr -): BitRightShift { - return new BitRightShift( - fieldOfOrExpr(xValue), - valueToDefaultExpr(numberExpr) - ); -} - -/** - * @beta - */ -export class ArrayOffset extends FirestoreFunction { - constructor(private arrayExpression: ScalarExpr, private offset: ScalarExpr) { - super('array_offset', [arrayExpression, offset]); - } +): FirestoreFunction { + return fieldOfOrExpr(xValue).bitRightShift(valueToDefaultExpr(numberExpr)); } /** @@ -3808,7 +3115,10 @@ export class ArrayOffset extends FirestoreFunction { * @param offset The index of the element to return. * @return A new Expr representing the 'arrayOffset' operation. */ -export function arrayOffset(arrayField: string, offset: number): ArrayOffset; +export function arrayOffset( + arrayField: string, + offset: number +): FirestoreFunction; /** * @beta @@ -3829,7 +3139,7 @@ export function arrayOffset(arrayField: string, offset: number): ArrayOffset; export function arrayOffset( arrayField: string, offsetExpr: ScalarExpr -): ArrayOffset; +): FirestoreFunction; /** * @beta @@ -3849,7 +3159,7 @@ export function arrayOffset( export function arrayOffset( arrayExpression: ScalarExpr, offset: number -): ArrayOffset; +): FirestoreFunction; /** * @beta @@ -3870,21 +3180,12 @@ export function arrayOffset( export function arrayOffset( arrayExpression: ScalarExpr, offsetExpr: ScalarExpr -): ArrayOffset; +): FirestoreFunction; export function arrayOffset( array: ScalarExpr | string, offset: ScalarExpr | number -): ArrayOffset { - return new ArrayOffset(fieldOfOrExpr(array), valueToDefaultExpr(offset)); -} - -/** - * @beta - */ -export class CurrentContext extends FirestoreFunction { - constructor() { - super('current_context', []); - } +): FirestoreFunction { + return fieldOfOrExpr(array).arrayOffset(valueToDefaultExpr(offset)); } /** @@ -3893,19 +3194,8 @@ export class CurrentContext extends FirestoreFunction { * * @return A new {@code Expr} representing the 'current_context' function. */ -export function currentContext(): CurrentContext { - return new CurrentContext(); -} - -/** - * @beta - */ -export class IsError extends BooleanExpr { - constructor(private expr: ScalarExpr) { - super('is_error', [expr]); - } - - filterable = true as const; +export function currentContext(): FirestoreFunction { + return new FirestoreFunction('current_context', []); } /** @@ -3921,17 +3211,8 @@ export class IsError extends BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isError' check. */ -export function isError(value: ScalarExpr): IsError { - return new IsError(value); -} - -/** - * @beta - */ -export class IfError extends FirestoreFunction { - constructor(private tryExpr: ScalarExpr, private catchExpr: ScalarExpr) { - super('if_error', [tryExpr, catchExpr]); - } +export function isError(value: ScalarExpr): BooleanExpr { + return value.isError(); } /** @@ -3951,7 +3232,10 @@ export class IfError extends FirestoreFunction { * returned if the tryExpr produces an error. * @return A new {@code Expr} representing the 'ifError' operation. */ -export function ifError(tryExpr: ScalarExpr, catchExpr: ScalarExpr): IfError; +export function ifError( + tryExpr: ScalarExpr, + catchExpr: ScalarExpr +): FirestoreFunction; /** * @beta @@ -3970,20 +3254,15 @@ export function ifError(tryExpr: ScalarExpr, catchExpr: ScalarExpr): IfError; * error. * @return A new {@code Expr} representing the 'ifError' operation. */ -export function ifError(tryExpr: ScalarExpr, catchValue: any): IfError; -export function ifError(tryExpr: ScalarExpr, catchValue: any): IfError { - return new IfError(tryExpr, valueToDefaultExpr(catchValue)); -} - -/** - * @beta - */ -export class IsAbsent extends BooleanExpr { - constructor(private expr: ScalarExpr) { - super('is_absent', [expr]); - } - - filterable = true as const; +export function ifError( + tryExpr: ScalarExpr, + catchValue: any +): FirestoreFunction; +export function ifError( + tryExpr: ScalarExpr, + catchValue: any +): FirestoreFunction { + return tryExpr.ifError(valueToDefaultExpr(catchValue)); } /** @@ -4000,7 +3279,7 @@ export class IsAbsent extends BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isAbsent' check. */ -export function isAbsent(value: ScalarExpr): IsAbsent; +export function isAbsent(value: ScalarExpr): BooleanExpr; /** * @beta @@ -4016,20 +3295,9 @@ export function isAbsent(value: ScalarExpr): IsAbsent; * @param field The field to check. * @return A new {@code Expr} representing the 'isAbsent' check. */ -export function isAbsent(field: string): IsAbsent; -export function isAbsent(value: ScalarExpr | string): IsAbsent { - return new IsAbsent(fieldOfOrExpr(value)); -} - -/** - * @beta - */ -export class IsNull extends BooleanExpr { - constructor(private expr: ScalarExpr) { - super('is_null', [expr]); - } - - filterable = true as const; +export function isAbsent(field: string): BooleanExpr; +export function isAbsent(value: ScalarExpr | string): BooleanExpr { + return fieldOfOrExpr(value).isAbsent(); } /** @@ -4045,7 +3313,7 @@ export class IsNull extends BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNull(value: ScalarExpr): IsNull; +export function isNull(value: ScalarExpr): BooleanExpr; /** * @beta @@ -4060,20 +3328,9 @@ export function isNull(value: ScalarExpr): IsNull; * @param value The name of the field to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNull(value: string): IsNull; -export function isNull(value: ScalarExpr | string): IsNull { - return new IsNull(fieldOfOrExpr(value)); -} - -/** - * @beta - */ -export class IsNotNull extends BooleanExpr { - constructor(private expr: ScalarExpr) { - super('is_not_null', [expr]); - } - - filterable = true as const; +export function isNull(value: string): BooleanExpr; +export function isNull(value: ScalarExpr | string): BooleanExpr { + return fieldOfOrExpr(value).isNull(); } /** @@ -4089,7 +3346,7 @@ export class IsNotNull extends BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNotNull(value: ScalarExpr): IsNotNull; +export function isNotNull(value: ScalarExpr): BooleanExpr; /** * @beta @@ -4104,20 +3361,9 @@ export function isNotNull(value: ScalarExpr): IsNotNull; * @param value The name of the field to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNotNull(value: string): IsNotNull; -export function isNotNull(value: ScalarExpr | string): IsNotNull { - return new IsNotNull(fieldOfOrExpr(value)); -} - -/** - * @beta - */ -export class IsNotNan extends BooleanExpr { - constructor(private expr: ScalarExpr) { - super('is_not_nan', [expr]); - } - - filterable = true as const; +export function isNotNull(value: string): BooleanExpr; +export function isNotNull(value: ScalarExpr | string): BooleanExpr { + return fieldOfOrExpr(value).isNotNull(); } /** @@ -4133,7 +3379,7 @@ export class IsNotNan extends BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isNotNaN' check. */ -export function isNotNan(value: ScalarExpr): IsNotNan; +export function isNotNan(value: ScalarExpr): BooleanExpr; /** * @beta @@ -4148,19 +3394,11 @@ export function isNotNan(value: ScalarExpr): IsNotNan; * @param value The name of the field to check. * @return A new {@code Expr} representing the 'isNotNaN' check. */ -export function isNotNan(value: string): IsNotNan; -export function isNotNan(value: ScalarExpr | string): IsNotNan { - return new IsNotNan(fieldOfOrExpr(value)); +export function isNotNan(value: string): BooleanExpr; +export function isNotNan(value: ScalarExpr | string): BooleanExpr { + return fieldOfOrExpr(value).isNotNan(); } -/** - * @beta - */ -export class MapRemove extends FirestoreFunction { - constructor(map: ScalarExpr, nameExpr: ScalarExpr) { - super('map_remove', [map, nameExpr]); - } -} /** * @beta * @@ -4174,7 +3412,7 @@ export class MapRemove extends FirestoreFunction { * @param mapField The name of a field containing a map value. * @param key The name of the key to remove from the input map. */ -export function mapRemove(mapField: string, key: string): MapRemove; +export function mapRemove(mapField: string, key: string): FirestoreFunction; /** * @beta * @@ -4188,7 +3426,7 @@ export function mapRemove(mapField: string, key: string): MapRemove; * @param mapExpr An expression return a map value. * @param key The name of the key to remove from the input map. */ -export function mapRemove(mapExpr: ScalarExpr, key: string): MapRemove; +export function mapRemove(mapExpr: ScalarExpr, key: string): FirestoreFunction; /** * @beta * @@ -4202,7 +3440,10 @@ export function mapRemove(mapExpr: ScalarExpr, key: string): MapRemove; * @param mapField The name of a field containing a map value. * @param keyExpr An expression that produces the name of the key to remove from the input map. */ -export function mapRemove(mapField: string, keyExpr: ScalarExpr): MapRemove; +export function mapRemove( + mapField: string, + keyExpr: ScalarExpr +): FirestoreFunction; /** * @beta * @@ -4216,22 +3457,16 @@ export function mapRemove(mapField: string, keyExpr: ScalarExpr): MapRemove; * @param mapExpr An expression return a map value. * @param keyExpr An expression that produces the name of the key to remove from the input map. */ -export function mapRemove(mapExpr: ScalarExpr, keyExpr: ScalarExpr): MapRemove; +export function mapRemove( + mapExpr: ScalarExpr, + keyExpr: ScalarExpr +): FirestoreFunction; export function mapRemove( mapExpr: ScalarExpr | string, stringExpr: ScalarExpr | string -): MapRemove { - return new MapRemove(fieldOfOrExpr(mapExpr), valueToDefaultExpr(stringExpr)); -} - -/** - * @beta - */ -export class MapMerge extends FirestoreFunction { - constructor(maps: ScalarExpr[]) { - super('map_merge', maps); - } +): FirestoreFunction { + return fieldOfOrExpr(mapExpr).mapRemove(valueToDefaultExpr(stringExpr)); } /** @@ -4255,7 +3490,7 @@ export function mapMerge( mapField: string, secondMap: Record | ScalarExpr, ...otherMaps: Array | ScalarExpr> -): MapMerge; +): FirestoreFunction; /** * @beta @@ -4278,71 +3513,16 @@ export function mapMerge( firstMap: Record | ScalarExpr, secondMap: Record | ScalarExpr, ...otherMaps: Array | ScalarExpr> -): MapMerge; +): FirestoreFunction; export function mapMerge( firstMap: string | Record | ScalarExpr, secondMap: Record | ScalarExpr, ...otherMaps: Array | ScalarExpr> -): MapMerge { - const firstMapExpr = - typeof firstMap === 'string' - ? Field.of(firstMap) - : valueToDefaultExpr(firstMap); +): FirestoreFunction { const secondMapExpr = valueToDefaultExpr(secondMap); const otherMapExprs = otherMaps.map(valueToDefaultExpr); - return new MapMerge([firstMapExpr, secondMapExpr, ...otherMapExprs]); -} - -/** - * @beta - */ -export class Parent extends FirestoreFunction { - constructor(pathExpr: ScalarExpr) { - super('parent', [pathExpr]); - } -} - -export function parentFunction(path: string | DocumentReference): Parent; - -export function parentFunction(pathExpr: ScalarExpr): Parent; - -export function parentFunction( - path: ScalarExpr | string | DocumentReference -): Parent { - // @ts-ignore - const pathExpr = valueToDefaultExpr(path); - return new Parent(pathExpr); -} - -/** - * @beta - */ -export class CollectionId extends FirestoreFunction { - constructor(pathExpr: ScalarExpr) { - super('collection_id', [pathExpr]); - } -} - -export function collectionId(path: string | DocumentReference): CollectionId; - -export function collectionId(pathExpr: ScalarExpr): CollectionId; - -export function collectionId( - path: ScalarExpr | string | DocumentReference -): CollectionId { - // @ts-ignore - const pathExpr = valueToDefaultExpr(path); - return new CollectionId(pathExpr); -} - -/** - * @beta - */ -export class DocumentId extends FirestoreFunction { - constructor(pathExpr: ScalarExpr) { - super('document_id', [pathExpr]); - } + return fieldOfOrExpr(firstMap).mapMerge(secondMapExpr, ...otherMapExprs); } /** @@ -4359,7 +3539,7 @@ export class DocumentId extends FirestoreFunction { */ export function documentIdFunction( documentPath: string | DocumentReference -): DocumentId; +): FirestoreFunction; /** * @beta @@ -4373,53 +3553,16 @@ export function documentIdFunction( * * @return A new {@code Expr} representing the documentId operation. */ -export function documentIdFunction(documentPathExpr: ScalarExpr): DocumentId; +export function documentIdFunction( + documentPathExpr: ScalarExpr +): FirestoreFunction; export function documentIdFunction( documentPath: ScalarExpr | string | DocumentReference -): DocumentId { +): FirestoreFunction { // @ts-ignore const documentPathExpr = valueToDefaultExpr(documentPath); - return new DocumentId(documentPathExpr); -} - -/** - * @beta - */ -export class Key extends FirestoreFunction { - constructor(namespaceExpr: ScalarExpr, pathExpr: ScalarExpr) { - super('key', [namespaceExpr, pathExpr]); - } -} - -export function key(namespace: string, path: string): Key; - -export function key(namespaceExpr: ScalarExpr, pathExpr: ScalarExpr): Key; - -export function key( - namespace: ScalarExpr | string, - path: ScalarExpr | string -): Key { - const namespaceExpr = valueToDefaultExpr(namespace); - const pathExpr = path instanceof ScalarExpr ? path : Constant.of(path); - return new Key(namespaceExpr, pathExpr); -} - -/** - * @beta - */ -export class Substr extends FirestoreFunction { - constructor( - inputExpr: ScalarExpr, - position: ScalarExpr, - length: ScalarExpr | undefined - ) { - if (length) { - super('substr', [inputExpr, position, length]); - } else { - super('substr', [inputExpr, position]); - } - } + return documentPathExpr.documentId(); } /** @@ -4435,7 +3578,7 @@ export function substr( field: string, position: number, length?: number -): Substr; +): FirestoreFunction; /** * @beta @@ -4450,7 +3593,7 @@ export function substr( input: ScalarExpr, position: number, length?: number -): Substr; +): FirestoreFunction; /** * @beta @@ -4461,169 +3604,37 @@ export function substr( * @param position An expression that returns the index of the first character of the substring. * @param length An expression that returns the length of the substring. */ -export function substr( - field: string, - position: ScalarExpr, - length?: ScalarExpr -): Substr; - -/** - * @beta - * - * Creates an expression that returns a substring of a string or byte array. - * - * @param input An expression returning a string or byte array to compute the substring from. - * @param position An expression that returns the index of the first character of the substring. - * @param length An expression that returns the length of the substring. - */ -export function substr( - input: ScalarExpr, - position: ScalarExpr, - length?: ScalarExpr -): Substr; - -export function substr( - field: ScalarExpr | string, - position: ScalarExpr | number, - length?: ScalarExpr | number -): Substr { - const fieldExpr = fieldOfOrExpr(field); - const positionExpr = valueToDefaultExpr(position); - const lengthExpr = - length === undefined ? undefined : valueToDefaultExpr(length); - return new Substr(fieldExpr, positionExpr, lengthExpr); -} - -/** - * @beta - */ -export class ManhattanDistance extends FirestoreFunction { - constructor(vector1: ScalarExpr, vector2: ScalarExpr) { - super('manhattan_distance', [vector1, vector2]); - } -} - -/** - * @beta - * - * Calculates the Manhattan distance between a field's vector value and a double array. - * - * ```typescript - * // Calculate the Manhattan distance between the 'location' field and a target location - * manhattanDistance("location", [37.7749, -122.4194]); - * ``` - * - * @param field The name of the field containing the first vector. - * @param other The other vector (as an array of doubles) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ -export function manhattanDistance( - field: string, - other: number[] -): ManhattanDistance; - -/** - * @beta - * - * Calculates the Manhattan distance between a field's vector value and a VectorValue. - * - * ```typescript - * // Calculate the Manhattan distance between the 'location' field and a target location - * manhattanDistance("location", new VectorValue([37.7749, -122.4194])); - * ``` - * - * @param expr The name of the field containing the first vector. - * @param other The other vector (as a VectorValue) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ -export function manhattanDistance( - expr: string, - other: VectorValue -): ManhattanDistance; - -/** - * @beta - * - * Calculates the Manhattan distance between a field's vector value and a vector expression. - * - * ```typescript - * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' - * manhattanDistance("pointA", Field.of("pointB")); - * ``` - * - * @param expr The name of the field containing the first vector. - * @param other The other vector (represented as an Expr) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ -export function manhattanDistance( - expr: string, - other: ScalarExpr -): ManhattanDistance; - -/** - * @beta - * - * Calculates the Manhattan distance between a vector expression and a double array. - * - * ```typescript - * // Calculate the Manhattan distance between the 'location' field and a target location - * - * manhattanDistance(Field.of("location"), [37.7749, -122.4194]); - * ``` - * - * @param expr The first vector (represented as an Expr) to compare against. - * @param other The other vector (as an array of doubles) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ -export function manhattanDistance( - expr: ScalarExpr, - other: number[] -): ManhattanDistance; - -/** - * @beta - * - * Calculates the Manhattan distance between a vector expression and a VectorValue. - * - * ```typescript - * // Calculate the Manhattan distance between the 'location' field and a target location - * manhattanDistance(Field.of("location"), new VectorValue([37.7749, -122.4194])); - * ``` - * - * @param expr The first vector (represented as an Expr) to compare against. - * @param other The other vector (as a VectorValue) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ -export function manhattanDistance( - expr: ScalarExpr, - other: VectorValue -): ManhattanDistance; +export function substr( + field: string, + position: ScalarExpr, + length?: ScalarExpr +): FirestoreFunction; /** * @beta * - * Calculates the Manhattan distance between two vector expressions. - * - * ```typescript - * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' - * manhattanDistance(Field.of("pointA"), Field.of("pointB")); - * ``` + * Creates an expression that returns a substring of a string or byte array. * - * @param expr The first vector (represented as an Expr) to compare against. - * @param other The other vector (represented as an Expr) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + * @param input An expression returning a string or byte array to compute the substring from. + * @param position An expression that returns the index of the first character of the substring. + * @param length An expression that returns the length of the substring. */ -export function manhattanDistance( - expr: ScalarExpr, - other: ScalarExpr -): ManhattanDistance; -export function manhattanDistance( - fieldOrExpr: ScalarExpr | string, - other: ScalarExpr | number[] | VectorValue -): ManhattanDistance { - const expr1 = fieldOfOrExpr(fieldOrExpr); - const expr2 = other instanceof ScalarExpr ? other : Constant.vector(other); - return new ManhattanDistance(expr1, expr2); +export function substr( + input: ScalarExpr, + position: ScalarExpr, + length?: ScalarExpr +): FirestoreFunction; + +export function substr( + field: ScalarExpr | string, + position: ScalarExpr | number, + length?: ScalarExpr | number +): FirestoreFunction { + const fieldExpr = fieldOfOrExpr(field); + const positionExpr = valueToDefaultExpr(position); + const lengthExpr = + length === undefined ? undefined : valueToDefaultExpr(length); + return fieldExpr.substr(positionExpr, lengthExpr); } /** @@ -4645,7 +3656,7 @@ export function add( first: ScalarExpr, second: ScalarExpr | any, ...others: Array -): Add; +): FirestoreFunction; /** * @beta @@ -4666,15 +3677,17 @@ export function add( fieldName: string, second: ScalarExpr | any, ...others: Array -): Add; +): FirestoreFunction; export function add( first: ScalarExpr | string, + second: ScalarExpr | any, ...others: Array -): Add { - const normalizedLeft = fieldOfOrExpr(first); - const normalizedRight = others.map(value => valueToDefaultExpr(value)); - return new Add(normalizedLeft, normalizedRight); +): FirestoreFunction { + return fieldOfOrExpr(first).add( + valueToDefaultExpr(second), + ...others.map(value => valueToDefaultExpr(value)) + ); } /** @@ -4691,7 +3704,10 @@ export function add( * @param right The expression to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: ScalarExpr, right: ScalarExpr): Subtract; +export function subtract( + left: ScalarExpr, + right: ScalarExpr +): FirestoreFunction; /** * @beta @@ -4707,7 +3723,7 @@ export function subtract(left: ScalarExpr, right: ScalarExpr): Subtract; * @param right The constant value to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: ScalarExpr, right: any): Subtract; +export function subtract(left: ScalarExpr, right: any): FirestoreFunction; /** * @beta @@ -4723,7 +3739,7 @@ export function subtract(left: ScalarExpr, right: any): Subtract; * @param right The expression to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: string, right: ScalarExpr): Subtract; +export function subtract(left: string, right: ScalarExpr): FirestoreFunction; /** * @beta @@ -4739,15 +3755,14 @@ export function subtract(left: string, right: ScalarExpr): Subtract; * @param right The constant value to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: string, right: any): Subtract; +export function subtract(left: string, right: any): FirestoreFunction; export function subtract( left: ScalarExpr | string, right: ScalarExpr | any -): Subtract { +): FirestoreFunction { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = - right instanceof ScalarExpr ? right : valueToDefaultExpr(right); - return new Subtract(normalizedLeft, normalizedRight); + const normalizedRight = valueToDefaultExpr(right); + return normalizedLeft.subtract(normalizedRight); } /** @@ -4769,7 +3784,7 @@ export function multiply( first: ScalarExpr, second: ScalarExpr | any, ...others: Array -): Multiply; +): FirestoreFunction; /** * @beta @@ -4790,15 +3805,17 @@ export function multiply( fieldName: string, second: ScalarExpr | any, ...others: Array -): Multiply; +): FirestoreFunction; export function multiply( - left: ScalarExpr | string, + first: ScalarExpr | string, + second: ScalarExpr | any, ...others: Array -): Multiply { - const normalizedLeft = fieldOfOrExpr(left); - const normalizedRight = others.map(value => valueToDefaultExpr(value)); - return new Multiply(normalizedLeft, normalizedRight); +): FirestoreFunction { + return fieldOfOrExpr(first).multiply( + valueToDefaultExpr(second), + ...others.map(valueToDefaultExpr) + ); } /** @@ -4815,7 +3832,7 @@ export function multiply( * @param right The expression to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: ScalarExpr, right: ScalarExpr): Divide; +export function divide(left: ScalarExpr, right: ScalarExpr): FirestoreFunction; /** * @beta @@ -4831,7 +3848,7 @@ export function divide(left: ScalarExpr, right: ScalarExpr): Divide; * @param right The constant value to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: ScalarExpr, right: any): Divide; +export function divide(left: ScalarExpr, right: any): FirestoreFunction; /** * @beta @@ -4847,7 +3864,7 @@ export function divide(left: ScalarExpr, right: any): Divide; * @param right The expression to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: string, right: ScalarExpr): Divide; +export function divide(left: string, right: ScalarExpr): FirestoreFunction; /** * @beta @@ -4863,15 +3880,14 @@ export function divide(left: string, right: ScalarExpr): Divide; * @param right The constant value to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: string, right: any): Divide; +export function divide(left: string, right: any): FirestoreFunction; export function divide( left: ScalarExpr | string, right: ScalarExpr | any -): Divide { +): FirestoreFunction { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = - right instanceof ScalarExpr ? right : valueToDefaultExpr(right); - return new Divide(normalizedLeft, normalizedRight); + const normalizedRight = valueToDefaultExpr(right); + return normalizedLeft.divide(normalizedRight); } /** @@ -4888,7 +3904,7 @@ export function divide( * @param right The divisor expression. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: ScalarExpr, right: ScalarExpr): Mod; +export function mod(left: ScalarExpr, right: ScalarExpr): FirestoreFunction; /** * @beta @@ -4904,7 +3920,7 @@ export function mod(left: ScalarExpr, right: ScalarExpr): Mod; * @param right The divisor constant. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: ScalarExpr, right: any): Mod; +export function mod(left: ScalarExpr, right: any): FirestoreFunction; /** * @beta @@ -4920,7 +3936,7 @@ export function mod(left: ScalarExpr, right: any): Mod; * @param right The divisor expression. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: string, right: ScalarExpr): Mod; +export function mod(left: string, right: ScalarExpr): FirestoreFunction; /** * @beta @@ -4936,15 +3952,17 @@ export function mod(left: string, right: ScalarExpr): Mod; * @param right The divisor constant. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: string, right: any): Mod; -export function mod(left: ScalarExpr | string, right: ScalarExpr | any): Mod { +export function mod(left: string, right: any): FirestoreFunction; +export function mod( + left: ScalarExpr | string, + right: ScalarExpr | any +): FirestoreFunction { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; - const normalizedRight = - right instanceof ScalarExpr ? right : valueToDefaultExpr(right); - return new Mod(normalizedLeft, normalizedRight); + const normalizedRight = valueToDefaultExpr(right); + return normalizedLeft.mod(normalizedRight); } -export function map(elements: Record): MapFunction { +export function map(elements: Record): FirestoreFunction { const result: any[] = []; for (const key in elements) { if (Object.prototype.hasOwnProperty.call(elements, key)) { @@ -4953,7 +3971,7 @@ export function map(elements: Record): MapFunction { result.push(valueToDefaultExpr(value)); } } - return new MapFunction(result); + return new FirestoreFunction('map', result); } /** @@ -4978,398 +3996,13 @@ export function _mapValue(plainObject: Record): MapValue { return new MapValue(result); } -export function array(elements: any[]): ArrayFunction { - return new ArrayFunction( +export function array(elements: any[]): FirestoreFunction { + return new FirestoreFunction( + 'array', elements.map(element => valueToDefaultExpr(element)) ); } -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise AND operation between two expressions. -// * -// * ```typescript -// * // Calculate the bitwise AND of 'field1' and 'field2'. -// * bitAnd(Field.of("field1"), Field.of("field2")); -// * ``` -// * -// * @param left The left operand expression. -// * @param right The right operand expression. -// * @return A new {@code Expr} representing the bitwise AND operation. -// */ -// export function bitAnd(left: Expr, right: Expr): BitAnd; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise AND operation between an expression and a constant. -// * -// * ```typescript -// * // Calculate the bitwise AND of 'field1' and 0xFF. -// * bitAnd(Field.of("field1"), 0xFF); -// * ``` -// * -// * @param left The left operand expression. -// * @param right The right operand constant. -// * @return A new {@code Expr} representing the bitwise AND operation. -// */ -// export function bitAnd(left: Expr, right: any): BitAnd; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise AND operation between a field and an expression. -// * -// * ```typescript -// * // Calculate the bitwise AND of 'field1' and 'field2'. -// * bitAnd("field1", Field.of("field2")); -// * ``` -// * -// * @param left The left operand field name. -// * @param right The right operand expression. -// * @return A new {@code Expr} representing the bitwise AND operation. -// */ -// export function bitAnd(left: string, right: Expr): BitAnd; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise AND operation between a field and a constant. -// * -// * ```typescript -// * // Calculate the bitwise AND of 'field1' and 0xFF. -// * bitAnd("field1", 0xFF); -// * ``` -// * -// * @param left The left operand field name. -// * @param right The right operand constant. -// * @return A new {@code Expr} representing the bitwise AND operation. -// */ -// export function bitAnd(left: string, right: any): BitAnd; -// export function bitAnd(left: Expr | string, right: Expr | any): BitAnd { -// const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; -// const normalizedRight = right instanceof Expr ? right : valueToDefaultExpr(right); -// return new BitAnd(normalizedLeft, normalizedRight); -// } -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise OR operation between two expressions. -// * -// * ```typescript -// * // Calculate the bitwise OR of 'field1' and 'field2'. -// * bitOr(Field.of("field1"), Field.of("field2")); -// * ``` -// * -// * @param left The left operand expression. -// * @param right The right operand expression. -// * @return A new {@code Expr} representing the bitwise OR operation. -// */ -// export function bitOr(left: Expr, right: Expr): BitOr; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise OR operation between an expression and a constant. -// * -// * ```typescript -// * // Calculate the bitwise OR of 'field1' and 0xFF. -// * bitOr(Field.of("field1"), 0xFF); -// * ``` -// * -// * @param left The left operand expression. -// * @param right The right operand constant. -// * @return A new {@code Expr} representing the bitwise OR operation. -// */ -// export function bitOr(left: Expr, right: any): BitOr; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise OR operation between a field and an expression. -// * -// * ```typescript -// * // Calculate the bitwise OR of 'field1' and 'field2'. -// * bitOr("field1", Field.of("field2")); -// * ``` -// * -// * @param left The left operand field name. -// * @param right The right operand expression. -// * @return A new {@code Expr} representing the bitwise OR operation. -// */ -// export function bitOr(left: string, right: Expr): BitOr; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise OR operation between a field and a constant. -// * -// * ```typescript -// * // Calculate the bitwise OR of 'field1' and 0xFF. -// * bitOr("field1", 0xFF); -// * ``` -// * -// * @param left The left operand field name. -// * @param right The right operand constant. -// * @return A new {@code Expr} representing the bitwise OR operation. -// */ -// export function bitOr(left: string, right: any): BitOr; -// export function bitOr(left: Expr | string, right: Expr | any): BitOr { -// const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; -// const normalizedRight = right instanceof Expr ? right : valueToDefaultExpr(right); -// return new BitOr(normalizedLeft, normalizedRight); -// } -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise XOR operation between two expressions. -// * -// * ```typescript -// * // Calculate the bitwise XOR of 'field1' and 'field2'. -// * bitXor(Field.of("field1"), Field.of("field2")); -// * ``` -// * -// * @param left The left operand expression. -// * @param right The right operand expression. -// * @return A new {@code Expr} representing the bitwise XOR operation. -// */ -// export function bitXor(left: Expr, right: Expr): BitXor; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise XOR operation between an expression and a constant. -// * -// * ```typescript -// * // Calculate the bitwise XOR of 'field1' and 0xFF. -// * bitXor(Field.of("field1"), 0xFF); -// * ``` -// * -// * @param left The left operand expression. -// * @param right The right operand constant. -// * @return A new {@code Expr} representing the bitwise XOR operation. -// */ -// export function bitXor(left: Expr, right: any): BitXor; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise XOR operation between a field and an expression. -// * -// * ```typescript -// * // Calculate the bitwise XOR of 'field1' and 'field2'. -// * bitXor("field1", Field.of("field2")); -// * ``` -// * -// * @param left The left operand field name. -// * @param right The right operand expression. -// * @return A new {@code Expr} representing the bitwise XOR operation. -// */ -// export function bitXor(left: string, right: Expr): BitXor; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise XOR operation between a field and a constant. -// * -// * ```typescript -// * // Calculate the bitwise XOR of 'field1' and 0xFF. -// * bitXor("field1", 0xFF); -// * ``` -// * -// * @param left The left operand field name. -// * @param right The right operand constant. -// * @return A new {@code Expr} representing the bitwise XOR operation. -// */ -// export function bitXor(left: string, right: any): BitXor; -// export function bitXor(left: Expr | string, right: Expr | any): BitXor { -// const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; -// const normalizedRight = right instanceof Expr ? right : valueToDefaultExpr(right); -// return new BitXor(normalizedLeft, normalizedRight); -// } -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise NOT operation to an expression. -// * -// * ```typescript -// * // Calculate the bitwise NOT of 'field1'. -// * bitNot(Field.of("field1")); -// * ``` -// * -// * @param operand The operand expression. -// * @return A new {@code Expr} representing the bitwise NOT operation. -// */ -// export function bitNot(operand: Expr): BitNot; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise NOT operation to a field. -// * -// * ```typescript -// * // Calculate the bitwise NOT of 'field1'. -// * bitNot("field1"); -// * ``` -// * -// * @param operand The operand field name. -// * @return A new {@code Expr} representing the bitwise NOT operation. -// */ -// export function bitNot(operand: string): BitNot; -// export function bitNot(operand: Expr | string): BitNot { -// const normalizedOperand = -// typeof operand === 'string' ? Field.of(operand) : operand; -// return new BitNot(normalizedOperand); -// } -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise left shift operation between two expressions. -// * -// * ```typescript -// * // Calculate the bitwise left shift of 'field1' by 'field2' bits. -// * bitLeftShift(Field.of("field1"), Field.of("field2")); -// * ``` -// * -// * @param left The left operand expression. -// * @param right The right operand expression representing the number of bits to shift. -// * @return A new {@code Expr} representing the bitwise left shift operation. -// */ -// export function bitLeftShift(left: Expr, right: Expr): BitLeftShift; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise left shift operation between an expression and a constant. -// * -// * ```typescript -// * // Calculate the bitwise left shift of 'field1' by 2 bits. -// * bitLeftShift(Field.of("field1"), 2); -// * ``` -// * -// * @param left The left operand expression. -// * @param right The right operand constant representing the number of bits to shift. -// * @return A new {@code Expr} representing the bitwise left shift operation. -// */ -// export function bitLeftShift(left: Expr, right: any): BitLeftShift; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise left shift operation between a field and an expression. -// * -// * ```typescript -// * // Calculate the bitwise left shift of 'field1' by 'field2' bits. -// * bitLeftShift("field1", Field.of("field2")); -// * ``` -// * -// * @param left The left operand field name. -// * @param right The right operand expression representing the number of bits to shift. -// * @return A new {@code Expr} representing the bitwise left shift operation. -// */ -// export function bitLeftShift(left: string, right: Expr): BitLeftShift; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise left shift operation between a field and a constant. -// * -// * ```typescript -// * // Calculate the bitwise left shift of 'field1' by 2 bits. -// * bitLeftShift("field1", 2); -// * ``` -// * -// * @param left The left operand field name. -// * @param right The right operand constant representing the number of bits to shift. -// * @return A new {@code Expr} representing the bitwise left shift operation. -// */ -// export function bitLeftShift(left: string, right: any): BitLeftShift; -// export function bitLeftShift( -// left: Expr | string, -// right: Expr | any -// ): BitLeftShift { -// const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; -// const normalizedRight = right instanceof Expr ? right : valueToDefaultExpr(right); -// return new BitLeftShift(normalizedLeft, normalizedRight); -// } -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise right shift operation between two expressions. -// * -// * ```typescript -// * // Calculate the bitwise right shift of 'field1' by 'field2' bits. -// * bitRightShift(Field.of("field1"), Field.of("field2")); -// * ``` -// * -// * @param left The left operand expression. -// * @param right The right operand expression representing the number of bits to shift. -// * @return A new {@code Expr} representing the bitwise right shift operation. -// */ -// export function bitRightShift(left: Expr, right: Expr): BitRightShift; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise right shift operation between an expression and a constant. -// * -// * ```typescript -// * // Calculate the bitwise right shift of 'field1' by 2 bits. -// * bitRightShift(Field.of("field1"), 2); -// * ``` -// * -// * @param left The left operand expression. -// * @param right The right operand constant representing the number of bits to shift. -// * @return A new {@code Expr} representing the bitwise right shift operation. -// */ -// export function bitRightShift(left: Expr, right: any): BitRightShift; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise right shift operation between a field and an expression. -// * -// * ```typescript -// * // Calculate the bitwise right shift of 'field1' by 'field2' bits. -// * bitRightShift("field1", Field.of("field2")); -// * ``` -// * -// * @param left The left operand field name. -// * @param right The right operand expression representing the number of bits to shift. -// * @return A new {@code Expr} representing the bitwise right shift operation. -// */ -// export function bitRightShift(left: string, right: Expr): BitRightShift; -// -// /** -// * @beta -// * -// * Creates an expression that applies a bitwise right shift operation between a field and a constant. -// * -// * ```typescript -// * // Calculate the bitwise right shift of 'field1' by 2 bits. -// * bitRightShift("field1", 2); -// * ``` -// * -// * @param left The left operand field name. -// * @param right The right operand constant representing the number of bits to shift. -// * @return A new {@code Expr} representing the bitwise right shift operation. -// */ -// export function bitRightShift(left: string, right: any): BitRightShift; -// export function bitRightShift( -// left: Expr | string, -// right: Expr | any -// ): BitRightShift { -// const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; -// const normalizedRight = right instanceof Expr ? right : valueToDefaultExpr(right); -// return new BitRightShift(normalizedLeft, normalizedRight); -// } - /** * @beta * @@ -5384,7 +4017,7 @@ export function array(elements: any[]): ArrayFunction { * @param right The second expression to compare. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: ScalarExpr, right: ScalarExpr): Eq; +export function eq(left: ScalarExpr, right: ScalarExpr): BooleanExpr; /** * @beta @@ -5400,7 +4033,7 @@ export function eq(left: ScalarExpr, right: ScalarExpr): Eq; * @param right The constant value to compare to. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: ScalarExpr, right: any): Eq; +export function eq(left: ScalarExpr, right: any): BooleanExpr; /** * @beta @@ -5416,7 +4049,7 @@ export function eq(left: ScalarExpr, right: any): Eq; * @param right The expression to compare to. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: string, right: ScalarExpr): Eq; +export function eq(left: string, right: ScalarExpr): BooleanExpr; /** * @beta @@ -5432,12 +4065,11 @@ export function eq(left: string, right: ScalarExpr): Eq; * @param right The constant value to compare to. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: string, right: any): Eq; -export function eq(left: ScalarExpr | string, right: any): Eq { +export function eq(left: string, right: any): BooleanExpr; +export function eq(left: ScalarExpr | string, right: any): BooleanExpr { const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); - const rightExpr = - right instanceof ScalarExpr ? right : valueToDefaultExpr(right); - return new Eq(leftExpr, rightExpr); + const rightExpr = valueToDefaultExpr(right); + return leftExpr.eq(rightExpr); } /** @@ -5454,7 +4086,7 @@ export function eq(left: ScalarExpr | string, right: any): Eq { * @param right The second expression to compare. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: ScalarExpr, right: ScalarExpr): Neq; +export function neq(left: ScalarExpr, right: ScalarExpr): BooleanExpr; /** * @beta @@ -5470,7 +4102,7 @@ export function neq(left: ScalarExpr, right: ScalarExpr): Neq; * @param right The constant value to compare to. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: ScalarExpr, right: any): Neq; +export function neq(left: ScalarExpr, right: any): BooleanExpr; /** * @beta @@ -5486,7 +4118,7 @@ export function neq(left: ScalarExpr, right: any): Neq; * @param right The expression to compare to. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: string, right: ScalarExpr): Neq; +export function neq(left: string, right: ScalarExpr): BooleanExpr; /** * @beta @@ -5502,12 +4134,11 @@ export function neq(left: string, right: ScalarExpr): Neq; * @param right The constant value to compare to. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: string, right: any): Neq; -export function neq(left: ScalarExpr | string, right: any): Neq { +export function neq(left: string, right: any): BooleanExpr; +export function neq(left: ScalarExpr | string, right: any): BooleanExpr { const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); - const rightExpr = - right instanceof ScalarExpr ? right : valueToDefaultExpr(right); - return new Neq(leftExpr, rightExpr); + const rightExpr = valueToDefaultExpr(right); + return leftExpr.neq(rightExpr); } /** @@ -5524,7 +4155,7 @@ export function neq(left: ScalarExpr | string, right: any): Neq { * @param right The second expression to compare. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: ScalarExpr, right: ScalarExpr): Lt; +export function lt(left: ScalarExpr, right: ScalarExpr): BooleanExpr; /** * @beta @@ -5540,7 +4171,7 @@ export function lt(left: ScalarExpr, right: ScalarExpr): Lt; * @param right The constant value to compare to. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: ScalarExpr, right: any): Lt; +export function lt(left: ScalarExpr, right: any): BooleanExpr; /** * @beta @@ -5556,7 +4187,7 @@ export function lt(left: ScalarExpr, right: any): Lt; * @param right The expression to compare to. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: string, right: ScalarExpr): Lt; +export function lt(left: string, right: ScalarExpr): BooleanExpr; /** * @beta @@ -5572,12 +4203,11 @@ export function lt(left: string, right: ScalarExpr): Lt; * @param right The constant value to compare to. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: string, right: any): Lt; -export function lt(left: ScalarExpr | string, right: any): Lt { +export function lt(left: string, right: any): BooleanExpr; +export function lt(left: ScalarExpr | string, right: any): BooleanExpr { const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); - const rightExpr = - right instanceof ScalarExpr ? right : valueToDefaultExpr(right); - return new Lt(leftExpr, rightExpr); + const rightExpr = valueToDefaultExpr(right); + return leftExpr.lt(rightExpr); } /** @@ -5595,7 +4225,7 @@ export function lt(left: ScalarExpr | string, right: any): Lt { * @param right The second expression to compare. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: ScalarExpr, right: ScalarExpr): Lte; +export function lte(left: ScalarExpr, right: ScalarExpr): BooleanExpr; /** * @beta @@ -5611,7 +4241,7 @@ export function lte(left: ScalarExpr, right: ScalarExpr): Lte; * @param right The constant value to compare to. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: ScalarExpr, right: any): Lte; +export function lte(left: ScalarExpr, right: any): BooleanExpr; /** * Creates an expression that checks if a field's value is less than or equal to an expression. @@ -5625,7 +4255,7 @@ export function lte(left: ScalarExpr, right: any): Lte; * @param right The expression to compare to. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: string, right: ScalarExpr): Lte; +export function lte(left: string, right: ScalarExpr): BooleanExpr; /** * @beta @@ -5641,12 +4271,11 @@ export function lte(left: string, right: ScalarExpr): Lte; * @param right The constant value to compare to. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: string, right: any): Lte; -export function lte(left: ScalarExpr | string, right: any): Lte { +export function lte(left: string, right: any): BooleanExpr; +export function lte(left: ScalarExpr | string, right: any): BooleanExpr { const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); - const rightExpr = - right instanceof ScalarExpr ? right : valueToDefaultExpr(right); - return new Lte(leftExpr, rightExpr); + const rightExpr = valueToDefaultExpr(right); + return leftExpr.lte(rightExpr); } /** @@ -5664,7 +4293,7 @@ export function lte(left: ScalarExpr | string, right: any): Lte { * @param right The second expression to compare. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: ScalarExpr, right: ScalarExpr): Gt; +export function gt(left: ScalarExpr, right: ScalarExpr): BooleanExpr; /** * @beta @@ -5680,7 +4309,7 @@ export function gt(left: ScalarExpr, right: ScalarExpr): Gt; * @param right The constant value to compare to. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: ScalarExpr, right: any): Gt; +export function gt(left: ScalarExpr, right: any): BooleanExpr; /** * @beta @@ -5696,7 +4325,7 @@ export function gt(left: ScalarExpr, right: any): Gt; * @param right The expression to compare to. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: string, right: ScalarExpr): Gt; +export function gt(left: string, right: ScalarExpr): BooleanExpr; /** * @beta @@ -5712,12 +4341,11 @@ export function gt(left: string, right: ScalarExpr): Gt; * @param right The constant value to compare to. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: string, right: any): Gt; -export function gt(left: ScalarExpr | string, right: any): Gt { +export function gt(left: string, right: any): BooleanExpr; +export function gt(left: ScalarExpr | string, right: any): BooleanExpr { const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); - const rightExpr = - right instanceof ScalarExpr ? right : valueToDefaultExpr(right); - return new Gt(leftExpr, rightExpr); + const rightExpr = valueToDefaultExpr(right); + return leftExpr.gt(rightExpr); } /** @@ -5735,7 +4363,7 @@ export function gt(left: ScalarExpr | string, right: any): Gt { * @param right The second expression to compare. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: ScalarExpr, right: ScalarExpr): Gte; +export function gte(left: ScalarExpr, right: ScalarExpr): BooleanExpr; /** * @beta @@ -5752,7 +4380,7 @@ export function gte(left: ScalarExpr, right: ScalarExpr): Gte; * @param right The constant value to compare to. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: ScalarExpr, right: any): Gte; +export function gte(left: ScalarExpr, right: any): BooleanExpr; /** * @beta @@ -5768,7 +4396,7 @@ export function gte(left: ScalarExpr, right: any): Gte; * @param right The expression to compare to. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: string, right: ScalarExpr): Gte; +export function gte(left: string, right: ScalarExpr): BooleanExpr; /** * @beta @@ -5785,12 +4413,11 @@ export function gte(left: string, right: ScalarExpr): Gte; * @param right The constant value to compare to. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: string, right: any): Gte; -export function gte(left: ScalarExpr | string, right: any): Gte { +export function gte(left: string, right: any): BooleanExpr; +export function gte(left: ScalarExpr | string, right: any): BooleanExpr { const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); - const rightExpr = - right instanceof ScalarExpr ? right : valueToDefaultExpr(right); - return new Gte(leftExpr, rightExpr); + const rightExpr = valueToDefaultExpr(right); + return leftExpr.gte(rightExpr); } /** @@ -5812,7 +4439,7 @@ export function arrayConcat( firstArray: ScalarExpr, secondArray: ScalarExpr | any, ...otherArrays: Array -): ArrayConcat; +): FirestoreFunction; /** * @beta @@ -5833,15 +4460,18 @@ export function arrayConcat( firstArrayField: string, secondArray: ScalarExpr | any[], ...otherArrays: Array -): ArrayConcat; +): FirestoreFunction; export function arrayConcat( firstArray: ScalarExpr | string, + secondArray: ScalarExpr | any[], ...otherArrays: Array -): ArrayConcat { - const arrayExpr = fieldOfOrExpr(firstArray); +): FirestoreFunction { const exprValues = otherArrays.map(element => valueToDefaultExpr(element)); - return new ArrayConcat(arrayExpr, exprValues); + return fieldOfOrExpr(firstArray).arrayConcat( + fieldOfOrExpr(secondArray), + ...exprValues + ); } /** @@ -5861,7 +4491,7 @@ export function arrayConcat( export function arrayContains( array: ScalarExpr, element: ScalarExpr -): ArrayContains; +): FirestoreFunction; /** * @beta @@ -5877,7 +4507,10 @@ export function arrayContains( * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains(array: ScalarExpr, element: any): ArrayContains; +export function arrayContains( + array: ScalarExpr, + element: any +): FirestoreFunction; /** * @beta @@ -5896,7 +4529,7 @@ export function arrayContains(array: ScalarExpr, element: any): ArrayContains; export function arrayContains( array: string, element: ScalarExpr -): ArrayContains; +): FirestoreFunction; /** * @beta @@ -5912,15 +4545,14 @@ export function arrayContains( * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains(array: string, element: any): ArrayContains; +export function arrayContains(array: string, element: any): BooleanExpr; export function arrayContains( array: ScalarExpr | string, element: any -): ArrayContains { - const arrayExpr = array instanceof ScalarExpr ? array : Field.of(array); - const elementExpr = - element instanceof ScalarExpr ? element : valueToDefaultExpr(element); - return new ArrayContains(arrayExpr, elementExpr); +): BooleanExpr { + const arrayExpr = fieldOfOrExpr(array); + const elementExpr = valueToDefaultExpr(element); + return arrayExpr.arrayContains(elementExpr); } /** @@ -5941,7 +4573,7 @@ export function arrayContains( export function arrayContainsAny( array: ScalarExpr, values: ScalarExpr[] -): ArrayContainsAny; +): BooleanExpr; /** * @beta @@ -5958,10 +4590,7 @@ export function arrayContainsAny( * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_any' comparison. */ -export function arrayContainsAny( - array: ScalarExpr, - values: any[] -): ArrayContainsAny; +export function arrayContainsAny(array: ScalarExpr, values: any[]): BooleanExpr; /** * @beta @@ -5982,7 +4611,7 @@ export function arrayContainsAny( export function arrayContainsAny( array: string, values: ScalarExpr[] -): ArrayContainsAny; +): BooleanExpr; /** * @beta @@ -6000,19 +4629,14 @@ export function arrayContainsAny( * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_any' comparison. */ -export function arrayContainsAny( - array: string, - values: any[] -): ArrayContainsAny; +export function arrayContainsAny(array: string, values: any[]): BooleanExpr; export function arrayContainsAny( array: ScalarExpr | string, values: any[] -): ArrayContainsAny { - const arrayExpr = array instanceof ScalarExpr ? array : Field.of(array); - const exprValues = values.map(value => - value instanceof ScalarExpr ? value : valueToDefaultExpr(value) +): BooleanExpr { + return fieldOfOrExpr(array).arrayContainsAny( + ...values.map(valueToDefaultExpr) ); - return new ArrayContainsAny(arrayExpr, exprValues); } /** @@ -6032,7 +4656,7 @@ export function arrayContainsAny( export function arrayContainsAll( array: ScalarExpr, values: ScalarExpr[] -): ArrayContainsAll; +): BooleanExpr; /** * @beta @@ -6048,10 +4672,7 @@ export function arrayContainsAll( * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_all' comparison. */ -export function arrayContainsAll( - array: ScalarExpr, - values: any[] -): ArrayContainsAll; +export function arrayContainsAll(array: ScalarExpr, values: any[]): BooleanExpr; /** * @beta @@ -6071,7 +4692,7 @@ export function arrayContainsAll( export function arrayContainsAll( array: string, values: ScalarExpr[] -): ArrayContainsAll; +): BooleanExpr; /** * @beta @@ -6088,19 +4709,14 @@ export function arrayContainsAll( * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_all' comparison. */ -export function arrayContainsAll( - array: string, - values: any[] -): ArrayContainsAll; +export function arrayContainsAll(array: string, values: any[]): BooleanExpr; export function arrayContainsAll( array: ScalarExpr | string, values: any[] -): ArrayContainsAll { - const arrayExpr = array instanceof ScalarExpr ? array : Field.of(array); - const exprValues = values.map(value => - value instanceof ScalarExpr ? value : valueToDefaultExpr(value) - ); - return new ArrayContainsAll(arrayExpr, exprValues); +): BooleanExpr { + const arrayExpr = fieldOfOrExpr(array); + const exprValues = values.map(value => valueToDefaultExpr(value)); + return arrayExpr.arrayContainsAll(exprValues); } /** @@ -6116,8 +4732,8 @@ export function arrayContainsAll( * @param array The array expression to calculate the length of. * @return A new {@code Expr} representing the length of the array. */ -export function arrayLength(array: ScalarExpr): ArrayLength { - return new ArrayLength(array); +export function arrayLength(array: ScalarExpr): FirestoreFunction { + return array.arrayLength(); } /** @@ -6135,7 +4751,7 @@ export function arrayLength(array: ScalarExpr): ArrayLength { * @param others The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: ScalarExpr, others: ScalarExpr[]): EqAny; +export function eqAny(element: ScalarExpr, others: ScalarExpr[]): BooleanExpr; /** * @beta @@ -6152,7 +4768,7 @@ export function eqAny(element: ScalarExpr, others: ScalarExpr[]): EqAny; * @param others The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: ScalarExpr, others: any[]): EqAny; +export function eqAny(element: ScalarExpr, others: any[]): BooleanExpr; /** * @beta @@ -6169,7 +4785,7 @@ export function eqAny(element: ScalarExpr, others: any[]): EqAny; * @param others The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: string, others: ScalarExpr[]): EqAny; +export function eqAny(element: string, others: ScalarExpr[]): BooleanExpr; /** * @beta @@ -6186,14 +4802,14 @@ export function eqAny(element: string, others: ScalarExpr[]): EqAny; * @param others The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: string, others: any[]): EqAny; -export function eqAny(element: ScalarExpr | string, others: any[]): EqAny { - const elementExpr = - element instanceof ScalarExpr ? element : Field.of(element); - const exprOthers = others.map(other => - other instanceof ScalarExpr ? other : valueToDefaultExpr(other) - ); - return new EqAny(elementExpr, exprOthers); +export function eqAny(element: string, others: any[]): BooleanExpr; +export function eqAny( + element: ScalarExpr | string, + others: any[] +): BooleanExpr { + const elementExpr = fieldOfOrExpr(element); + const exprOthers = others.map(other => valueToDefaultExpr(other)); + return elementExpr.eqAny(...exprOthers); } /** @@ -6211,7 +4827,10 @@ export function eqAny(element: ScalarExpr | string, others: any[]): EqAny { * @param others The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: ScalarExpr, others: ScalarExpr[]): NotEqAny; +export function notEqAny( + element: ScalarExpr, + others: ScalarExpr[] +): BooleanExpr; /** * @beta @@ -6228,7 +4847,7 @@ export function notEqAny(element: ScalarExpr, others: ScalarExpr[]): NotEqAny; * @param others The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: ScalarExpr, others: any[]): NotEqAny; +export function notEqAny(element: ScalarExpr, others: any[]): BooleanExpr; /** * @beta @@ -6245,7 +4864,7 @@ export function notEqAny(element: ScalarExpr, others: any[]): NotEqAny; * @param others The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: string, others: ScalarExpr[]): NotEqAny; +export function notEqAny(element: string, others: ScalarExpr[]): BooleanExpr; /** * @beta @@ -6262,17 +4881,14 @@ export function notEqAny(element: string, others: ScalarExpr[]): NotEqAny; * @param others The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: string, others: any[]): NotEqAny; +export function notEqAny(element: string, others: any[]): BooleanExpr; export function notEqAny( element: ScalarExpr | string, others: any[] -): NotEqAny { - const elementExpr = - element instanceof ScalarExpr ? element : Field.of(element); - const exprOthers = others.map(other => - other instanceof ScalarExpr ? other : valueToDefaultExpr(other) - ); - return new NotEqAny(elementExpr, exprOthers); +): BooleanExpr { + const elementExpr = fieldOfOrExpr(element); + const exprOthers = others.map(other => valueToDefaultExpr(other)); + return elementExpr.notEqAny(...exprOthers); } /** @@ -6299,8 +4915,8 @@ export function xor( first: BooleanExpr, second: BooleanExpr, ...more: BooleanExpr[] -): Xor { - return new Xor([first, second, ...more]); +): BooleanExpr { + return new BooleanExpr('xor', [first, second, ...more]); } /** @@ -6324,8 +4940,8 @@ export function cond( condition: BooleanExpr, thenExpr: ScalarExpr, elseExpr: ScalarExpr -): Cond { - return new Cond(condition, thenExpr, elseExpr); +): FirestoreFunction { + return new BooleanExpr('cond', [condition, thenExpr, elseExpr]); } /** @@ -6341,8 +4957,8 @@ export function cond( * @param filter The filter condition to negate. * @return A new {@code Expr} representing the negated filter condition. */ -export function not(filter: BooleanExpr): Not { - return new Not(filter); +export function not(filter: BooleanExpr): BooleanExpr { + return filter.not(); } /** @@ -6364,7 +4980,7 @@ export function logicalMaximum( first: ScalarExpr, second: ScalarExpr | any, ...others: Array -): LogicalMaximum; +): FirestoreFunction; /** * @beta @@ -6385,15 +5001,16 @@ export function logicalMaximum( left: string, second: ScalarExpr | any, ...others: Array -): LogicalMaximum; +): FirestoreFunction; export function logicalMaximum( first: ScalarExpr | string, + second: ScalarExpr | any, ...others: Array -): LogicalMaximum { - return new LogicalMaximum( - fieldOfOrExpr(first), - others.map(value => valueToDefaultExpr(value)) +): FirestoreFunction { + return fieldOfOrExpr(first).logicalMaximum( + valueToDefaultExpr(second), + ...others.map(value => valueToDefaultExpr(value)) ); } @@ -6416,7 +5033,7 @@ export function logicalMinimum( first: ScalarExpr, second: ScalarExpr | any, ...others: Array -): LogicalMinimum; +): FirestoreFunction; /** * @beta @@ -6437,15 +5054,16 @@ export function logicalMinimum( fieldName: string, second: ScalarExpr | any, ...others: Array -): LogicalMinimum; +): FirestoreFunction; export function logicalMinimum( first: ScalarExpr | string, + second: ScalarExpr | any, ...others: Array -): LogicalMinimum { - return new LogicalMinimum( - fieldOfOrExpr(first), - others.map(value => valueToDefaultExpr(value)) +): FirestoreFunction { + return fieldOfOrExpr(first).logicalMinimum( + valueToDefaultExpr(second), + ...others.map(value => valueToDefaultExpr(value)) ); } @@ -6462,7 +5080,7 @@ export function logicalMinimum( * @param value An expression evaluates to the name of the field to check. * @return A new {@code Expr} representing the 'exists' check. */ -export function exists(value: ScalarExpr): Exists; +export function exists(value: ScalarExpr): BooleanExpr; /** * @beta @@ -6477,11 +5095,9 @@ export function exists(value: ScalarExpr): Exists; * @param field The field name to check. * @return A new {@code Expr} representing the 'exists' check. */ -export function exists(field: string): Exists; -export function exists(valueOrField: ScalarExpr | string): Exists { - const valueExpr = - valueOrField instanceof ScalarExpr ? valueOrField : Field.of(valueOrField); - return new Exists(valueExpr); +export function exists(field: string): BooleanExpr; +export function exists(valueOrField: ScalarExpr | string): BooleanExpr { + return fieldOfOrExpr(valueOrField).exists(); } /** @@ -6497,7 +5113,7 @@ export function exists(valueOrField: ScalarExpr | string): Exists { * @param value The expression to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNan(value: ScalarExpr): IsNan; +export function isNan(value: ScalarExpr): BooleanExpr; /** * @beta @@ -6512,10 +5128,9 @@ export function isNan(value: ScalarExpr): IsNan; * @param value The name of the field to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNan(value: string): IsNan; -export function isNan(value: ScalarExpr | string): IsNan { - const valueExpr = value instanceof ScalarExpr ? value : Field.of(value); - return new IsNan(valueExpr); +export function isNan(value: string): BooleanExpr; +export function isNan(value: ScalarExpr | string): BooleanExpr { + return fieldOfOrExpr(value).isNan(); } /** @@ -6531,7 +5146,7 @@ export function isNan(value: ScalarExpr | string): IsNan { * @param expr The expression representing the string to reverse. * @return A new {@code Expr} representing the reversed string. */ -export function reverse(expr: ScalarExpr): Reverse; +export function reverse(expr: ScalarExpr): FirestoreFunction; /** * @beta @@ -6546,10 +5161,9 @@ export function reverse(expr: ScalarExpr): Reverse; * @param field The name of the field representing the string to reverse. * @return A new {@code Expr} representing the reversed string. */ -export function reverse(field: string): Reverse; -export function reverse(expr: ScalarExpr | string): Reverse { - const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; - return new Reverse(normalizedExpr); +export function reverse(field: string): FirestoreFunction; +export function reverse(expr: ScalarExpr | string): FirestoreFunction { + return fieldOfOrExpr(expr).reverse(); } /** @@ -6571,7 +5185,7 @@ export function replaceFirst( value: ScalarExpr, find: string, replace: string -): ReplaceFirst; +): FirestoreFunction; /** * @beta @@ -6593,7 +5207,7 @@ export function replaceFirst( value: ScalarExpr, find: ScalarExpr, replace: ScalarExpr -): ReplaceFirst; +): FirestoreFunction; /** * @beta @@ -6614,17 +5228,16 @@ export function replaceFirst( field: string, find: string, replace: string -): ReplaceFirst; +): FirestoreFunction; export function replaceFirst( value: ScalarExpr | string, find: ScalarExpr | string, replace: ScalarExpr | string -): ReplaceFirst { - const normalizedValue = typeof value === 'string' ? Field.of(value) : value; - const normalizedFind = typeof find === 'string' ? Constant.of(find) : find; - const normalizedReplace = - typeof replace === 'string' ? Constant.of(replace) : replace; - return new ReplaceFirst(normalizedValue, normalizedFind, normalizedReplace); +): FirestoreFunction { + const normalizedValue = fieldOfOrExpr(value); + const normalizedFind = valueToDefaultExpr(find); + const normalizedReplace = valueToDefaultExpr(replace); + return normalizedValue.replaceFirst(normalizedFind, normalizedReplace); } /** @@ -6646,7 +5259,7 @@ export function replaceAll( value: ScalarExpr, find: string, replace: string -): ReplaceAll; +): FirestoreFunction; /** * @beta @@ -6668,7 +5281,7 @@ export function replaceAll( value: ScalarExpr, find: ScalarExpr, replace: ScalarExpr -): ReplaceAll; +): FirestoreFunction; /** * @beta @@ -6689,17 +5302,16 @@ export function replaceAll( field: string, find: string, replace: string -): ReplaceAll; +): FirestoreFunction; export function replaceAll( value: ScalarExpr | string, find: ScalarExpr | string, replace: ScalarExpr | string -): ReplaceAll { - const normalizedValue = typeof value === 'string' ? Field.of(value) : value; - const normalizedFind = typeof find === 'string' ? Constant.of(find) : find; - const normalizedReplace = - typeof replace === 'string' ? Constant.of(replace) : replace; - return new ReplaceAll(normalizedValue, normalizedFind, normalizedReplace); +): FirestoreFunction { + const normalizedValue = fieldOfOrExpr(value); + const normalizedFind = valueToDefaultExpr(find); + const normalizedReplace = valueToDefaultExpr(replace); + return normalizedValue.replaceAll(normalizedFind, normalizedReplace); } /** @@ -6715,7 +5327,7 @@ export function replaceAll( * @param expr The expression representing the string. * @return A new {@code Expr} representing the length of the string in bytes. */ -export function byteLength(expr: ScalarExpr): ByteLength; +export function byteLength(expr: ScalarExpr): FirestoreFunction; /** * @beta @@ -6730,10 +5342,10 @@ export function byteLength(expr: ScalarExpr): ByteLength; * @param field The name of the field representing the string. * @return A new {@code Expr} representing the length of the string in bytes. */ -export function byteLength(field: string): ByteLength; -export function byteLength(expr: ScalarExpr | string): ByteLength { - const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; - return new ByteLength(normalizedExpr); +export function byteLength(field: string): FirestoreFunction; +export function byteLength(expr: ScalarExpr | string): FirestoreFunction { + const normalizedExpr = fieldOfOrExpr(expr); + return normalizedExpr.byteLength(); } /** @@ -6749,7 +5361,7 @@ export function byteLength(expr: ScalarExpr | string): ByteLength { * @param field The name of the field containing the string. * @return A new {@code Expr} representing the length of the string. */ -export function charLength(field: string): CharLength; +export function charLength(field: string): FirestoreFunction; /** * @beta @@ -6764,10 +5376,10 @@ export function charLength(field: string): CharLength; * @param expr The expression representing the string to calculate the length of. * @return A new {@code Expr} representing the length of the string. */ -export function charLength(expr: ScalarExpr): CharLength; -export function charLength(value: ScalarExpr | string): CharLength { - const valueExpr = value instanceof ScalarExpr ? value : Field.of(value); - return new CharLength(valueExpr); +export function charLength(expr: ScalarExpr): FirestoreFunction; +export function charLength(value: ScalarExpr | string): FirestoreFunction { + const valueExpr = fieldOfOrExpr(value); + return valueExpr.charLength(); } /** @@ -6785,7 +5397,7 @@ export function charLength(value: ScalarExpr | string): CharLength { * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: string, pattern: string): Like; +export function like(left: string, pattern: string): BooleanExpr; /** * @beta @@ -6802,7 +5414,7 @@ export function like(left: string, pattern: string): Like; * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: string, pattern: ScalarExpr): Like; +export function like(left: string, pattern: ScalarExpr): BooleanExpr; /** * @beta @@ -6818,7 +5430,7 @@ export function like(left: string, pattern: ScalarExpr): Like; * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: ScalarExpr, pattern: string): Like; +export function like(left: ScalarExpr, pattern: string): BooleanExpr; /** * @beta @@ -6834,15 +5446,14 @@ export function like(left: ScalarExpr, pattern: string): Like; * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: ScalarExpr, pattern: ScalarExpr): Like; +export function like(left: ScalarExpr, pattern: ScalarExpr): BooleanExpr; export function like( left: ScalarExpr | string, pattern: ScalarExpr | string -): Like { - const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); - const patternExpr = - pattern instanceof ScalarExpr ? pattern : valueToDefaultExpr(pattern); - return new Like(leftExpr, patternExpr); +): FirestoreFunction { + const leftExpr = fieldOfOrExpr(left); + const patternExpr = valueToDefaultExpr(pattern); + return leftExpr.like(patternExpr); } /** @@ -6860,7 +5471,7 @@ export function like( * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function regexContains(left: string, pattern: string): RegexContains; +export function regexContains(left: string, pattern: string): BooleanExpr; /** * @beta @@ -6877,7 +5488,7 @@ export function regexContains(left: string, pattern: string): RegexContains; * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function regexContains(left: string, pattern: ScalarExpr): RegexContains; +export function regexContains(left: string, pattern: ScalarExpr): BooleanExpr; /** * @beta @@ -6894,7 +5505,7 @@ export function regexContains(left: string, pattern: ScalarExpr): RegexContains; * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function regexContains(left: ScalarExpr, pattern: string): RegexContains; +export function regexContains(left: ScalarExpr, pattern: string): BooleanExpr; /** * @beta @@ -6914,15 +5525,14 @@ export function regexContains(left: ScalarExpr, pattern: string): RegexContains; export function regexContains( left: ScalarExpr, pattern: ScalarExpr -): RegexContains; +): BooleanExpr; export function regexContains( left: ScalarExpr | string, pattern: ScalarExpr | string -): RegexContains { - const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); - const patternExpr = - pattern instanceof ScalarExpr ? pattern : valueToDefaultExpr(pattern); - return new RegexContains(leftExpr, patternExpr); +): BooleanExpr { + const leftExpr = fieldOfOrExpr(left); + const patternExpr = valueToDefaultExpr(pattern); + return leftExpr.regexContains(patternExpr); } /** @@ -6939,7 +5549,7 @@ export function regexContains( * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: string, pattern: string): RegexMatch; +export function regexMatch(left: string, pattern: string): BooleanExpr; /** * @beta @@ -6955,7 +5565,7 @@ export function regexMatch(left: string, pattern: string): RegexMatch; * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: string, pattern: ScalarExpr): RegexMatch; +export function regexMatch(left: string, pattern: ScalarExpr): BooleanExpr; /** * @beta @@ -6972,7 +5582,7 @@ export function regexMatch(left: string, pattern: ScalarExpr): RegexMatch; * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: ScalarExpr, pattern: string): RegexMatch; +export function regexMatch(left: ScalarExpr, pattern: string): BooleanExpr; /** * @beta @@ -6989,15 +5599,14 @@ export function regexMatch(left: ScalarExpr, pattern: string): RegexMatch; * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: ScalarExpr, pattern: ScalarExpr): RegexMatch; +export function regexMatch(left: ScalarExpr, pattern: ScalarExpr): BooleanExpr; export function regexMatch( left: ScalarExpr | string, pattern: ScalarExpr | string -): RegexMatch { - const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); - const patternExpr = - pattern instanceof ScalarExpr ? pattern : valueToDefaultExpr(pattern); - return new RegexMatch(leftExpr, patternExpr); +): BooleanExpr { + const leftExpr = fieldOfOrExpr(left); + const patternExpr = valueToDefaultExpr(pattern); + return leftExpr.regexMatch(patternExpr); } /** @@ -7014,7 +5623,7 @@ export function regexMatch( * @param substring The substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function strContains(left: string, substring: string): StrContains; +export function strContains(left: string, substring: string): BooleanExpr; /** * @beta @@ -7030,7 +5639,7 @@ export function strContains(left: string, substring: string): StrContains; * @param substring The expression representing the substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function strContains(left: string, substring: ScalarExpr): StrContains; +export function strContains(left: string, substring: ScalarExpr): BooleanExpr; /** * @beta @@ -7046,7 +5655,7 @@ export function strContains(left: string, substring: ScalarExpr): StrContains; * @param substring The substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function strContains(left: ScalarExpr, substring: string): StrContains; +export function strContains(left: ScalarExpr, substring: string): BooleanExpr; /** * @beta @@ -7065,15 +5674,14 @@ export function strContains(left: ScalarExpr, substring: string): StrContains; export function strContains( left: ScalarExpr, substring: ScalarExpr -): StrContains; +): BooleanExpr; export function strContains( left: ScalarExpr | string, substring: ScalarExpr | string -): StrContains { - const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); - const substringExpr = - substring instanceof ScalarExpr ? substring : valueToDefaultExpr(substring); - return new StrContains(leftExpr, substringExpr); +): BooleanExpr { + const leftExpr = fieldOfOrExpr(left); + const substringExpr = valueToDefaultExpr(substring); + return leftExpr.strContains(substringExpr); } /** @@ -7090,7 +5698,7 @@ export function strContains( * @param prefix The prefix to check for. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: string, prefix: string): StartsWith; +export function startsWith(expr: string, prefix: string): BooleanExpr; /** * @beta @@ -7106,7 +5714,7 @@ export function startsWith(expr: string, prefix: string): StartsWith; * @param prefix The expression representing the prefix. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: string, prefix: ScalarExpr): StartsWith; +export function startsWith(expr: string, prefix: ScalarExpr): BooleanExpr; /** * @beta @@ -7122,7 +5730,7 @@ export function startsWith(expr: string, prefix: ScalarExpr): StartsWith; * @param prefix The prefix to check for. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: ScalarExpr, prefix: string): StartsWith; +export function startsWith(expr: ScalarExpr, prefix: string): BooleanExpr; /** * @beta @@ -7138,15 +5746,12 @@ export function startsWith(expr: ScalarExpr, prefix: string): StartsWith; * @param prefix The prefix to check for. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: ScalarExpr, prefix: ScalarExpr): StartsWith; +export function startsWith(expr: ScalarExpr, prefix: ScalarExpr): BooleanExpr; export function startsWith( expr: ScalarExpr | string, prefix: ScalarExpr | string -): StartsWith { - const exprLeft = expr instanceof ScalarExpr ? expr : Field.of(expr); - const prefixExpr = - prefix instanceof ScalarExpr ? prefix : valueToDefaultExpr(prefix); - return new StartsWith(exprLeft, prefixExpr); +): BooleanExpr { + return fieldOfOrExpr(expr).startsWith(valueToDefaultExpr(prefix)); } /** @@ -7163,7 +5768,7 @@ export function startsWith( * @param suffix The postfix to check for. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: string, suffix: string): EndsWith; +export function endsWith(expr: string, suffix: string): BooleanExpr; /** * @beta @@ -7179,7 +5784,7 @@ export function endsWith(expr: string, suffix: string): EndsWith; * @param suffix The expression representing the postfix. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: string, suffix: ScalarExpr): EndsWith; +export function endsWith(expr: string, suffix: ScalarExpr): BooleanExpr; /** * @beta @@ -7195,7 +5800,7 @@ export function endsWith(expr: string, suffix: ScalarExpr): EndsWith; * @param suffix The postfix to check for. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: ScalarExpr, suffix: string): EndsWith; +export function endsWith(expr: ScalarExpr, suffix: string): BooleanExpr; /** * @beta @@ -7211,15 +5816,12 @@ export function endsWith(expr: ScalarExpr, suffix: string): EndsWith; * @param suffix The postfix to check for. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: ScalarExpr, suffix: ScalarExpr): EndsWith; +export function endsWith(expr: ScalarExpr, suffix: ScalarExpr): BooleanExpr; export function endsWith( expr: ScalarExpr | string, suffix: ScalarExpr | string -): EndsWith { - const exprLeft = expr instanceof ScalarExpr ? expr : Field.of(expr); - const suffixExpr = - suffix instanceof ScalarExpr ? suffix : valueToDefaultExpr(suffix); - return new EndsWith(exprLeft, suffixExpr); +): BooleanExpr { + return fieldOfOrExpr(expr).endsWith(valueToDefaultExpr(suffix)); } /** @@ -7235,7 +5837,7 @@ export function endsWith( * @param expr The name of the field containing the string. * @return A new {@code Expr} representing the lowercase string. */ -export function toLower(expr: string): ToLower; +export function toLower(expr: string): FirestoreFunction; /** * @beta @@ -7250,9 +5852,9 @@ export function toLower(expr: string): ToLower; * @param expr The expression representing the string to convert to lowercase. * @return A new {@code Expr} representing the lowercase string. */ -export function toLower(expr: ScalarExpr): ToLower; -export function toLower(expr: ScalarExpr | string): ToLower { - return new ToLower(expr instanceof ScalarExpr ? expr : Field.of(expr)); +export function toLower(expr: ScalarExpr): FirestoreFunction; +export function toLower(expr: ScalarExpr | string): FirestoreFunction { + return fieldOfOrExpr(expr).toLower(); } /** @@ -7268,7 +5870,7 @@ export function toLower(expr: ScalarExpr | string): ToLower { * @param expr The name of the field containing the string. * @return A new {@code Expr} representing the uppercase string. */ -export function toUpper(expr: string): ToUpper; +export function toUpper(expr: string): FirestoreFunction; /** * @beta @@ -7283,9 +5885,9 @@ export function toUpper(expr: string): ToUpper; * @param expr The expression representing the string to convert to uppercase. * @return A new {@code Expr} representing the uppercase string. */ -export function toUpper(expr: ScalarExpr): ToUpper; -export function toUpper(expr: ScalarExpr | string): ToUpper { - return new ToUpper(expr instanceof ScalarExpr ? expr : Field.of(expr)); +export function toUpper(expr: ScalarExpr): FirestoreFunction; +export function toUpper(expr: ScalarExpr | string): FirestoreFunction { + return fieldOfOrExpr(expr).toUpper(); } /** @@ -7301,7 +5903,7 @@ export function toUpper(expr: ScalarExpr | string): ToUpper { * @param expr The name of the field containing the string. * @return A new {@code Expr} representing the trimmed string. */ -export function trim(expr: string): Trim; +export function trim(expr: string): FirestoreFunction; /** * @beta @@ -7316,9 +5918,9 @@ export function trim(expr: string): Trim; * @param expr The expression representing the string to trim. * @return A new {@code Expr} representing the trimmed string. */ -export function trim(expr: ScalarExpr): Trim; -export function trim(expr: ScalarExpr | string): Trim { - return new Trim(expr instanceof ScalarExpr ? expr : Field.of(expr)); +export function trim(expr: ScalarExpr): FirestoreFunction; +export function trim(expr: ScalarExpr | string): FirestoreFunction { + return fieldOfOrExpr(expr).trim(); } /** @@ -7340,7 +5942,7 @@ export function strConcat( fieldName: string, secondString: ScalarExpr | string, ...otherStrings: Array -): StrConcat; +): FirestoreFunction; /** * @beta @@ -7360,15 +5962,16 @@ export function strConcat( firstString: ScalarExpr, secondString: ScalarExpr | string, ...otherStrings: Array -): StrConcat; +): FirestoreFunction; export function strConcat( first: string | ScalarExpr, + second: string | ScalarExpr, ...elements: Array -): StrConcat { - const exprs = elements.map(e => - e instanceof ScalarExpr ? e : valueToDefaultExpr(e) +): FirestoreFunction { + return valueToDefaultExpr(first).strConcat( + valueToDefaultExpr(second), + ...elements.map(valueToDefaultExpr) ); - return new StrConcat(valueToDefaultExpr(first), exprs); } /** @@ -7385,7 +5988,7 @@ export function strConcat( * @param subField The key to access in the map. * @return A new {@code Expr} representing the value associated with the given key in the map. */ -export function mapGet(mapField: string, subField: string): MapGet; +export function mapGet(mapField: string, subField: string): FirestoreFunction; /** * @beta @@ -7401,15 +6004,15 @@ export function mapGet(mapField: string, subField: string): MapGet; * @param subField The key to access in the map. * @return A new {@code Expr} representing the value associated with the given key in the map. */ -export function mapGet(mapExpr: ScalarExpr, subField: string): MapGet; +export function mapGet( + mapExpr: ScalarExpr, + subField: string +): FirestoreFunction; export function mapGet( fieldOrExpr: string | ScalarExpr, subField: string -): MapGet { - return new MapGet( - typeof fieldOrExpr === 'string' ? Field.of(fieldOrExpr) : fieldOrExpr, - subField - ); +): FirestoreFunction { + return fieldOfOrExpr(fieldOrExpr).mapGet(subField); } /** @@ -7418,14 +6021,14 @@ export function mapGet( * Creates an aggregation that counts the total number of stage inputs. * * ```typescript - * // Count the total number of users - * countAll().as("totalUsers"); + * // Count the total number of input documents + * countAll().as("totalDocument"); * ``` * * @return A new {@code AggregateFunction} representing the 'countAll' aggregation. */ -export function countAll(): Count { - return new Count(undefined, false); +export function countAll(): AggregateFunction { + return new AggregateFunction('count', []); } /** @@ -7442,7 +6045,7 @@ export function countAll(): Count { * @param value The expression to count. * @return A new {@code AggregateFunction} representing the 'count' aggregation. */ -export function countFunction(value: ScalarExpr): Count; +export function countFunction(value: ScalarExpr): AggregateFunction; /** * Creates an aggregation that counts the number of stage inputs with valid evaluations of the @@ -7456,10 +6059,9 @@ export function countFunction(value: ScalarExpr): Count; * @param value The name of the field to count. * @return A new {@code AggregateFunction} representing the 'count' aggregation. */ -export function countFunction(value: string): Count; -export function countFunction(value: ScalarExpr | string): Count { - const exprValue = value instanceof ScalarExpr ? value : Field.of(value); - return new Count(exprValue, false); +export function countFunction(value: string): AggregateFunction; +export function countFunction(value: ScalarExpr | string): AggregateFunction { + return fieldOfOrExpr(value).count(); } /** @@ -7476,7 +6078,7 @@ export function countFunction(value: ScalarExpr | string): Count { * @param value The expression to sum up. * @return A new {@code AggregateFunction} representing the 'sum' aggregation. */ -export function sumFunction(value: ScalarExpr): Sum; +export function sumFunction(value: ScalarExpr): AggregateFunction; /** * @beta @@ -7492,10 +6094,9 @@ export function sumFunction(value: ScalarExpr): Sum; * @param value The name of the field containing numeric values to sum up. * @return A new {@code AggregateFunction} representing the 'sum' aggregation. */ -export function sumFunction(value: string): Sum; -export function sumFunction(value: ScalarExpr | string): Sum { - const exprValue = value instanceof ScalarExpr ? value : Field.of(value); - return new Sum(exprValue, false); +export function sumFunction(value: string): AggregateFunction; +export function sumFunction(value: ScalarExpr | string): AggregateFunction { + return fieldOfOrExpr(value).sum(); } /** @@ -7512,7 +6113,7 @@ export function sumFunction(value: ScalarExpr | string): Sum { * @param value The expression representing the values to average. * @return A new {@code AggregateFunction} representing the 'avg' aggregation. */ -export function avgFunction(value: ScalarExpr): Avg; +export function avgFunction(value: ScalarExpr): AggregateFunction; /** * @beta @@ -7528,10 +6129,9 @@ export function avgFunction(value: ScalarExpr): Avg; * @param value The name of the field containing numeric values to average. * @return A new {@code AggregateFunction} representing the 'avg' aggregation. */ -export function avgFunction(value: string): Avg; -export function avgFunction(value: ScalarExpr | string): Avg { - const exprValue = value instanceof ScalarExpr ? value : Field.of(value); - return new Avg(exprValue, false); +export function avgFunction(value: string): AggregateFunction; +export function avgFunction(value: ScalarExpr | string): AggregateFunction { + return fieldOfOrExpr(value).avg(); } /** @@ -7548,7 +6148,7 @@ export function avgFunction(value: ScalarExpr | string): Avg { * @param value The expression to find the minimum value of. * @return A new {@code AggregateFunction} representing the 'min' aggregation. */ -export function minimum(value: ScalarExpr): Minimum; +export function minimum(value: ScalarExpr): AggregateFunction; /** * @beta @@ -7563,10 +6163,9 @@ export function minimum(value: ScalarExpr): Minimum; * @param value The name of the field to find the minimum value of. * @return A new {@code AggregateFunction} representing the 'min' aggregation. */ -export function minimum(value: string): Minimum; -export function minimum(value: ScalarExpr | string): Minimum { - const exprValue = value instanceof ScalarExpr ? value : Field.of(value); - return new Minimum(exprValue, false); +export function minimum(value: string): AggregateFunction; +export function minimum(value: ScalarExpr | string): AggregateFunction { + return fieldOfOrExpr(value).minimum(); } /** @@ -7583,7 +6182,7 @@ export function minimum(value: ScalarExpr | string): Minimum { * @param value The expression to find the maximum value of. * @return A new {@code AggregateFunction} representing the 'max' aggregation. */ -export function maximum(value: ScalarExpr): Maximum; +export function maximum(value: ScalarExpr): AggregateFunction; /** * @beta @@ -7598,10 +6197,9 @@ export function maximum(value: ScalarExpr): Maximum; * @param value The name of the field to find the maximum value of. * @return A new {@code AggregateFunction} representing the 'max' aggregation. */ -export function maximum(value: string): Maximum; -export function maximum(value: ScalarExpr | string): Maximum { - const exprValue = value instanceof ScalarExpr ? value : Field.of(value); - return new Maximum(exprValue, false); +export function maximum(value: string): AggregateFunction; +export function maximum(value: ScalarExpr | string): AggregateFunction { + return fieldOfOrExpr(value).maximum(); } /** @@ -7618,7 +6216,10 @@ export function maximum(value: ScalarExpr | string): Maximum { * @param other The other vector (as an array of doubles) to compare against. * @return A new {@code Expr} representing the Cosine distance between the two vectors. */ -export function cosineDistance(expr: string, other: number[]): CosineDistance; +export function cosineDistance( + expr: string, + other: number[] +): FirestoreFunction; /** * @beta @@ -7637,7 +6238,7 @@ export function cosineDistance(expr: string, other: number[]): CosineDistance; export function cosineDistance( expr: string, other: VectorValue -): CosineDistance; +): FirestoreFunction; /** * @beta @@ -7653,7 +6254,10 @@ export function cosineDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance(expr: string, other: ScalarExpr): CosineDistance; +export function cosineDistance( + expr: string, + other: ScalarExpr +): FirestoreFunction; /** * @beta @@ -7672,7 +6276,7 @@ export function cosineDistance(expr: string, other: ScalarExpr): CosineDistance; export function cosineDistance( expr: ScalarExpr, other: number[] -): CosineDistance; +): FirestoreFunction; /** * @beta @@ -7691,7 +6295,7 @@ export function cosineDistance( export function cosineDistance( expr: ScalarExpr, other: VectorValue -): CosineDistance; +): FirestoreFunction; /** * @beta @@ -7710,14 +6314,14 @@ export function cosineDistance( export function cosineDistance( expr: ScalarExpr, other: ScalarExpr -): CosineDistance; +): FirestoreFunction; export function cosineDistance( expr: ScalarExpr | string, other: ScalarExpr | number[] | VectorValue -): CosineDistance { - const expr1 = expr instanceof ScalarExpr ? expr : Field.of(expr); - const expr2 = other instanceof ScalarExpr ? other : Constant.vector(other); - return new CosineDistance(expr1, expr2); +): FirestoreFunction { + const expr1 = fieldOfOrExpr(expr); + const expr2 = vectorToExpr(other); + return expr1.cosineDistance(expr2); } /** @@ -7734,7 +6338,7 @@ export function cosineDistance( * @param other The other vector (as an array of doubles) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: string, other: number[]): DotProduct; +export function dotProduct(expr: string, other: number[]): FirestoreFunction; /** * @beta @@ -7750,7 +6354,7 @@ export function dotProduct(expr: string, other: number[]): DotProduct; * @param other The other vector (as a VectorValue) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: string, other: VectorValue): DotProduct; +export function dotProduct(expr: string, other: VectorValue): FirestoreFunction; /** * @beta @@ -7766,7 +6370,7 @@ export function dotProduct(expr: string, other: VectorValue): DotProduct; * @param other The other vector (represented as an Expr) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: string, other: ScalarExpr): DotProduct; +export function dotProduct(expr: string, other: ScalarExpr): FirestoreFunction; /** * @beta @@ -7782,7 +6386,10 @@ export function dotProduct(expr: string, other: ScalarExpr): DotProduct; * @param other The other vector (as an array of doubles) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: ScalarExpr, other: number[]): DotProduct; +export function dotProduct( + expr: ScalarExpr, + other: number[] +): FirestoreFunction; /** * @beta @@ -7798,7 +6405,10 @@ export function dotProduct(expr: ScalarExpr, other: number[]): DotProduct; * @param other The other vector (as a VectorValue) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: ScalarExpr, other: VectorValue): DotProduct; +export function dotProduct( + expr: ScalarExpr, + other: VectorValue +): FirestoreFunction; /** * @beta @@ -7814,14 +6424,17 @@ export function dotProduct(expr: ScalarExpr, other: VectorValue): DotProduct; * @param other The other vector (represented as an Expr) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: ScalarExpr, other: ScalarExpr): DotProduct; +export function dotProduct( + expr: ScalarExpr, + other: ScalarExpr +): FirestoreFunction; export function dotProduct( expr: ScalarExpr | string, other: ScalarExpr | number[] | VectorValue -): DotProduct { - const expr1 = expr instanceof ScalarExpr ? expr : Field.of(expr); - const expr2 = other instanceof ScalarExpr ? other : Constant.vector(other); - return new DotProduct(expr1, expr2); +): FirestoreFunction { + const expr1 = fieldOfOrExpr(expr); + const expr2 = vectorToExpr(other); + return expr1.dotProduct(expr2); } /** @@ -7841,7 +6454,7 @@ export function dotProduct( export function euclideanDistance( expr: string, other: number[] -): EuclideanDistance; +): FirestoreFunction; /** * @beta @@ -7860,7 +6473,7 @@ export function euclideanDistance( export function euclideanDistance( expr: string, other: VectorValue -): EuclideanDistance; +): FirestoreFunction; /** * @beta @@ -7879,7 +6492,7 @@ export function euclideanDistance( export function euclideanDistance( expr: string, other: ScalarExpr -): EuclideanDistance; +): FirestoreFunction; /** * @beta @@ -7899,7 +6512,7 @@ export function euclideanDistance( export function euclideanDistance( expr: ScalarExpr, other: number[] -): EuclideanDistance; +): FirestoreFunction; /** * @beta @@ -7918,7 +6531,7 @@ export function euclideanDistance( export function euclideanDistance( expr: ScalarExpr, other: VectorValue -): EuclideanDistance; +): FirestoreFunction; /** * @beta @@ -7937,14 +6550,137 @@ export function euclideanDistance( export function euclideanDistance( expr: ScalarExpr, other: ScalarExpr -): EuclideanDistance; +): FirestoreFunction; export function euclideanDistance( expr: ScalarExpr | string, other: ScalarExpr | number[] | VectorValue -): EuclideanDistance { - const expr1 = expr instanceof ScalarExpr ? expr : Field.of(expr); - const expr2 = other instanceof ScalarExpr ? other : Constant.vector(other); - return new EuclideanDistance(expr1, expr2); +): FirestoreFunction { + const expr1 = fieldOfOrExpr(expr); + const expr2 = vectorToExpr(other); + return expr1.euclideanDistance(expr2); +} + +/** + * @beta + * + * Calculates the Manhattan distance between a field's vector value and a double array. + * + * ```typescript + * // Calculate the Manhattan distance between the 'location' field and a target location + * manhattanDistance("location", [37.7749, -122.4194]); + * ``` + * + * @param field The name of the field containing the first vector. + * @param other The other vector (as an array of doubles) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ +export function manhattanDistance( + field: string, + other: number[] +): FirestoreFunction; + +/** + * @beta + * + * Calculates the Manhattan distance between a field's vector value and a VectorValue. + * + * ```typescript + * // Calculate the Manhattan distance between the 'location' field and a target location + * manhattanDistance("location", new VectorValue([37.7749, -122.4194])); + * ``` + * + * @param expr The name of the field containing the first vector. + * @param other The other vector (as a VectorValue) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ +export function manhattanDistance( + expr: string, + other: VectorValue +): FirestoreFunction; + +/** + * @beta + * + * Calculates the Manhattan distance between a field's vector value and a vector expression. + * + * ```typescript + * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' + * manhattanDistance("pointA", Field.of("pointB")); + * ``` + * + * @param expr The name of the field containing the first vector. + * @param other The other vector (represented as an Expr) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ +export function manhattanDistance( + expr: string, + other: ScalarExpr +): FirestoreFunction; + +/** + * @beta + * + * Calculates the Manhattan distance between a vector expression and a double array. + * + * ```typescript + * // Calculate the Manhattan distance between the 'location' field and a target location + * + * manhattanDistance(Field.of("location"), [37.7749, -122.4194]); + * ``` + * + * @param expr The first vector (represented as an Expr) to compare against. + * @param other The other vector (as an array of doubles) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ +export function manhattanDistance( + expr: ScalarExpr, + other: number[] +): FirestoreFunction; + +/** + * @beta + * + * Calculates the Manhattan distance between a vector expression and a VectorValue. + * + * ```typescript + * // Calculate the Manhattan distance between the 'location' field and a target location + * manhattanDistance(Field.of("location"), new VectorValue([37.7749, -122.4194])); + * ``` + * + * @param expr The first vector (represented as an Expr) to compare against. + * @param other The other vector (as a VectorValue) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ +export function manhattanDistance( + expr: ScalarExpr, + other: VectorValue +): FirestoreFunction; + +/** + * @beta + * + * Calculates the Manhattan distance between two vector expressions. + * + * ```typescript + * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' + * manhattanDistance(Field.of("pointA"), Field.of("pointB")); + * ``` + * + * @param expr The first vector (represented as an Expr) to compare against. + * @param other The other vector (represented as an Expr) to compare against. + * @return A new {@code Expr} representing the Manhattan distance between the two vectors. + */ +export function manhattanDistance( + expr: ScalarExpr, + other: ScalarExpr +): FirestoreFunction; +export function manhattanDistance( + fieldOrExpr: ScalarExpr | string, + other: ScalarExpr | number[] | VectorValue +): FirestoreFunction { + const expr1 = fieldOfOrExpr(fieldOrExpr); + const expr2 = vectorToExpr(other); + return expr1.manhattanDistance(expr2); } /** @@ -7960,7 +6696,7 @@ export function euclideanDistance( * @param expr The expression representing the Firestore Vector. * @return A new {@code Expr} representing the length of the array. */ -export function vectorLength(expr: ScalarExpr): VectorLength; +export function vectorLength(expr: ScalarExpr): FirestoreFunction; /** * @beta @@ -7975,10 +6711,9 @@ export function vectorLength(expr: ScalarExpr): VectorLength; * @param field The name of the field representing the Firestore Vector. * @return A new {@code Expr} representing the length of the array. */ -export function vectorLength(field: string): VectorLength; -export function vectorLength(expr: ScalarExpr | string): VectorLength { - const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; - return new VectorLength(normalizedExpr); +export function vectorLength(field: string): FirestoreFunction; +export function vectorLength(expr: ScalarExpr | string): FirestoreFunction { + return fieldOfOrExpr(expr).vectorLength(); } /** @@ -7995,7 +6730,7 @@ export function vectorLength(expr: ScalarExpr | string): VectorLength { * @param expr The expression representing the number of microseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMicrosToTimestamp(expr: ScalarExpr): UnixMicrosToTimestamp; +export function unixMicrosToTimestamp(expr: ScalarExpr): FirestoreFunction; /** * @beta @@ -8011,12 +6746,11 @@ export function unixMicrosToTimestamp(expr: ScalarExpr): UnixMicrosToTimestamp; * @param field The name of the field representing the number of microseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; +export function unixMicrosToTimestamp(field: string): FirestoreFunction; export function unixMicrosToTimestamp( expr: ScalarExpr | string -): UnixMicrosToTimestamp { - const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; - return new UnixMicrosToTimestamp(normalizedExpr); +): FirestoreFunction { + return fieldOfOrExpr(expr).unixMicrosToTimestamp(); } /** @@ -8032,7 +6766,7 @@ export function unixMicrosToTimestamp( * @param expr The expression representing the timestamp. * @return A new {@code Expr} representing the number of microseconds since epoch. */ -export function timestampToUnixMicros(expr: ScalarExpr): TimestampToUnixMicros; +export function timestampToUnixMicros(expr: ScalarExpr): FirestoreFunction; /** * @beta @@ -8047,12 +6781,11 @@ export function timestampToUnixMicros(expr: ScalarExpr): TimestampToUnixMicros; * @param field The name of the field representing the timestamp. * @return A new {@code Expr} representing the number of microseconds since epoch. */ -export function timestampToUnixMicros(field: string): TimestampToUnixMicros; +export function timestampToUnixMicros(field: string): FirestoreFunction; export function timestampToUnixMicros( expr: ScalarExpr | string -): TimestampToUnixMicros { - const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; - return new TimestampToUnixMicros(normalizedExpr); +): FirestoreFunction { + return fieldOfOrExpr(expr).timestampToUnixMicros(); } /** @@ -8069,7 +6802,7 @@ export function timestampToUnixMicros( * @param expr The expression representing the number of milliseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMillisToTimestamp(expr: ScalarExpr): UnixMillisToTimestamp; +export function unixMillisToTimestamp(expr: ScalarExpr): FirestoreFunction; /** * @beta @@ -8085,12 +6818,12 @@ export function unixMillisToTimestamp(expr: ScalarExpr): UnixMillisToTimestamp; * @param field The name of the field representing the number of milliseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; +export function unixMillisToTimestamp(field: string): FirestoreFunction; export function unixMillisToTimestamp( expr: ScalarExpr | string -): UnixMillisToTimestamp { - const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; - return new UnixMillisToTimestamp(normalizedExpr); +): FirestoreFunction { + const normalizedExpr = fieldOfOrExpr(expr); + return normalizedExpr.unixMillisToTimestamp(); } /** @@ -8106,7 +6839,7 @@ export function unixMillisToTimestamp( * @param expr The expression representing the timestamp. * @return A new {@code Expr} representing the number of milliseconds since epoch. */ -export function timestampToUnixMillis(expr: ScalarExpr): TimestampToUnixMillis; +export function timestampToUnixMillis(expr: ScalarExpr): FirestoreFunction; /** * @beta @@ -8121,12 +6854,12 @@ export function timestampToUnixMillis(expr: ScalarExpr): TimestampToUnixMillis; * @param field The name of the field representing the timestamp. * @return A new {@code Expr} representing the number of milliseconds since epoch. */ -export function timestampToUnixMillis(field: string): TimestampToUnixMillis; +export function timestampToUnixMillis(field: string): FirestoreFunction; export function timestampToUnixMillis( expr: ScalarExpr | string -): TimestampToUnixMillis { - const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; - return new TimestampToUnixMillis(normalizedExpr); +): FirestoreFunction { + const normalizedExpr = fieldOfOrExpr(expr); + return normalizedExpr.timestampToUnixMillis(); } /** @@ -8143,9 +6876,7 @@ export function timestampToUnixMillis( * @param expr The expression representing the number of seconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixSecondsToTimestamp( - expr: ScalarExpr -): UnixSecondsToTimestamp; +export function unixSecondsToTimestamp(expr: ScalarExpr): FirestoreFunction; /** * @beta @@ -8161,12 +6892,12 @@ export function unixSecondsToTimestamp( * @param field The name of the field representing the number of seconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; +export function unixSecondsToTimestamp(field: string): FirestoreFunction; export function unixSecondsToTimestamp( expr: ScalarExpr | string -): UnixSecondsToTimestamp { - const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; - return new UnixSecondsToTimestamp(normalizedExpr); +): FirestoreFunction { + const normalizedExpr = fieldOfOrExpr(expr); + return normalizedExpr.unixSecondsToTimestamp(); } /** @@ -8182,9 +6913,7 @@ export function unixSecondsToTimestamp( * @param expr The expression representing the timestamp. * @return A new {@code Expr} representing the number of seconds since epoch. */ -export function timestampToUnixSeconds( - expr: ScalarExpr -): TimestampToUnixSeconds; +export function timestampToUnixSeconds(expr: ScalarExpr): FirestoreFunction; /** * @beta @@ -8199,12 +6928,12 @@ export function timestampToUnixSeconds( * @param field The name of the field representing the timestamp. * @return A new {@code Expr} representing the number of seconds since epoch. */ -export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; +export function timestampToUnixSeconds(field: string): FirestoreFunction; export function timestampToUnixSeconds( expr: ScalarExpr | string -): TimestampToUnixSeconds { - const normalizedExpr = typeof expr === 'string' ? Field.of(expr) : expr; - return new TimestampToUnixSeconds(normalizedExpr); +): FirestoreFunction { + const normalizedExpr = fieldOfOrExpr(expr); + return normalizedExpr.timestampToUnixSeconds(); } /** @@ -8226,7 +6955,7 @@ export function timestampAdd( timestamp: ScalarExpr, unit: ScalarExpr, amount: ScalarExpr -): TimestampAdd; +): FirestoreFunction; /** * @beta @@ -8247,7 +6976,7 @@ export function timestampAdd( timestamp: ScalarExpr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number -): TimestampAdd; +): FirestoreFunction; /** * @beta @@ -8268,7 +6997,7 @@ export function timestampAdd( field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number -): TimestampAdd; +): FirestoreFunction; export function timestampAdd( timestamp: ScalarExpr | string, unit: @@ -8280,18 +7009,11 @@ export function timestampAdd( | 'hour' | 'day', amount: ScalarExpr | number -): TimestampAdd { - const normalizedTimestamp = - typeof timestamp === 'string' ? Field.of(timestamp) : timestamp; - const normalizedUnit = - unit instanceof ScalarExpr ? unit : valueToDefaultExpr(unit); - const normalizedAmount = - typeof amount === 'number' ? Constant.of(amount) : amount; - return new TimestampAdd( - normalizedTimestamp, - normalizedUnit, - normalizedAmount - ); +): FirestoreFunction { + const normalizedTimestamp = fieldOfOrExpr(timestamp); + const normalizedUnit = valueToDefaultExpr(unit); + const normalizedAmount = valueToDefaultExpr(amount); + return normalizedTimestamp.timestampAdd(normalizedUnit, normalizedAmount); } /** @@ -8313,7 +7035,7 @@ export function timestampSub( timestamp: ScalarExpr, unit: ScalarExpr, amount: ScalarExpr -): TimestampSub; +): FirestoreFunction; /** * @beta @@ -8334,7 +7056,7 @@ export function timestampSub( timestamp: ScalarExpr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number -): TimestampSub; +): FirestoreFunction; /** * @beta @@ -8355,7 +7077,7 @@ export function timestampSub( field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number -): TimestampSub; +): FirestoreFunction; export function timestampSub( timestamp: ScalarExpr | string, unit: @@ -8367,18 +7089,11 @@ export function timestampSub( | 'hour' | 'day', amount: ScalarExpr | number -): TimestampSub { - const normalizedTimestamp = - typeof timestamp === 'string' ? Field.of(timestamp) : timestamp; - const normalizedUnit = - unit instanceof ScalarExpr ? unit : valueToDefaultExpr(unit); - const normalizedAmount = - typeof amount === 'number' ? Constant.of(amount) : amount; - return new TimestampSub( - normalizedTimestamp, - normalizedUnit, - normalizedAmount - ); +): FirestoreFunction { + const normalizedTimestamp = fieldOfOrExpr(timestamp); + const normalizedUnit = valueToDefaultExpr(unit); + const normalizedAmount = valueToDefaultExpr(amount); + return normalizedTimestamp.timestampSub(normalizedUnit, normalizedAmount); } /** @@ -8464,8 +7179,8 @@ export function andFunction( first: BooleanExpr, second: BooleanExpr, ...more: BooleanExpr[] -): And { - return new And([first, second, ...more]); +): BooleanExpr { + return new BooleanExpr('and', [first, second, ...more]); } /** @@ -8488,8 +7203,8 @@ export function orFunction( first: BooleanExpr, second: BooleanExpr, ...more: BooleanExpr[] -): Or { - return new Or([first, second, ...more]); +): BooleanExpr { + return new BooleanExpr('or', [first, second, ...more]); } /** diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index 112753ffd74..88c5e2d8d7a 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -35,7 +35,8 @@ import { ScalarExpr, Field, BooleanExpr, - Ordering, Expr + Ordering, + Expr } from './expressions'; import { Pipeline } from './pipeline'; import { DocumentReference } from './reference'; @@ -491,10 +492,7 @@ export class GenericStage implements Stage { * @private * @internal */ - constructor( - public name: string, - private params: Array - ) {} + constructor(public name: string, private params: Expr[]) {} /** * @internal diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 17d4aa08865..210a990d755 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -1473,7 +1473,7 @@ apiDescribe.only('Pipelines', persistence => { .limit(1) .select( Field.of('rating').isNull().as('ratingIsNull'), - Field.of('rating').isNaN().as('ratingIsNaN'), + Field.of('rating').isNan().as('ratingIsNaN'), arrayOffset('title', 0).isError().as('isError'), arrayOffset('title', 0) .ifError(Constant.of('was error')) From c40ea1257ee76a8260f18ed2c409c2ef72457c0f Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Tue, 25 Feb 2025 15:44:09 -0700 Subject: [PATCH 35/75] Separate scalar expressions and aggregate functions into different class hierarchies --- packages/firestore/src/api_pipelines.ts | 2 +- .../firestore/src/lite-api/expressions.ts | 991 ++++++++---------- packages/firestore/src/lite-api/pipeline.ts | 39 +- packages/firestore/src/lite-api/stage.ts | 22 +- .../src/lite-api/user_data_reader.ts | 7 +- 5 files changed, 457 insertions(+), 604 deletions(-) diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index aab25707d0c..1e1b118ef9e 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -161,7 +161,7 @@ export { Key, Substr, ManhattanDistance, - ScalarExpr, + Expr, ExprWithAlias, Field, Constant, diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index a8be6ad60ed..b9b8f75cdeb 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -68,8 +68,8 @@ export type ExprType = * @internal * @param value */ -function valueToDefaultExpr(value: any): ScalarExpr { - if (value instanceof ScalarExpr) { +function valueToDefaultExpr(value: any): Expr { + if (value instanceof Expr) { return value; } else if (isPlainObject(value)) { return map(value); @@ -87,8 +87,8 @@ function valueToDefaultExpr(value: any): ScalarExpr { * @internal * @param value */ -function vectorToExpr(value: VectorValue | number[] | ScalarExpr): ScalarExpr { - if (value instanceof ScalarExpr) { +function vectorToExpr(value: VectorValue | number[] | Expr): Expr { + if (value instanceof Expr) { return value; } else { return Constant.vector(value); @@ -105,7 +105,7 @@ function vectorToExpr(value: VectorValue | number[] | ScalarExpr): ScalarExpr { * @internal * @param value */ -function fieldOfOrExpr(value: any): ScalarExpr { +function fieldOfOrExpr(value: any): Expr { if (isString(value)) { return Field.of(value); } else { @@ -125,7 +125,6 @@ function fieldOfOrExpr(value: any): ScalarExpr { * - **Field references:** Access values from document fields. * - **Literals:** Represent constant values (strings, numbers, booleans). * - **Function calls:** Apply functions to one or more expressions. - * - **Aggregations:** Calculate aggregate values (e.g., sum, average) over a set of documents. * * The `Expr` class provides a fluent API for building expressions. You can chain together * method calls to create complex expressions. @@ -144,26 +143,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @internal */ abstract _readUserData(dataReader: UserDataReader): void; -} -/** - * @beta - * - * Represents an expression that can be evaluated to a value within the execution of a {@link - * Pipeline}. - * - * Expressions are the building blocks for creating complex queries and transformations in - * Firestore pipelines. They can represent: - * - * - **Field references:** Access values from document fields. - * - **Literals:** Represent constant values (strings, numbers, booleans). - * - **Function calls:** Apply functions to one or more expressions. - * - **Aggregations:** Calculate aggregate values (e.g., sum, average) over a set of documents. - * - * The `Expr` class provides a fluent API for building expressions. You can chain together - * method calls to create complex expressions. - */ -export abstract class ScalarExpr extends Expr { /** * Creates an expression that adds this expression to another expression. * @@ -176,10 +156,7 @@ export abstract class ScalarExpr extends Expr { * @param others Optional additional expressions or literals to add to this expression. * @return A new `Expr` representing the addition operation. */ - add( - second: ScalarExpr | any, - ...others: Array - ): FirestoreFunction { + add(second: Expr | any, ...others: Array): FirestoreFunction { const values = [second, ...others]; return new FirestoreFunction('add', [ this, @@ -198,7 +175,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to subtract from this expression. * @return A new `Expr` representing the subtraction operation. */ - subtract(other: ScalarExpr): FirestoreFunction; + subtract(other: Expr): FirestoreFunction; /** * Creates an expression that subtracts a constant value from this expression. @@ -229,8 +206,8 @@ export abstract class ScalarExpr extends Expr { * @return A new `Expr` representing the multiplication operation. */ multiply( - second: ScalarExpr | any, - ...others: Array + second: Expr | any, + ...others: Array ): FirestoreFunction { return new FirestoreFunction('multiply', [ this, @@ -250,7 +227,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to divide by. * @return A new `Expr` representing the division operation. */ - divide(other: ScalarExpr): FirestoreFunction; + divide(other: Expr): FirestoreFunction; /** * Creates an expression that divides this expression by a constant value. @@ -279,7 +256,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to divide by. * @return A new `Expr` representing the modulo operation. */ - mod(other: ScalarExpr): FirestoreFunction; + mod(other: Expr): FirestoreFunction; /** * Creates an expression that calculates the modulo (remainder) of dividing this expression by a constant value. @@ -308,7 +285,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to compare for equality. * @return A new `Expr` representing the equality comparison. */ - eq(other: ScalarExpr): BooleanExpr; + eq(other: Expr): BooleanExpr; /** * Creates an expression that checks if this expression is equal to a constant value. @@ -337,7 +314,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to compare for inequality. * @return A new `Expr` representing the inequality comparison. */ - neq(other: ScalarExpr): BooleanExpr; + neq(other: Expr): BooleanExpr; /** * Creates an expression that checks if this expression is not equal to a constant value. @@ -366,7 +343,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to compare for less than. * @return A new `Expr` representing the less than comparison. */ - lt(other: ScalarExpr): BooleanExpr; + lt(other: Expr): BooleanExpr; /** * Creates an expression that checks if this expression is less than a constant value. @@ -396,7 +373,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to compare for less than or equal to. * @return A new `Expr` representing the less than or equal to comparison. */ - lte(other: ScalarExpr): BooleanExpr; + lte(other: Expr): BooleanExpr; /** * Creates an expression that checks if this expression is less than or equal to a constant value. @@ -425,7 +402,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to compare for greater than. * @return A new `Expr` representing the greater than comparison. */ - gt(other: ScalarExpr): BooleanExpr; + gt(other: Expr): BooleanExpr; /** * Creates an expression that checks if this expression is greater than a constant value. @@ -455,7 +432,7 @@ export abstract class ScalarExpr extends Expr { * @param other The expression to compare for greater than or equal to. * @return A new `Expr` representing the greater than or equal to comparison. */ - gte(other: ScalarExpr): BooleanExpr; + gte(other: Expr): BooleanExpr; /** * Creates an expression that checks if this expression is greater than or equal to a constant @@ -486,8 +463,8 @@ export abstract class ScalarExpr extends Expr { * @return A new `Expr` representing the concatenated array. */ arrayConcat( - secondArray: ScalarExpr | any[], - ...otherArrays: Array + secondArray: Expr | any[], + ...otherArrays: Array ): FirestoreFunction { const elements = [secondArray, ...otherArrays]; const exprValues = elements.map(value => valueToDefaultExpr(value)); @@ -505,7 +482,7 @@ export abstract class ScalarExpr extends Expr { * @param element The element to search for in the array. * @return A new `Expr` representing the 'array_contains' comparison. */ - arrayContains(element: ScalarExpr): BooleanExpr; + arrayContains(element: Expr): BooleanExpr; /** * Creates an expression that checks if an array contains a specific value. @@ -537,7 +514,7 @@ export abstract class ScalarExpr extends Expr { * @param values The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_all' comparison. */ - arrayContainsAll(...values: ScalarExpr[]): BooleanExpr; + arrayContainsAll(...values: Expr[]): BooleanExpr; /** * Creates an expression that checks if an array contains all the specified elements. @@ -570,7 +547,7 @@ export abstract class ScalarExpr extends Expr { * @param values The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_any' comparison. */ - arrayContainsAny(...values: ScalarExpr[]): BooleanExpr; + arrayContainsAny(...values: Expr[]): BooleanExpr; /** * Creates an expression that checks if an array contains any of the specified elements. @@ -619,7 +596,7 @@ export abstract class ScalarExpr extends Expr { * @param others The values or expressions to check against. * @return A new `Expr` representing the 'IN' comparison. */ - eqAny(...others: ScalarExpr[]): BooleanExpr; + eqAny(...others: Expr[]): BooleanExpr; /** * Creates an expression that checks if this expression is equal to any of the provided values or @@ -651,7 +628,7 @@ export abstract class ScalarExpr extends Expr { * @param others The values or expressions to check against. * @return A new `Expr` representing the 'NotEqAny' comparison. */ - notEqAny(...others: ScalarExpr[]): BooleanExpr; + notEqAny(...others: Expr[]): BooleanExpr; /** * Creates an expression that checks if this expression is not equal to any of the provided values or @@ -751,8 +728,8 @@ export abstract class ScalarExpr extends Expr { * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new `Expr` representing the 'like' comparison. */ - like(pattern: ScalarExpr): FirestoreFunction; - like(stringOrExpr: string | ScalarExpr): FirestoreFunction { + like(pattern: Expr): FirestoreFunction; + like(stringOrExpr: string | Expr): FirestoreFunction { return new FirestoreFunction('like', [ this, valueToDefaultExpr(stringOrExpr) @@ -785,8 +762,8 @@ export abstract class ScalarExpr extends Expr { * @param pattern The regular expression to use for the search. * @return A new `Expr` representing the 'contains' comparison. */ - regexContains(pattern: ScalarExpr): BooleanExpr; - regexContains(stringOrExpr: string | ScalarExpr): BooleanExpr { + regexContains(pattern: Expr): BooleanExpr; + regexContains(stringOrExpr: string | Expr): BooleanExpr { return new BooleanExpr('regex_contains', [ this, valueToDefaultExpr(stringOrExpr) @@ -817,8 +794,8 @@ export abstract class ScalarExpr extends Expr { * @param pattern The regular expression to use for the match. * @return A new `Expr` representing the regular expression match. */ - regexMatch(pattern: ScalarExpr): BooleanExpr; - regexMatch(stringOrExpr: string | ScalarExpr): BooleanExpr { + regexMatch(pattern: Expr): BooleanExpr; + regexMatch(stringOrExpr: string | Expr): BooleanExpr { return new BooleanExpr('regex_match', [ this, valueToDefaultExpr(stringOrExpr) @@ -849,8 +826,8 @@ export abstract class ScalarExpr extends Expr { * @param expr The expression representing the substring to search for. * @return A new `Expr` representing the 'contains' comparison. */ - strContains(expr: ScalarExpr): BooleanExpr; - strContains(stringOrExpr: string | ScalarExpr): BooleanExpr { + strContains(expr: Expr): BooleanExpr; + strContains(stringOrExpr: string | Expr): BooleanExpr { return new BooleanExpr('str_contains', [ this, valueToDefaultExpr(stringOrExpr) @@ -882,8 +859,8 @@ export abstract class ScalarExpr extends Expr { * @param prefix The prefix expression to check for. * @return A new `Expr` representing the 'starts with' comparison. */ - startsWith(prefix: ScalarExpr): BooleanExpr; - startsWith(stringOrExpr: string | ScalarExpr): BooleanExpr { + startsWith(prefix: Expr): BooleanExpr; + startsWith(stringOrExpr: string | Expr): BooleanExpr { return new BooleanExpr('starts_with', [ this, valueToDefaultExpr(stringOrExpr) @@ -915,8 +892,8 @@ export abstract class ScalarExpr extends Expr { * @param suffix The postfix expression to check for. * @return A new `Expr` representing the 'ends with' comparison. */ - endsWith(suffix: ScalarExpr): BooleanExpr; - endsWith(stringOrExpr: string | ScalarExpr): BooleanExpr { + endsWith(suffix: Expr): BooleanExpr; + endsWith(stringOrExpr: string | Expr): BooleanExpr { return new BooleanExpr('ends_with', [ this, valueToDefaultExpr(stringOrExpr) @@ -978,8 +955,8 @@ export abstract class ScalarExpr extends Expr { * @return A new `Expr` representing the concatenated string. */ strConcat( - secondString: ScalarExpr | string, - ...otherStrings: Array + secondString: Expr | string, + ...otherStrings: Array ): FirestoreFunction { const elements = [secondString, ...otherStrings]; const exprs = elements.map(valueToDefaultExpr); @@ -1027,11 +1004,8 @@ export abstract class ScalarExpr extends Expr { * @param replace The expression representing the substring to replace the first occurrence of 'find' with. * @return A new {@code Expr} representing the string with the first occurrence replaced. */ - replaceFirst(find: ScalarExpr, replace: ScalarExpr): FirestoreFunction; - replaceFirst( - find: ScalarExpr | string, - replace: ScalarExpr | string - ): FirestoreFunction { + replaceFirst(find: Expr, replace: Expr): FirestoreFunction; + replaceFirst(find: Expr | string, replace: Expr | string): FirestoreFunction { return new FirestoreFunction('replace_first', [ this, valueToDefaultExpr(find), @@ -1066,11 +1040,8 @@ export abstract class ScalarExpr extends Expr { * @param replace The expression representing the substring to replace all occurrences of 'find' with. * @return A new {@code Expr} representing the string with all occurrences replaced. */ - replaceAll(find: ScalarExpr, replace: ScalarExpr): FirestoreFunction; - replaceAll( - find: ScalarExpr | string, - replace: ScalarExpr | string - ): FirestoreFunction { + replaceAll(find: Expr, replace: Expr): FirestoreFunction; + replaceAll(find: Expr | string, replace: Expr | string): FirestoreFunction { return new FirestoreFunction('replace_all', [ this, valueToDefaultExpr(find), @@ -1192,8 +1163,8 @@ export abstract class ScalarExpr extends Expr { * @return A new {@code Expr} representing the logical max operation. */ logicalMaximum( - second: ScalarExpr | any, - ...others: Array + second: Expr | any, + ...others: Array ): FirestoreFunction { const values = [second, ...others]; return new FirestoreFunction('logical_maximum', [ @@ -1215,8 +1186,8 @@ export abstract class ScalarExpr extends Expr { * @return A new {@code Expr} representing the logical min operation. */ logicalMinimum( - second: ScalarExpr | any, - ...others: Array + second: Expr | any, + ...others: Array ): FirestoreFunction { const values = [second, ...others]; return new FirestoreFunction('logical_min', [ @@ -1250,7 +1221,7 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (represented as an Expr) to compare against. * @return A new `Expr` representing the cosine distance between the two vectors. */ - cosineDistance(other: ScalarExpr): FirestoreFunction; + cosineDistance(other: Expr): FirestoreFunction; /** * Calculates the Cosine distance between two vectors. * @@ -1275,9 +1246,7 @@ export abstract class ScalarExpr extends Expr { * @return A new `Expr` representing the Cosine distance between the two vectors. */ cosineDistance(other: number[]): FirestoreFunction; - cosineDistance( - other: ScalarExpr | VectorValue | number[] - ): FirestoreFunction { + cosineDistance(other: Expr | VectorValue | number[]): FirestoreFunction { return new FirestoreFunction('cosine_distance', [ this, vectorToExpr(other) @@ -1295,7 +1264,7 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the dot product between the two vectors. */ - dotProduct(other: ScalarExpr): FirestoreFunction; + dotProduct(other: Expr): FirestoreFunction; /** * Calculates the dot product between two vectors. @@ -1322,7 +1291,7 @@ export abstract class ScalarExpr extends Expr { * @return A new `Expr` representing the dot product between the two vectors. */ dotProduct(other: number[]): FirestoreFunction; - dotProduct(other: ScalarExpr | VectorValue | number[]): FirestoreFunction { + dotProduct(other: Expr | VectorValue | number[]): FirestoreFunction { return new FirestoreFunction('dot_product', [this, vectorToExpr(other)]); } @@ -1337,7 +1306,7 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the Euclidean distance between the two vectors. */ - euclideanDistance(other: ScalarExpr): FirestoreFunction; + euclideanDistance(other: Expr): FirestoreFunction; /** * Calculates the Euclidean distance between two vectors. @@ -1364,9 +1333,7 @@ export abstract class ScalarExpr extends Expr { * @return A new `Expr` representing the Euclidean distance between the two vectors. */ euclideanDistance(other: number[]): FirestoreFunction; - euclideanDistance( - other: ScalarExpr | VectorValue | number[] - ): FirestoreFunction { + euclideanDistance(other: Expr | VectorValue | number[]): FirestoreFunction { return new FirestoreFunction('euclidean_distance', [ this, vectorToExpr(other) @@ -1415,10 +1382,8 @@ export abstract class ScalarExpr extends Expr { * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ - manhattanDistance(other: ScalarExpr): FirestoreFunction; - manhattanDistance( - other: ScalarExpr | number[] | VectorValue - ): FirestoreFunction { + manhattanDistance(other: Expr): FirestoreFunction; + manhattanDistance(other: Expr | number[] | VectorValue): FirestoreFunction { return new FirestoreFunction('manhattan_distance', [ this, vectorToExpr(other) @@ -1524,7 +1489,7 @@ export abstract class ScalarExpr extends Expr { * @param amount The expression evaluates to amount of the unit. * @return A new {@code Expr} representing the resulting timestamp. */ - timestampAdd(unit: ScalarExpr, amount: ScalarExpr): FirestoreFunction; + timestampAdd(unit: Expr, amount: Expr): FirestoreFunction; /** * Creates an expression that adds a specified amount of time to this timestamp expression. @@ -1544,14 +1509,14 @@ export abstract class ScalarExpr extends Expr { ): FirestoreFunction; timestampAdd( unit: - | ScalarExpr + | Expr | 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', - amount: ScalarExpr | number + amount: Expr | number ): FirestoreFunction { return new FirestoreFunction('timestamp_add', [ this, @@ -1572,7 +1537,7 @@ export abstract class ScalarExpr extends Expr { * @param amount The expression evaluates to amount of the unit. * @return A new {@code Expr} representing the resulting timestamp. */ - timestampSub(unit: ScalarExpr, amount: ScalarExpr): FirestoreFunction; + timestampSub(unit: Expr, amount: Expr): FirestoreFunction; /** * Creates an expression that subtracts a specified amount of time from this timestamp expression. @@ -1592,14 +1557,14 @@ export abstract class ScalarExpr extends Expr { ): FirestoreFunction; timestampSub( unit: - | ScalarExpr + | Expr | 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', - amount: ScalarExpr | number + amount: Expr | number ): FirestoreFunction { return new FirestoreFunction('timestamp_sub', [ this, @@ -1635,8 +1600,8 @@ export abstract class ScalarExpr extends Expr { * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise AND operation. */ - bitAnd(bitsExpression: ScalarExpr): FirestoreFunction; - bitAnd(bitsOrExpression: number | ScalarExpr | Bytes): FirestoreFunction { + bitAnd(bitsExpression: Expr): FirestoreFunction; + bitAnd(bitsOrExpression: number | Expr | Bytes): FirestoreFunction { return new FirestoreFunction('bit_and', [ this, valueToDefaultExpr(bitsOrExpression) @@ -1670,8 +1635,8 @@ export abstract class ScalarExpr extends Expr { * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise OR operation. */ - bitOr(bitsExpression: ScalarExpr): FirestoreFunction; - bitOr(bitsOrExpression: number | ScalarExpr | Bytes): FirestoreFunction { + bitOr(bitsExpression: Expr): FirestoreFunction; + bitOr(bitsOrExpression: number | Expr | Bytes): FirestoreFunction { return new FirestoreFunction('bit_or', [ this, valueToDefaultExpr(bitsOrExpression) @@ -1705,8 +1670,8 @@ export abstract class ScalarExpr extends Expr { * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise XOR operation. */ - bitXor(bitsExpression: ScalarExpr): FirestoreFunction; - bitXor(bitsOrExpression: number | ScalarExpr | Bytes): FirestoreFunction { + bitXor(bitsExpression: Expr): FirestoreFunction; + bitXor(bitsOrExpression: number | Expr | Bytes): FirestoreFunction { return new FirestoreFunction('bit_xor', [ this, valueToDefaultExpr(bitsOrExpression) @@ -1756,8 +1721,8 @@ export abstract class ScalarExpr extends Expr { * @param numberExpr The operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ - bitLeftShift(numberExpr: ScalarExpr): FirestoreFunction; - bitLeftShift(numberExpr: number | ScalarExpr): FirestoreFunction { + bitLeftShift(numberExpr: Expr): FirestoreFunction; + bitLeftShift(numberExpr: number | Expr): FirestoreFunction { return new FirestoreFunction('bit_left_shift', [ this, valueToDefaultExpr(numberExpr) @@ -1791,8 +1756,8 @@ export abstract class ScalarExpr extends Expr { * @param numberExpr The operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ - bitRightShift(numberExpr: ScalarExpr): FirestoreFunction; - bitRightShift(numberExpr: number | ScalarExpr): FirestoreFunction { + bitRightShift(numberExpr: Expr): FirestoreFunction; + bitRightShift(numberExpr: number | Expr): FirestoreFunction { return new FirestoreFunction('bit_right_shift', [ this, valueToDefaultExpr(numberExpr) @@ -1835,11 +1800,8 @@ export abstract class ScalarExpr extends Expr { * @param length An expression returning the length of the substring. If not provided the * substring will end at the end of the input. */ - substr(position: ScalarExpr, length?: ScalarExpr): FirestoreFunction; - substr( - position: ScalarExpr | number, - length?: ScalarExpr | number - ): FirestoreFunction { + substr(position: Expr, length?: Expr): FirestoreFunction; + substr(position: Expr | number, length?: Expr | number): FirestoreFunction { const positionExpr = valueToDefaultExpr(position); if (length === undefined) { return new FirestoreFunction('substr', [this, positionExpr]); @@ -1883,8 +1845,8 @@ export abstract class ScalarExpr extends Expr { * @param offsetExpr An Expr evaluating to the index of the element to return. * @return A new Expr representing the 'arrayOffset' operation. */ - arrayOffset(offsetExpr: ScalarExpr): FirestoreFunction; - arrayOffset(offset: ScalarExpr | number): FirestoreFunction { + arrayOffset(offsetExpr: Expr): FirestoreFunction; + arrayOffset(offset: Expr | number): FirestoreFunction { return new FirestoreFunction('array_offset', [ this, valueToDefaultExpr(offset) @@ -1923,7 +1885,7 @@ export abstract class ScalarExpr extends Expr { * returned if this expression produces an error. * @return A new {@code Expr} representing the 'ifError' operation. */ - ifError(catchExpr: ScalarExpr): FirestoreFunction; + ifError(catchExpr: Expr): FirestoreFunction; /** * @beta @@ -2025,8 +1987,8 @@ export abstract class ScalarExpr extends Expr { * @param keyExpr An expression that produces the name of the key to remove from the input map. * @returns A new {@code FirestoreFunction} representing the 'mapRemove' operation. */ - mapRemove(keyExpr: ScalarExpr): FirestoreFunction; - mapRemove(stringExpr: ScalarExpr | string): FirestoreFunction { + mapRemove(keyExpr: Expr): FirestoreFunction; + mapRemove(stringExpr: Expr | string): FirestoreFunction { return new FirestoreFunction('map_remove', [ this, valueToDefaultExpr(stringExpr) @@ -2052,8 +2014,8 @@ export abstract class ScalarExpr extends Expr { * @returns A new {@code FirestoreFunction} representing the 'mapMerge' operation. */ mapMerge( - secondMap: Record | ScalarExpr, - ...otherMaps: Array | ScalarExpr> + secondMap: Record | Expr, + ...otherMaps: Array | Expr> ): FirestoreFunction { const secondMapExpr = valueToDefaultExpr(secondMap); const otherMapExprs = otherMaps.map(valueToDefaultExpr); @@ -2123,20 +2085,26 @@ export abstract class ScalarExpr extends Expr { export interface Selectable { selectable: true; readonly alias: string; - readonly expr: ScalarExpr; + readonly expr: Expr; +} + +export function _isSelectable(value: any): value is Selectable { + return value.selectable && + typeof value.alias === 'string' && + value.expr instanceof Expr; } /** * @beta * - * An class that represents an aggregate function. + * A class that represents an aggregate function. */ -export class AggregateFunction extends Expr { +export class AggregateFunction + implements ProtoSerializable, UserData +{ exprType: ExprType = 'AggregateFunction'; - constructor(private name: string, private params: ScalarExpr[]) { - super(); - } + constructor(private name: string, private params: Expr[]) {} /** * Assigns an alias to this AggregateFunction. The alias specifies the name that @@ -2214,7 +2182,7 @@ export class ExprWithAlias implements Selectable, UserData { exprType: ExprType = 'ExprWithAlias'; selectable = true as const; - constructor(readonly expr: ScalarExpr, readonly alias: string) {} + constructor(readonly expr: Expr, readonly alias: string) {} /** * @private @@ -2228,10 +2196,10 @@ export class ExprWithAlias implements Selectable, UserData { /** * @internal */ -class ListOfExprs extends ScalarExpr { +class ListOfExprs extends Expr { exprType: ExprType = 'ListOfExprs'; - constructor(private exprs: ScalarExpr[]) { + constructor(private exprs: Expr[]) { super(); } @@ -2252,7 +2220,7 @@ class ListOfExprs extends ScalarExpr { * @internal */ _readUserData(dataReader: UserDataReader): void { - this.exprs.forEach((expr: ScalarExpr) => expr._readUserData(dataReader)); + this.exprs.forEach((expr: Expr) => expr._readUserData(dataReader)); } } @@ -2274,7 +2242,7 @@ class ListOfExprs extends ScalarExpr { * const cityField = Field.of("address.city"); * ``` */ -export class Field extends ScalarExpr implements Selectable { +export class Field extends Expr implements Selectable { exprType: ExprType = 'Field'; selectable = true as const; @@ -2323,7 +2291,7 @@ export class Field extends ScalarExpr implements Selectable { return this.fieldName(); } - get expr(): ScalarExpr { + get expr(): Expr { return this; } @@ -2359,7 +2327,7 @@ export class Field extends ScalarExpr implements Selectable { * const hello = Constant.of("hello"); * ``` */ -export class Constant extends ScalarExpr { +export class Constant extends Expr { exprType: ExprType = 'Constant'; private _protoValue?: ProtoValue; @@ -2555,8 +2523,8 @@ export class Constant extends ScalarExpr { * @internal * @private */ -export class MapValue extends ScalarExpr { - constructor(private plainObject: Map) { +export class MapValue extends Expr { + constructor(private plainObject: Map) { super(); } @@ -2580,12 +2548,12 @@ export class MapValue extends ScalarExpr { * execution. * * Typically, you would not use this class or its children directly. Use either the functions like {@link and}, {@link eq}, - * or the methods on {@link ScalarExpr} ({@link ScalarExpr#eq}, {@link ScalarExpr#lt}, etc) to construct new Function instances. + * or the methods on {@link Expr} ({@link Expr#eq}, {@link Expr#lt}, etc) to construct new Function instances. */ -export class FirestoreFunction extends ScalarExpr { +export class FirestoreFunction extends Expr { exprType: ExprType = 'Function'; - constructor(private name: string, private params: ScalarExpr[]) { + constructor(private name: string, private params: Expr[]) { super(); } @@ -2711,10 +2679,7 @@ export function bitAnd( * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise AND operation. */ -export function bitAnd( - field: string, - bitsExpression: ScalarExpr -): FirestoreFunction; +export function bitAnd(field: string, bitsExpression: Expr): FirestoreFunction; /** * @beta * @@ -2730,7 +2695,7 @@ export function bitAnd( * @return A new {@code Expr} representing the bitwise AND operation. */ export function bitAnd( - bitsExpression: ScalarExpr, + bitsExpression: Expr, otherBits: number | Bytes ): FirestoreFunction; /** @@ -2748,12 +2713,12 @@ export function bitAnd( * @return A new {@code Expr} representing the bitwise AND operation. */ export function bitAnd( - bitsExpression: ScalarExpr, - otherBitsExpression: ScalarExpr + bitsExpression: Expr, + otherBitsExpression: Expr ): FirestoreFunction; export function bitAnd( - fieldOrExpression: string | ScalarExpr, - bitsOrExpression: number | ScalarExpr | Bytes + fieldOrExpression: string | Expr, + bitsOrExpression: number | Expr | Bytes ): FirestoreFunction { return fieldOfOrExpr(fieldOrExpression).bitAnd( valueToDefaultExpr(bitsOrExpression) @@ -2792,10 +2757,7 @@ export function bitOr( * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise OR operation. */ -export function bitOr( - field: string, - bitsExpression: ScalarExpr -): FirestoreFunction; +export function bitOr(field: string, bitsExpression: Expr): FirestoreFunction; /** * @beta * @@ -2811,7 +2773,7 @@ export function bitOr( * @return A new {@code Expr} representing the bitwise OR operation. */ export function bitOr( - bitsExpression: ScalarExpr, + bitsExpression: Expr, otherBits: number | Bytes ): FirestoreFunction; /** @@ -2829,12 +2791,12 @@ export function bitOr( * @return A new {@code Expr} representing the bitwise OR operation. */ export function bitOr( - bitsExpression: ScalarExpr, - otherBitsExpression: ScalarExpr + bitsExpression: Expr, + otherBitsExpression: Expr ): FirestoreFunction; export function bitOr( - fieldOrExpression: string | ScalarExpr, - bitsOrExpression: number | ScalarExpr | Bytes + fieldOrExpression: string | Expr, + bitsOrExpression: number | Expr | Bytes ): FirestoreFunction { return fieldOfOrExpr(fieldOrExpression).bitOr( valueToDefaultExpr(bitsOrExpression) @@ -2873,10 +2835,7 @@ export function bitXor( * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise XOR operation. */ -export function bitXor( - field: string, - bitsExpression: ScalarExpr -): FirestoreFunction; +export function bitXor(field: string, bitsExpression: Expr): FirestoreFunction; /** * @beta * @@ -2892,7 +2851,7 @@ export function bitXor( * @return A new {@code Expr} representing the bitwise XOR operation. */ export function bitXor( - bitsExpression: ScalarExpr, + bitsExpression: Expr, otherBits: number | Bytes ): FirestoreFunction; /** @@ -2910,12 +2869,12 @@ export function bitXor( * @return A new {@code Expr} representing the bitwise XOR operation. */ export function bitXor( - bitsExpression: ScalarExpr, - otherBitsExpression: ScalarExpr + bitsExpression: Expr, + otherBitsExpression: Expr ): FirestoreFunction; export function bitXor( - fieldOrExpression: string | ScalarExpr, - bitsOrExpression: number | ScalarExpr | Bytes + fieldOrExpression: string | Expr, + bitsOrExpression: number | Expr | Bytes ): FirestoreFunction { return fieldOfOrExpr(fieldOrExpression).bitXor( valueToDefaultExpr(bitsOrExpression) @@ -2949,8 +2908,8 @@ export function bitNot(field: string): FirestoreFunction; * @param bitsValueExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise NOT operation. */ -export function bitNot(bitsValueExpression: ScalarExpr): FirestoreFunction; -export function bitNot(bits: string | ScalarExpr): FirestoreFunction { +export function bitNot(bitsValueExpression: Expr): FirestoreFunction; +export function bitNot(bits: string | Expr): FirestoreFunction { return fieldOfOrExpr(bits).bitNot(); } @@ -2985,7 +2944,7 @@ export function bitLeftShift(field: string, y: number): FirestoreFunction; */ export function bitLeftShift( field: string, - numberExpr: ScalarExpr + numberExpr: Expr ): FirestoreFunction; /** * @beta @@ -3001,7 +2960,7 @@ export function bitLeftShift( * @param y The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ -export function bitLeftShift(xValue: ScalarExpr, y: number): FirestoreFunction; +export function bitLeftShift(xValue: Expr, y: number): FirestoreFunction; /** * @beta * @@ -3016,13 +2975,10 @@ export function bitLeftShift(xValue: ScalarExpr, y: number): FirestoreFunction; * @param right The right operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ +export function bitLeftShift(xValue: Expr, numberExpr: Expr): FirestoreFunction; export function bitLeftShift( - xValue: ScalarExpr, - numberExpr: ScalarExpr -): FirestoreFunction; -export function bitLeftShift( - xValue: string | ScalarExpr, - numberExpr: number | ScalarExpr + xValue: string | Expr, + numberExpr: number | Expr ): FirestoreFunction { return fieldOfOrExpr(xValue).bitLeftShift(valueToDefaultExpr(numberExpr)); } @@ -3058,7 +3014,7 @@ export function bitRightShift(field: string, y: number): FirestoreFunction; */ export function bitRightShift( field: string, - numberExpr: ScalarExpr + numberExpr: Expr ): FirestoreFunction; /** * @beta @@ -3074,7 +3030,7 @@ export function bitRightShift( * @param y The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ -export function bitRightShift(xValue: ScalarExpr, y: number): FirestoreFunction; +export function bitRightShift(xValue: Expr, y: number): FirestoreFunction; /** * @beta * @@ -3090,12 +3046,12 @@ export function bitRightShift(xValue: ScalarExpr, y: number): FirestoreFunction; * @return A new {@code Expr} representing the bitwise right shift operation. */ export function bitRightShift( - xValue: ScalarExpr, - numberExpr: ScalarExpr + xValue: Expr, + numberExpr: Expr ): FirestoreFunction; export function bitRightShift( - xValue: string | ScalarExpr, - numberExpr: number | ScalarExpr + xValue: string | Expr, + numberExpr: number | Expr ): FirestoreFunction { return fieldOfOrExpr(xValue).bitRightShift(valueToDefaultExpr(numberExpr)); } @@ -3138,7 +3094,7 @@ export function arrayOffset( */ export function arrayOffset( arrayField: string, - offsetExpr: ScalarExpr + offsetExpr: Expr ): FirestoreFunction; /** @@ -3157,7 +3113,7 @@ export function arrayOffset( * @return A new Expr representing the 'arrayOffset' operation. */ export function arrayOffset( - arrayExpression: ScalarExpr, + arrayExpression: Expr, offset: number ): FirestoreFunction; @@ -3178,12 +3134,12 @@ export function arrayOffset( * @return A new Expr representing the 'arrayOffset' operation. */ export function arrayOffset( - arrayExpression: ScalarExpr, - offsetExpr: ScalarExpr + arrayExpression: Expr, + offsetExpr: Expr ): FirestoreFunction; export function arrayOffset( - array: ScalarExpr | string, - offset: ScalarExpr | number + array: Expr | string, + offset: Expr | number ): FirestoreFunction { return fieldOfOrExpr(array).arrayOffset(valueToDefaultExpr(offset)); } @@ -3211,7 +3167,7 @@ export function currentContext(): FirestoreFunction { * @param value The expression to check. * @return A new {@code Expr} representing the 'isError' check. */ -export function isError(value: ScalarExpr): BooleanExpr { +export function isError(value: Expr): BooleanExpr { return value.isError(); } @@ -3232,10 +3188,7 @@ export function isError(value: ScalarExpr): BooleanExpr { * returned if the tryExpr produces an error. * @return A new {@code Expr} representing the 'ifError' operation. */ -export function ifError( - tryExpr: ScalarExpr, - catchExpr: ScalarExpr -): FirestoreFunction; +export function ifError(tryExpr: Expr, catchExpr: Expr): FirestoreFunction; /** * @beta @@ -3254,14 +3207,8 @@ export function ifError( * error. * @return A new {@code Expr} representing the 'ifError' operation. */ -export function ifError( - tryExpr: ScalarExpr, - catchValue: any -): FirestoreFunction; -export function ifError( - tryExpr: ScalarExpr, - catchValue: any -): FirestoreFunction { +export function ifError(tryExpr: Expr, catchValue: any): FirestoreFunction; +export function ifError(tryExpr: Expr, catchValue: any): FirestoreFunction { return tryExpr.ifError(valueToDefaultExpr(catchValue)); } @@ -3279,7 +3226,7 @@ export function ifError( * @param value The expression to check. * @return A new {@code Expr} representing the 'isAbsent' check. */ -export function isAbsent(value: ScalarExpr): BooleanExpr; +export function isAbsent(value: Expr): BooleanExpr; /** * @beta @@ -3296,7 +3243,7 @@ export function isAbsent(value: ScalarExpr): BooleanExpr; * @return A new {@code Expr} representing the 'isAbsent' check. */ export function isAbsent(field: string): BooleanExpr; -export function isAbsent(value: ScalarExpr | string): BooleanExpr { +export function isAbsent(value: Expr | string): BooleanExpr { return fieldOfOrExpr(value).isAbsent(); } @@ -3313,7 +3260,7 @@ export function isAbsent(value: ScalarExpr | string): BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNull(value: ScalarExpr): BooleanExpr; +export function isNull(value: Expr): BooleanExpr; /** * @beta @@ -3329,7 +3276,7 @@ export function isNull(value: ScalarExpr): BooleanExpr; * @return A new {@code Expr} representing the 'isNaN' check. */ export function isNull(value: string): BooleanExpr; -export function isNull(value: ScalarExpr | string): BooleanExpr { +export function isNull(value: Expr | string): BooleanExpr { return fieldOfOrExpr(value).isNull(); } @@ -3346,7 +3293,7 @@ export function isNull(value: ScalarExpr | string): BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNotNull(value: ScalarExpr): BooleanExpr; +export function isNotNull(value: Expr): BooleanExpr; /** * @beta @@ -3362,7 +3309,7 @@ export function isNotNull(value: ScalarExpr): BooleanExpr; * @return A new {@code Expr} representing the 'isNaN' check. */ export function isNotNull(value: string): BooleanExpr; -export function isNotNull(value: ScalarExpr | string): BooleanExpr { +export function isNotNull(value: Expr | string): BooleanExpr { return fieldOfOrExpr(value).isNotNull(); } @@ -3379,7 +3326,7 @@ export function isNotNull(value: ScalarExpr | string): BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isNotNaN' check. */ -export function isNotNan(value: ScalarExpr): BooleanExpr; +export function isNotNan(value: Expr): BooleanExpr; /** * @beta @@ -3395,7 +3342,7 @@ export function isNotNan(value: ScalarExpr): BooleanExpr; * @return A new {@code Expr} representing the 'isNotNaN' check. */ export function isNotNan(value: string): BooleanExpr; -export function isNotNan(value: ScalarExpr | string): BooleanExpr { +export function isNotNan(value: Expr | string): BooleanExpr { return fieldOfOrExpr(value).isNotNan(); } @@ -3426,7 +3373,7 @@ export function mapRemove(mapField: string, key: string): FirestoreFunction; * @param mapExpr An expression return a map value. * @param key The name of the key to remove from the input map. */ -export function mapRemove(mapExpr: ScalarExpr, key: string): FirestoreFunction; +export function mapRemove(mapExpr: Expr, key: string): FirestoreFunction; /** * @beta * @@ -3440,10 +3387,7 @@ export function mapRemove(mapExpr: ScalarExpr, key: string): FirestoreFunction; * @param mapField The name of a field containing a map value. * @param keyExpr An expression that produces the name of the key to remove from the input map. */ -export function mapRemove( - mapField: string, - keyExpr: ScalarExpr -): FirestoreFunction; +export function mapRemove(mapField: string, keyExpr: Expr): FirestoreFunction; /** * @beta * @@ -3457,14 +3401,11 @@ export function mapRemove( * @param mapExpr An expression return a map value. * @param keyExpr An expression that produces the name of the key to remove from the input map. */ -export function mapRemove( - mapExpr: ScalarExpr, - keyExpr: ScalarExpr -): FirestoreFunction; +export function mapRemove(mapExpr: Expr, keyExpr: Expr): FirestoreFunction; export function mapRemove( - mapExpr: ScalarExpr | string, - stringExpr: ScalarExpr | string + mapExpr: Expr | string, + stringExpr: Expr | string ): FirestoreFunction { return fieldOfOrExpr(mapExpr).mapRemove(valueToDefaultExpr(stringExpr)); } @@ -3488,8 +3429,8 @@ export function mapRemove( */ export function mapMerge( mapField: string, - secondMap: Record | ScalarExpr, - ...otherMaps: Array | ScalarExpr> + secondMap: Record | Expr, + ...otherMaps: Array | Expr> ): FirestoreFunction; /** @@ -3510,15 +3451,15 @@ export function mapMerge( * as a literal or an expression that returns a map. */ export function mapMerge( - firstMap: Record | ScalarExpr, - secondMap: Record | ScalarExpr, - ...otherMaps: Array | ScalarExpr> + firstMap: Record | Expr, + secondMap: Record | Expr, + ...otherMaps: Array | Expr> ): FirestoreFunction; export function mapMerge( - firstMap: string | Record | ScalarExpr, - secondMap: Record | ScalarExpr, - ...otherMaps: Array | ScalarExpr> + firstMap: string | Record | Expr, + secondMap: Record | Expr, + ...otherMaps: Array | Expr> ): FirestoreFunction { const secondMapExpr = valueToDefaultExpr(secondMap); const otherMapExprs = otherMaps.map(valueToDefaultExpr); @@ -3553,12 +3494,10 @@ export function documentIdFunction( * * @return A new {@code Expr} representing the documentId operation. */ -export function documentIdFunction( - documentPathExpr: ScalarExpr -): FirestoreFunction; +export function documentIdFunction(documentPathExpr: Expr): FirestoreFunction; export function documentIdFunction( - documentPath: ScalarExpr | string | DocumentReference + documentPath: Expr | string | DocumentReference ): FirestoreFunction { // @ts-ignore const documentPathExpr = valueToDefaultExpr(documentPath); @@ -3590,7 +3529,7 @@ export function substr( * @param length Length of the substring. */ export function substr( - input: ScalarExpr, + input: Expr, position: number, length?: number ): FirestoreFunction; @@ -3606,8 +3545,8 @@ export function substr( */ export function substr( field: string, - position: ScalarExpr, - length?: ScalarExpr + position: Expr, + length?: Expr ): FirestoreFunction; /** @@ -3620,15 +3559,15 @@ export function substr( * @param length An expression that returns the length of the substring. */ export function substr( - input: ScalarExpr, - position: ScalarExpr, - length?: ScalarExpr + input: Expr, + position: Expr, + length?: Expr ): FirestoreFunction; export function substr( - field: ScalarExpr | string, - position: ScalarExpr | number, - length?: ScalarExpr | number + field: Expr | string, + position: Expr | number, + length?: Expr | number ): FirestoreFunction { const fieldExpr = fieldOfOrExpr(field); const positionExpr = valueToDefaultExpr(position); @@ -3653,9 +3592,9 @@ export function substr( * @return A new {@code Expr} representing the addition operation. */ export function add( - first: ScalarExpr, - second: ScalarExpr | any, - ...others: Array + first: Expr, + second: Expr | any, + ...others: Array ): FirestoreFunction; /** @@ -3675,14 +3614,14 @@ export function add( */ export function add( fieldName: string, - second: ScalarExpr | any, - ...others: Array + second: Expr | any, + ...others: Array ): FirestoreFunction; export function add( - first: ScalarExpr | string, - second: ScalarExpr | any, - ...others: Array + first: Expr | string, + second: Expr | any, + ...others: Array ): FirestoreFunction { return fieldOfOrExpr(first).add( valueToDefaultExpr(second), @@ -3704,10 +3643,7 @@ export function add( * @param right The expression to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract( - left: ScalarExpr, - right: ScalarExpr -): FirestoreFunction; +export function subtract(left: Expr, right: Expr): FirestoreFunction; /** * @beta @@ -3723,7 +3659,7 @@ export function subtract( * @param right The constant value to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: ScalarExpr, right: any): FirestoreFunction; +export function subtract(left: Expr, right: any): FirestoreFunction; /** * @beta @@ -3739,7 +3675,7 @@ export function subtract(left: ScalarExpr, right: any): FirestoreFunction; * @param right The expression to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: string, right: ScalarExpr): FirestoreFunction; +export function subtract(left: string, right: Expr): FirestoreFunction; /** * @beta @@ -3757,8 +3693,8 @@ export function subtract(left: string, right: ScalarExpr): FirestoreFunction; */ export function subtract(left: string, right: any): FirestoreFunction; export function subtract( - left: ScalarExpr | string, - right: ScalarExpr | any + left: Expr | string, + right: Expr | any ): FirestoreFunction { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; const normalizedRight = valueToDefaultExpr(right); @@ -3781,9 +3717,9 @@ export function subtract( * @return A new {@code Expr} representing the multiplication operation. */ export function multiply( - first: ScalarExpr, - second: ScalarExpr | any, - ...others: Array + first: Expr, + second: Expr | any, + ...others: Array ): FirestoreFunction; /** @@ -3803,14 +3739,14 @@ export function multiply( */ export function multiply( fieldName: string, - second: ScalarExpr | any, - ...others: Array + second: Expr | any, + ...others: Array ): FirestoreFunction; export function multiply( - first: ScalarExpr | string, - second: ScalarExpr | any, - ...others: Array + first: Expr | string, + second: Expr | any, + ...others: Array ): FirestoreFunction { return fieldOfOrExpr(first).multiply( valueToDefaultExpr(second), @@ -3832,7 +3768,7 @@ export function multiply( * @param right The expression to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: ScalarExpr, right: ScalarExpr): FirestoreFunction; +export function divide(left: Expr, right: Expr): FirestoreFunction; /** * @beta @@ -3848,7 +3784,7 @@ export function divide(left: ScalarExpr, right: ScalarExpr): FirestoreFunction; * @param right The constant value to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: ScalarExpr, right: any): FirestoreFunction; +export function divide(left: Expr, right: any): FirestoreFunction; /** * @beta @@ -3864,7 +3800,7 @@ export function divide(left: ScalarExpr, right: any): FirestoreFunction; * @param right The expression to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: string, right: ScalarExpr): FirestoreFunction; +export function divide(left: string, right: Expr): FirestoreFunction; /** * @beta @@ -3882,8 +3818,8 @@ export function divide(left: string, right: ScalarExpr): FirestoreFunction; */ export function divide(left: string, right: any): FirestoreFunction; export function divide( - left: ScalarExpr | string, - right: ScalarExpr | any + left: Expr | string, + right: Expr | any ): FirestoreFunction { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; const normalizedRight = valueToDefaultExpr(right); @@ -3904,7 +3840,7 @@ export function divide( * @param right The divisor expression. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: ScalarExpr, right: ScalarExpr): FirestoreFunction; +export function mod(left: Expr, right: Expr): FirestoreFunction; /** * @beta @@ -3920,7 +3856,7 @@ export function mod(left: ScalarExpr, right: ScalarExpr): FirestoreFunction; * @param right The divisor constant. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: ScalarExpr, right: any): FirestoreFunction; +export function mod(left: Expr, right: any): FirestoreFunction; /** * @beta @@ -3936,7 +3872,7 @@ export function mod(left: ScalarExpr, right: any): FirestoreFunction; * @param right The divisor expression. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: string, right: ScalarExpr): FirestoreFunction; +export function mod(left: string, right: Expr): FirestoreFunction; /** * @beta @@ -3953,10 +3889,7 @@ export function mod(left: string, right: ScalarExpr): FirestoreFunction; * @return A new {@code Expr} representing the modulo operation. */ export function mod(left: string, right: any): FirestoreFunction; -export function mod( - left: ScalarExpr | string, - right: ScalarExpr | any -): FirestoreFunction { +export function mod(left: Expr | string, right: Expr | any): FirestoreFunction { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; const normalizedRight = valueToDefaultExpr(right); return normalizedLeft.mod(normalizedRight); @@ -3986,7 +3919,7 @@ export function map(elements: Record): FirestoreFunction { * @param plainObject */ export function _mapValue(plainObject: Record): MapValue { - const result: Map = new Map(); + const result: Map = new Map(); for (const key in plainObject) { if (Object.prototype.hasOwnProperty.call(plainObject, key)) { const value = plainObject[key]; @@ -4017,7 +3950,7 @@ export function array(elements: any[]): FirestoreFunction { * @param right The second expression to compare. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: ScalarExpr, right: ScalarExpr): BooleanExpr; +export function eq(left: Expr, right: Expr): BooleanExpr; /** * @beta @@ -4033,7 +3966,7 @@ export function eq(left: ScalarExpr, right: ScalarExpr): BooleanExpr; * @param right The constant value to compare to. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: ScalarExpr, right: any): BooleanExpr; +export function eq(left: Expr, right: any): BooleanExpr; /** * @beta @@ -4049,7 +3982,7 @@ export function eq(left: ScalarExpr, right: any): BooleanExpr; * @param right The expression to compare to. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: string, right: ScalarExpr): BooleanExpr; +export function eq(left: string, right: Expr): BooleanExpr; /** * @beta @@ -4066,8 +3999,8 @@ export function eq(left: string, right: ScalarExpr): BooleanExpr; * @return A new `Expr` representing the equality comparison. */ export function eq(left: string, right: any): BooleanExpr; -export function eq(left: ScalarExpr | string, right: any): BooleanExpr { - const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); +export function eq(left: Expr | string, right: any): BooleanExpr { + const leftExpr = left instanceof Expr ? left : Field.of(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.eq(rightExpr); } @@ -4086,7 +4019,7 @@ export function eq(left: ScalarExpr | string, right: any): BooleanExpr { * @param right The second expression to compare. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: ScalarExpr, right: ScalarExpr): BooleanExpr; +export function neq(left: Expr, right: Expr): BooleanExpr; /** * @beta @@ -4102,7 +4035,7 @@ export function neq(left: ScalarExpr, right: ScalarExpr): BooleanExpr; * @param right The constant value to compare to. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: ScalarExpr, right: any): BooleanExpr; +export function neq(left: Expr, right: any): BooleanExpr; /** * @beta @@ -4118,7 +4051,7 @@ export function neq(left: ScalarExpr, right: any): BooleanExpr; * @param right The expression to compare to. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: string, right: ScalarExpr): BooleanExpr; +export function neq(left: string, right: Expr): BooleanExpr; /** * @beta @@ -4135,8 +4068,8 @@ export function neq(left: string, right: ScalarExpr): BooleanExpr; * @return A new `Expr` representing the inequality comparison. */ export function neq(left: string, right: any): BooleanExpr; -export function neq(left: ScalarExpr | string, right: any): BooleanExpr { - const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); +export function neq(left: Expr | string, right: any): BooleanExpr { + const leftExpr = left instanceof Expr ? left : Field.of(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.neq(rightExpr); } @@ -4155,7 +4088,7 @@ export function neq(left: ScalarExpr | string, right: any): BooleanExpr { * @param right The second expression to compare. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: ScalarExpr, right: ScalarExpr): BooleanExpr; +export function lt(left: Expr, right: Expr): BooleanExpr; /** * @beta @@ -4171,7 +4104,7 @@ export function lt(left: ScalarExpr, right: ScalarExpr): BooleanExpr; * @param right The constant value to compare to. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: ScalarExpr, right: any): BooleanExpr; +export function lt(left: Expr, right: any): BooleanExpr; /** * @beta @@ -4187,7 +4120,7 @@ export function lt(left: ScalarExpr, right: any): BooleanExpr; * @param right The expression to compare to. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: string, right: ScalarExpr): BooleanExpr; +export function lt(left: string, right: Expr): BooleanExpr; /** * @beta @@ -4204,8 +4137,8 @@ export function lt(left: string, right: ScalarExpr): BooleanExpr; * @return A new `Expr` representing the less than comparison. */ export function lt(left: string, right: any): BooleanExpr; -export function lt(left: ScalarExpr | string, right: any): BooleanExpr { - const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); +export function lt(left: Expr | string, right: any): BooleanExpr { + const leftExpr = left instanceof Expr ? left : Field.of(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.lt(rightExpr); } @@ -4225,7 +4158,7 @@ export function lt(left: ScalarExpr | string, right: any): BooleanExpr { * @param right The second expression to compare. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: ScalarExpr, right: ScalarExpr): BooleanExpr; +export function lte(left: Expr, right: Expr): BooleanExpr; /** * @beta @@ -4241,7 +4174,7 @@ export function lte(left: ScalarExpr, right: ScalarExpr): BooleanExpr; * @param right The constant value to compare to. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: ScalarExpr, right: any): BooleanExpr; +export function lte(left: Expr, right: any): BooleanExpr; /** * Creates an expression that checks if a field's value is less than or equal to an expression. @@ -4255,7 +4188,7 @@ export function lte(left: ScalarExpr, right: any): BooleanExpr; * @param right The expression to compare to. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: string, right: ScalarExpr): BooleanExpr; +export function lte(left: string, right: Expr): BooleanExpr; /** * @beta @@ -4272,8 +4205,8 @@ export function lte(left: string, right: ScalarExpr): BooleanExpr; * @return A new `Expr` representing the less than or equal to comparison. */ export function lte(left: string, right: any): BooleanExpr; -export function lte(left: ScalarExpr | string, right: any): BooleanExpr { - const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); +export function lte(left: Expr | string, right: any): BooleanExpr { + const leftExpr = left instanceof Expr ? left : Field.of(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.lte(rightExpr); } @@ -4293,7 +4226,7 @@ export function lte(left: ScalarExpr | string, right: any): BooleanExpr { * @param right The second expression to compare. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: ScalarExpr, right: ScalarExpr): BooleanExpr; +export function gt(left: Expr, right: Expr): BooleanExpr; /** * @beta @@ -4309,7 +4242,7 @@ export function gt(left: ScalarExpr, right: ScalarExpr): BooleanExpr; * @param right The constant value to compare to. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: ScalarExpr, right: any): BooleanExpr; +export function gt(left: Expr, right: any): BooleanExpr; /** * @beta @@ -4325,7 +4258,7 @@ export function gt(left: ScalarExpr, right: any): BooleanExpr; * @param right The expression to compare to. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: string, right: ScalarExpr): BooleanExpr; +export function gt(left: string, right: Expr): BooleanExpr; /** * @beta @@ -4342,8 +4275,8 @@ export function gt(left: string, right: ScalarExpr): BooleanExpr; * @return A new `Expr` representing the greater than comparison. */ export function gt(left: string, right: any): BooleanExpr; -export function gt(left: ScalarExpr | string, right: any): BooleanExpr { - const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); +export function gt(left: Expr | string, right: any): BooleanExpr { + const leftExpr = left instanceof Expr ? left : Field.of(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.gt(rightExpr); } @@ -4363,7 +4296,7 @@ export function gt(left: ScalarExpr | string, right: any): BooleanExpr { * @param right The second expression to compare. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: ScalarExpr, right: ScalarExpr): BooleanExpr; +export function gte(left: Expr, right: Expr): BooleanExpr; /** * @beta @@ -4380,7 +4313,7 @@ export function gte(left: ScalarExpr, right: ScalarExpr): BooleanExpr; * @param right The constant value to compare to. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: ScalarExpr, right: any): BooleanExpr; +export function gte(left: Expr, right: any): BooleanExpr; /** * @beta @@ -4396,7 +4329,7 @@ export function gte(left: ScalarExpr, right: any): BooleanExpr; * @param right The expression to compare to. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: string, right: ScalarExpr): BooleanExpr; +export function gte(left: string, right: Expr): BooleanExpr; /** * @beta @@ -4414,8 +4347,8 @@ export function gte(left: string, right: ScalarExpr): BooleanExpr; * @return A new `Expr` representing the greater than or equal to comparison. */ export function gte(left: string, right: any): BooleanExpr; -export function gte(left: ScalarExpr | string, right: any): BooleanExpr { - const leftExpr = left instanceof ScalarExpr ? left : Field.of(left); +export function gte(left: Expr | string, right: any): BooleanExpr { + const leftExpr = left instanceof Expr ? left : Field.of(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.gte(rightExpr); } @@ -4436,9 +4369,9 @@ export function gte(left: ScalarExpr | string, right: any): BooleanExpr { * @return A new {@code Expr} representing the concatenated array. */ export function arrayConcat( - firstArray: ScalarExpr, - secondArray: ScalarExpr | any, - ...otherArrays: Array + firstArray: Expr, + secondArray: Expr | any, + ...otherArrays: Array ): FirestoreFunction; /** @@ -4458,14 +4391,14 @@ export function arrayConcat( */ export function arrayConcat( firstArrayField: string, - secondArray: ScalarExpr | any[], - ...otherArrays: Array + secondArray: Expr | any[], + ...otherArrays: Array ): FirestoreFunction; export function arrayConcat( - firstArray: ScalarExpr | string, - secondArray: ScalarExpr | any[], - ...otherArrays: Array + firstArray: Expr | string, + secondArray: Expr | any[], + ...otherArrays: Array ): FirestoreFunction { const exprValues = otherArrays.map(element => valueToDefaultExpr(element)); return fieldOfOrExpr(firstArray).arrayConcat( @@ -4488,10 +4421,7 @@ export function arrayConcat( * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains( - array: ScalarExpr, - element: ScalarExpr -): FirestoreFunction; +export function arrayContains(array: Expr, element: Expr): FirestoreFunction; /** * @beta @@ -4507,10 +4437,7 @@ export function arrayContains( * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains( - array: ScalarExpr, - element: any -): FirestoreFunction; +export function arrayContains(array: Expr, element: any): FirestoreFunction; /** * @beta @@ -4526,10 +4453,7 @@ export function arrayContains( * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains( - array: string, - element: ScalarExpr -): FirestoreFunction; +export function arrayContains(array: string, element: Expr): FirestoreFunction; /** * @beta @@ -4546,10 +4470,7 @@ export function arrayContains( * @return A new {@code Expr} representing the 'array_contains' comparison. */ export function arrayContains(array: string, element: any): BooleanExpr; -export function arrayContains( - array: ScalarExpr | string, - element: any -): BooleanExpr { +export function arrayContains(array: Expr | string, element: any): BooleanExpr { const arrayExpr = fieldOfOrExpr(array); const elementExpr = valueToDefaultExpr(element); return arrayExpr.arrayContains(elementExpr); @@ -4570,10 +4491,7 @@ export function arrayContains( * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_any' comparison. */ -export function arrayContainsAny( - array: ScalarExpr, - values: ScalarExpr[] -): BooleanExpr; +export function arrayContainsAny(array: Expr, values: Expr[]): BooleanExpr; /** * @beta @@ -4590,7 +4508,7 @@ export function arrayContainsAny( * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_any' comparison. */ -export function arrayContainsAny(array: ScalarExpr, values: any[]): BooleanExpr; +export function arrayContainsAny(array: Expr, values: any[]): BooleanExpr; /** * @beta @@ -4608,10 +4526,7 @@ export function arrayContainsAny(array: ScalarExpr, values: any[]): BooleanExpr; * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_any' comparison. */ -export function arrayContainsAny( - array: string, - values: ScalarExpr[] -): BooleanExpr; +export function arrayContainsAny(array: string, values: Expr[]): BooleanExpr; /** * @beta @@ -4631,7 +4546,7 @@ export function arrayContainsAny( */ export function arrayContainsAny(array: string, values: any[]): BooleanExpr; export function arrayContainsAny( - array: ScalarExpr | string, + array: Expr | string, values: any[] ): BooleanExpr { return fieldOfOrExpr(array).arrayContainsAny( @@ -4653,10 +4568,7 @@ export function arrayContainsAny( * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_all' comparison. */ -export function arrayContainsAll( - array: ScalarExpr, - values: ScalarExpr[] -): BooleanExpr; +export function arrayContainsAll(array: Expr, values: Expr[]): BooleanExpr; /** * @beta @@ -4672,7 +4584,7 @@ export function arrayContainsAll( * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_all' comparison. */ -export function arrayContainsAll(array: ScalarExpr, values: any[]): BooleanExpr; +export function arrayContainsAll(array: Expr, values: any[]): BooleanExpr; /** * @beta @@ -4689,10 +4601,7 @@ export function arrayContainsAll(array: ScalarExpr, values: any[]): BooleanExpr; * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_all' comparison. */ -export function arrayContainsAll( - array: string, - values: ScalarExpr[] -): BooleanExpr; +export function arrayContainsAll(array: string, values: Expr[]): BooleanExpr; /** * @beta @@ -4711,7 +4620,7 @@ export function arrayContainsAll( */ export function arrayContainsAll(array: string, values: any[]): BooleanExpr; export function arrayContainsAll( - array: ScalarExpr | string, + array: Expr | string, values: any[] ): BooleanExpr { const arrayExpr = fieldOfOrExpr(array); @@ -4732,7 +4641,7 @@ export function arrayContainsAll( * @param array The array expression to calculate the length of. * @return A new {@code Expr} representing the length of the array. */ -export function arrayLength(array: ScalarExpr): FirestoreFunction { +export function arrayLength(array: Expr): FirestoreFunction { return array.arrayLength(); } @@ -4751,7 +4660,7 @@ export function arrayLength(array: ScalarExpr): FirestoreFunction { * @param others The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: ScalarExpr, others: ScalarExpr[]): BooleanExpr; +export function eqAny(element: Expr, others: Expr[]): BooleanExpr; /** * @beta @@ -4768,7 +4677,7 @@ export function eqAny(element: ScalarExpr, others: ScalarExpr[]): BooleanExpr; * @param others The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: ScalarExpr, others: any[]): BooleanExpr; +export function eqAny(element: Expr, others: any[]): BooleanExpr; /** * @beta @@ -4785,7 +4694,7 @@ export function eqAny(element: ScalarExpr, others: any[]): BooleanExpr; * @param others The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: string, others: ScalarExpr[]): BooleanExpr; +export function eqAny(element: string, others: Expr[]): BooleanExpr; /** * @beta @@ -4803,10 +4712,7 @@ export function eqAny(element: string, others: ScalarExpr[]): BooleanExpr; * @return A new {@code Expr} representing the 'IN' comparison. */ export function eqAny(element: string, others: any[]): BooleanExpr; -export function eqAny( - element: ScalarExpr | string, - others: any[] -): BooleanExpr { +export function eqAny(element: Expr | string, others: any[]): BooleanExpr { const elementExpr = fieldOfOrExpr(element); const exprOthers = others.map(other => valueToDefaultExpr(other)); return elementExpr.eqAny(...exprOthers); @@ -4827,10 +4733,7 @@ export function eqAny( * @param others The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny( - element: ScalarExpr, - others: ScalarExpr[] -): BooleanExpr; +export function notEqAny(element: Expr, others: Expr[]): BooleanExpr; /** * @beta @@ -4847,7 +4750,7 @@ export function notEqAny( * @param others The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: ScalarExpr, others: any[]): BooleanExpr; +export function notEqAny(element: Expr, others: any[]): BooleanExpr; /** * @beta @@ -4864,7 +4767,7 @@ export function notEqAny(element: ScalarExpr, others: any[]): BooleanExpr; * @param others The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: string, others: ScalarExpr[]): BooleanExpr; +export function notEqAny(element: string, others: Expr[]): BooleanExpr; /** * @beta @@ -4882,10 +4785,7 @@ export function notEqAny(element: string, others: ScalarExpr[]): BooleanExpr; * @return A new {@code Expr} representing the 'NOT IN' comparison. */ export function notEqAny(element: string, others: any[]): BooleanExpr; -export function notEqAny( - element: ScalarExpr | string, - others: any[] -): BooleanExpr { +export function notEqAny(element: Expr | string, others: any[]): BooleanExpr { const elementExpr = fieldOfOrExpr(element); const exprOthers = others.map(other => valueToDefaultExpr(other)); return elementExpr.notEqAny(...exprOthers); @@ -4938,8 +4838,8 @@ export function xor( */ export function cond( condition: BooleanExpr, - thenExpr: ScalarExpr, - elseExpr: ScalarExpr + thenExpr: Expr, + elseExpr: Expr ): FirestoreFunction { return new BooleanExpr('cond', [condition, thenExpr, elseExpr]); } @@ -4977,9 +4877,9 @@ export function not(filter: BooleanExpr): BooleanExpr { * @return A new {@code Expr} representing the logical max operation. */ export function logicalMaximum( - first: ScalarExpr, - second: ScalarExpr | any, - ...others: Array + first: Expr, + second: Expr | any, + ...others: Array ): FirestoreFunction; /** @@ -4999,14 +4899,14 @@ export function logicalMaximum( */ export function logicalMaximum( left: string, - second: ScalarExpr | any, - ...others: Array + second: Expr | any, + ...others: Array ): FirestoreFunction; export function logicalMaximum( - first: ScalarExpr | string, - second: ScalarExpr | any, - ...others: Array + first: Expr | string, + second: Expr | any, + ...others: Array ): FirestoreFunction { return fieldOfOrExpr(first).logicalMaximum( valueToDefaultExpr(second), @@ -5030,9 +4930,9 @@ export function logicalMaximum( * @return A new {@code Expr} representing the logical min operation. */ export function logicalMinimum( - first: ScalarExpr, - second: ScalarExpr | any, - ...others: Array + first: Expr, + second: Expr | any, + ...others: Array ): FirestoreFunction; /** @@ -5052,14 +4952,14 @@ export function logicalMinimum( */ export function logicalMinimum( fieldName: string, - second: ScalarExpr | any, - ...others: Array + second: Expr | any, + ...others: Array ): FirestoreFunction; export function logicalMinimum( - first: ScalarExpr | string, - second: ScalarExpr | any, - ...others: Array + first: Expr | string, + second: Expr | any, + ...others: Array ): FirestoreFunction { return fieldOfOrExpr(first).logicalMinimum( valueToDefaultExpr(second), @@ -5080,7 +4980,7 @@ export function logicalMinimum( * @param value An expression evaluates to the name of the field to check. * @return A new {@code Expr} representing the 'exists' check. */ -export function exists(value: ScalarExpr): BooleanExpr; +export function exists(value: Expr): BooleanExpr; /** * @beta @@ -5096,7 +4996,7 @@ export function exists(value: ScalarExpr): BooleanExpr; * @return A new {@code Expr} representing the 'exists' check. */ export function exists(field: string): BooleanExpr; -export function exists(valueOrField: ScalarExpr | string): BooleanExpr { +export function exists(valueOrField: Expr | string): BooleanExpr { return fieldOfOrExpr(valueOrField).exists(); } @@ -5113,7 +5013,7 @@ export function exists(valueOrField: ScalarExpr | string): BooleanExpr { * @param value The expression to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNan(value: ScalarExpr): BooleanExpr; +export function isNan(value: Expr): BooleanExpr; /** * @beta @@ -5129,7 +5029,7 @@ export function isNan(value: ScalarExpr): BooleanExpr; * @return A new {@code Expr} representing the 'isNaN' check. */ export function isNan(value: string): BooleanExpr; -export function isNan(value: ScalarExpr | string): BooleanExpr { +export function isNan(value: Expr | string): BooleanExpr { return fieldOfOrExpr(value).isNan(); } @@ -5146,7 +5046,7 @@ export function isNan(value: ScalarExpr | string): BooleanExpr { * @param expr The expression representing the string to reverse. * @return A new {@code Expr} representing the reversed string. */ -export function reverse(expr: ScalarExpr): FirestoreFunction; +export function reverse(expr: Expr): FirestoreFunction; /** * @beta @@ -5162,7 +5062,7 @@ export function reverse(expr: ScalarExpr): FirestoreFunction; * @return A new {@code Expr} representing the reversed string. */ export function reverse(field: string): FirestoreFunction; -export function reverse(expr: ScalarExpr | string): FirestoreFunction { +export function reverse(expr: Expr | string): FirestoreFunction { return fieldOfOrExpr(expr).reverse(); } @@ -5182,7 +5082,7 @@ export function reverse(expr: ScalarExpr | string): FirestoreFunction { * @return A new {@code Expr} representing the string with the first occurrence replaced. */ export function replaceFirst( - value: ScalarExpr, + value: Expr, find: string, replace: string ): FirestoreFunction; @@ -5204,9 +5104,9 @@ export function replaceFirst( * @return A new {@code Expr} representing the string with the first occurrence replaced. */ export function replaceFirst( - value: ScalarExpr, - find: ScalarExpr, - replace: ScalarExpr + value: Expr, + find: Expr, + replace: Expr ): FirestoreFunction; /** @@ -5230,9 +5130,9 @@ export function replaceFirst( replace: string ): FirestoreFunction; export function replaceFirst( - value: ScalarExpr | string, - find: ScalarExpr | string, - replace: ScalarExpr | string + value: Expr | string, + find: Expr | string, + replace: Expr | string ): FirestoreFunction { const normalizedValue = fieldOfOrExpr(value); const normalizedFind = valueToDefaultExpr(find); @@ -5256,7 +5156,7 @@ export function replaceFirst( * @return A new {@code Expr} representing the string with all occurrences replaced. */ export function replaceAll( - value: ScalarExpr, + value: Expr, find: string, replace: string ): FirestoreFunction; @@ -5278,9 +5178,9 @@ export function replaceAll( * @return A new {@code Expr} representing the string with all occurrences replaced. */ export function replaceAll( - value: ScalarExpr, - find: ScalarExpr, - replace: ScalarExpr + value: Expr, + find: Expr, + replace: Expr ): FirestoreFunction; /** @@ -5304,9 +5204,9 @@ export function replaceAll( replace: string ): FirestoreFunction; export function replaceAll( - value: ScalarExpr | string, - find: ScalarExpr | string, - replace: ScalarExpr | string + value: Expr | string, + find: Expr | string, + replace: Expr | string ): FirestoreFunction { const normalizedValue = fieldOfOrExpr(value); const normalizedFind = valueToDefaultExpr(find); @@ -5327,7 +5227,7 @@ export function replaceAll( * @param expr The expression representing the string. * @return A new {@code Expr} representing the length of the string in bytes. */ -export function byteLength(expr: ScalarExpr): FirestoreFunction; +export function byteLength(expr: Expr): FirestoreFunction; /** * @beta @@ -5343,7 +5243,7 @@ export function byteLength(expr: ScalarExpr): FirestoreFunction; * @return A new {@code Expr} representing the length of the string in bytes. */ export function byteLength(field: string): FirestoreFunction; -export function byteLength(expr: ScalarExpr | string): FirestoreFunction { +export function byteLength(expr: Expr | string): FirestoreFunction { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.byteLength(); } @@ -5376,8 +5276,8 @@ export function charLength(field: string): FirestoreFunction; * @param expr The expression representing the string to calculate the length of. * @return A new {@code Expr} representing the length of the string. */ -export function charLength(expr: ScalarExpr): FirestoreFunction; -export function charLength(value: ScalarExpr | string): FirestoreFunction { +export function charLength(expr: Expr): FirestoreFunction; +export function charLength(value: Expr | string): FirestoreFunction { const valueExpr = fieldOfOrExpr(value); return valueExpr.charLength(); } @@ -5414,7 +5314,7 @@ export function like(left: string, pattern: string): BooleanExpr; * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: string, pattern: ScalarExpr): BooleanExpr; +export function like(left: string, pattern: Expr): BooleanExpr; /** * @beta @@ -5430,7 +5330,7 @@ export function like(left: string, pattern: ScalarExpr): BooleanExpr; * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: ScalarExpr, pattern: string): BooleanExpr; +export function like(left: Expr, pattern: string): BooleanExpr; /** * @beta @@ -5446,10 +5346,10 @@ export function like(left: ScalarExpr, pattern: string): BooleanExpr; * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: ScalarExpr, pattern: ScalarExpr): BooleanExpr; +export function like(left: Expr, pattern: Expr): BooleanExpr; export function like( - left: ScalarExpr | string, - pattern: ScalarExpr | string + left: Expr | string, + pattern: Expr | string ): FirestoreFunction { const leftExpr = fieldOfOrExpr(left); const patternExpr = valueToDefaultExpr(pattern); @@ -5488,7 +5388,7 @@ export function regexContains(left: string, pattern: string): BooleanExpr; * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function regexContains(left: string, pattern: ScalarExpr): BooleanExpr; +export function regexContains(left: string, pattern: Expr): BooleanExpr; /** * @beta @@ -5505,7 +5405,7 @@ export function regexContains(left: string, pattern: ScalarExpr): BooleanExpr; * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function regexContains(left: ScalarExpr, pattern: string): BooleanExpr; +export function regexContains(left: Expr, pattern: string): BooleanExpr; /** * @beta @@ -5522,13 +5422,10 @@ export function regexContains(left: ScalarExpr, pattern: string): BooleanExpr; * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ +export function regexContains(left: Expr, pattern: Expr): BooleanExpr; export function regexContains( - left: ScalarExpr, - pattern: ScalarExpr -): BooleanExpr; -export function regexContains( - left: ScalarExpr | string, - pattern: ScalarExpr | string + left: Expr | string, + pattern: Expr | string ): BooleanExpr { const leftExpr = fieldOfOrExpr(left); const patternExpr = valueToDefaultExpr(pattern); @@ -5565,7 +5462,7 @@ export function regexMatch(left: string, pattern: string): BooleanExpr; * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: string, pattern: ScalarExpr): BooleanExpr; +export function regexMatch(left: string, pattern: Expr): BooleanExpr; /** * @beta @@ -5582,7 +5479,7 @@ export function regexMatch(left: string, pattern: ScalarExpr): BooleanExpr; * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: ScalarExpr, pattern: string): BooleanExpr; +export function regexMatch(left: Expr, pattern: string): BooleanExpr; /** * @beta @@ -5599,10 +5496,10 @@ export function regexMatch(left: ScalarExpr, pattern: string): BooleanExpr; * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: ScalarExpr, pattern: ScalarExpr): BooleanExpr; +export function regexMatch(left: Expr, pattern: Expr): BooleanExpr; export function regexMatch( - left: ScalarExpr | string, - pattern: ScalarExpr | string + left: Expr | string, + pattern: Expr | string ): BooleanExpr { const leftExpr = fieldOfOrExpr(left); const patternExpr = valueToDefaultExpr(pattern); @@ -5639,7 +5536,7 @@ export function strContains(left: string, substring: string): BooleanExpr; * @param substring The expression representing the substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function strContains(left: string, substring: ScalarExpr): BooleanExpr; +export function strContains(left: string, substring: Expr): BooleanExpr; /** * @beta @@ -5655,7 +5552,7 @@ export function strContains(left: string, substring: ScalarExpr): BooleanExpr; * @param substring The substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function strContains(left: ScalarExpr, substring: string): BooleanExpr; +export function strContains(left: Expr, substring: string): BooleanExpr; /** * @beta @@ -5671,13 +5568,10 @@ export function strContains(left: ScalarExpr, substring: string): BooleanExpr; * @param substring The expression representing the substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ +export function strContains(left: Expr, substring: Expr): BooleanExpr; export function strContains( - left: ScalarExpr, - substring: ScalarExpr -): BooleanExpr; -export function strContains( - left: ScalarExpr | string, - substring: ScalarExpr | string + left: Expr | string, + substring: Expr | string ): BooleanExpr { const leftExpr = fieldOfOrExpr(left); const substringExpr = valueToDefaultExpr(substring); @@ -5714,7 +5608,7 @@ export function startsWith(expr: string, prefix: string): BooleanExpr; * @param prefix The expression representing the prefix. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: string, prefix: ScalarExpr): BooleanExpr; +export function startsWith(expr: string, prefix: Expr): BooleanExpr; /** * @beta @@ -5730,7 +5624,7 @@ export function startsWith(expr: string, prefix: ScalarExpr): BooleanExpr; * @param prefix The prefix to check for. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: ScalarExpr, prefix: string): BooleanExpr; +export function startsWith(expr: Expr, prefix: string): BooleanExpr; /** * @beta @@ -5746,10 +5640,10 @@ export function startsWith(expr: ScalarExpr, prefix: string): BooleanExpr; * @param prefix The prefix to check for. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: ScalarExpr, prefix: ScalarExpr): BooleanExpr; +export function startsWith(expr: Expr, prefix: Expr): BooleanExpr; export function startsWith( - expr: ScalarExpr | string, - prefix: ScalarExpr | string + expr: Expr | string, + prefix: Expr | string ): BooleanExpr { return fieldOfOrExpr(expr).startsWith(valueToDefaultExpr(prefix)); } @@ -5784,7 +5678,7 @@ export function endsWith(expr: string, suffix: string): BooleanExpr; * @param suffix The expression representing the postfix. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: string, suffix: ScalarExpr): BooleanExpr; +export function endsWith(expr: string, suffix: Expr): BooleanExpr; /** * @beta @@ -5800,7 +5694,7 @@ export function endsWith(expr: string, suffix: ScalarExpr): BooleanExpr; * @param suffix The postfix to check for. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: ScalarExpr, suffix: string): BooleanExpr; +export function endsWith(expr: Expr, suffix: string): BooleanExpr; /** * @beta @@ -5816,10 +5710,10 @@ export function endsWith(expr: ScalarExpr, suffix: string): BooleanExpr; * @param suffix The postfix to check for. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: ScalarExpr, suffix: ScalarExpr): BooleanExpr; +export function endsWith(expr: Expr, suffix: Expr): BooleanExpr; export function endsWith( - expr: ScalarExpr | string, - suffix: ScalarExpr | string + expr: Expr | string, + suffix: Expr | string ): BooleanExpr { return fieldOfOrExpr(expr).endsWith(valueToDefaultExpr(suffix)); } @@ -5852,8 +5746,8 @@ export function toLower(expr: string): FirestoreFunction; * @param expr The expression representing the string to convert to lowercase. * @return A new {@code Expr} representing the lowercase string. */ -export function toLower(expr: ScalarExpr): FirestoreFunction; -export function toLower(expr: ScalarExpr | string): FirestoreFunction { +export function toLower(expr: Expr): FirestoreFunction; +export function toLower(expr: Expr | string): FirestoreFunction { return fieldOfOrExpr(expr).toLower(); } @@ -5885,8 +5779,8 @@ export function toUpper(expr: string): FirestoreFunction; * @param expr The expression representing the string to convert to uppercase. * @return A new {@code Expr} representing the uppercase string. */ -export function toUpper(expr: ScalarExpr): FirestoreFunction; -export function toUpper(expr: ScalarExpr | string): FirestoreFunction { +export function toUpper(expr: Expr): FirestoreFunction; +export function toUpper(expr: Expr | string): FirestoreFunction { return fieldOfOrExpr(expr).toUpper(); } @@ -5918,8 +5812,8 @@ export function trim(expr: string): FirestoreFunction; * @param expr The expression representing the string to trim. * @return A new {@code Expr} representing the trimmed string. */ -export function trim(expr: ScalarExpr): FirestoreFunction; -export function trim(expr: ScalarExpr | string): FirestoreFunction { +export function trim(expr: Expr): FirestoreFunction; +export function trim(expr: Expr | string): FirestoreFunction { return fieldOfOrExpr(expr).trim(); } @@ -5940,8 +5834,8 @@ export function trim(expr: ScalarExpr | string): FirestoreFunction { */ export function strConcat( fieldName: string, - secondString: ScalarExpr | string, - ...otherStrings: Array + secondString: Expr | string, + ...otherStrings: Array ): FirestoreFunction; /** @@ -5959,14 +5853,14 @@ export function strConcat( * @return A new {@code Expr} representing the concatenated string. */ export function strConcat( - firstString: ScalarExpr, - secondString: ScalarExpr | string, - ...otherStrings: Array + firstString: Expr, + secondString: Expr | string, + ...otherStrings: Array ): FirestoreFunction; export function strConcat( - first: string | ScalarExpr, - second: string | ScalarExpr, - ...elements: Array + first: string | Expr, + second: string | Expr, + ...elements: Array ): FirestoreFunction { return valueToDefaultExpr(first).strConcat( valueToDefaultExpr(second), @@ -6004,12 +5898,9 @@ export function mapGet(mapField: string, subField: string): FirestoreFunction; * @param subField The key to access in the map. * @return A new {@code Expr} representing the value associated with the given key in the map. */ +export function mapGet(mapExpr: Expr, subField: string): FirestoreFunction; export function mapGet( - mapExpr: ScalarExpr, - subField: string -): FirestoreFunction; -export function mapGet( - fieldOrExpr: string | ScalarExpr, + fieldOrExpr: string | Expr, subField: string ): FirestoreFunction { return fieldOfOrExpr(fieldOrExpr).mapGet(subField); @@ -6045,7 +5936,7 @@ export function countAll(): AggregateFunction { * @param value The expression to count. * @return A new {@code AggregateFunction} representing the 'count' aggregation. */ -export function countFunction(value: ScalarExpr): AggregateFunction; +export function countFunction(value: Expr): AggregateFunction; /** * Creates an aggregation that counts the number of stage inputs with valid evaluations of the @@ -6060,7 +5951,7 @@ export function countFunction(value: ScalarExpr): AggregateFunction; * @return A new {@code AggregateFunction} representing the 'count' aggregation. */ export function countFunction(value: string): AggregateFunction; -export function countFunction(value: ScalarExpr | string): AggregateFunction { +export function countFunction(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).count(); } @@ -6078,7 +5969,7 @@ export function countFunction(value: ScalarExpr | string): AggregateFunction { * @param value The expression to sum up. * @return A new {@code AggregateFunction} representing the 'sum' aggregation. */ -export function sumFunction(value: ScalarExpr): AggregateFunction; +export function sumFunction(value: Expr): AggregateFunction; /** * @beta @@ -6095,7 +5986,7 @@ export function sumFunction(value: ScalarExpr): AggregateFunction; * @return A new {@code AggregateFunction} representing the 'sum' aggregation. */ export function sumFunction(value: string): AggregateFunction; -export function sumFunction(value: ScalarExpr | string): AggregateFunction { +export function sumFunction(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).sum(); } @@ -6113,7 +6004,7 @@ export function sumFunction(value: ScalarExpr | string): AggregateFunction { * @param value The expression representing the values to average. * @return A new {@code AggregateFunction} representing the 'avg' aggregation. */ -export function avgFunction(value: ScalarExpr): AggregateFunction; +export function avgFunction(value: Expr): AggregateFunction; /** * @beta @@ -6130,7 +6021,7 @@ export function avgFunction(value: ScalarExpr): AggregateFunction; * @return A new {@code AggregateFunction} representing the 'avg' aggregation. */ export function avgFunction(value: string): AggregateFunction; -export function avgFunction(value: ScalarExpr | string): AggregateFunction { +export function avgFunction(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).avg(); } @@ -6148,7 +6039,7 @@ export function avgFunction(value: ScalarExpr | string): AggregateFunction { * @param value The expression to find the minimum value of. * @return A new {@code AggregateFunction} representing the 'min' aggregation. */ -export function minimum(value: ScalarExpr): AggregateFunction; +export function minimum(value: Expr): AggregateFunction; /** * @beta @@ -6164,7 +6055,7 @@ export function minimum(value: ScalarExpr): AggregateFunction; * @return A new {@code AggregateFunction} representing the 'min' aggregation. */ export function minimum(value: string): AggregateFunction; -export function minimum(value: ScalarExpr | string): AggregateFunction { +export function minimum(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).minimum(); } @@ -6182,7 +6073,7 @@ export function minimum(value: ScalarExpr | string): AggregateFunction { * @param value The expression to find the maximum value of. * @return A new {@code AggregateFunction} representing the 'max' aggregation. */ -export function maximum(value: ScalarExpr): AggregateFunction; +export function maximum(value: Expr): AggregateFunction; /** * @beta @@ -6198,7 +6089,7 @@ export function maximum(value: ScalarExpr): AggregateFunction; * @return A new {@code AggregateFunction} representing the 'max' aggregation. */ export function maximum(value: string): AggregateFunction; -export function maximum(value: ScalarExpr | string): AggregateFunction { +export function maximum(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).maximum(); } @@ -6254,10 +6145,7 @@ export function cosineDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance( - expr: string, - other: ScalarExpr -): FirestoreFunction; +export function cosineDistance(expr: string, other: Expr): FirestoreFunction; /** * @beta @@ -6273,10 +6161,7 @@ export function cosineDistance( * @param other The other vector (as an array of doubles) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance( - expr: ScalarExpr, - other: number[] -): FirestoreFunction; +export function cosineDistance(expr: Expr, other: number[]): FirestoreFunction; /** * @beta @@ -6293,7 +6178,7 @@ export function cosineDistance( * @return A new {@code Expr} representing the cosine distance between the two vectors. */ export function cosineDistance( - expr: ScalarExpr, + expr: Expr, other: VectorValue ): FirestoreFunction; @@ -6311,13 +6196,10 @@ export function cosineDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ +export function cosineDistance(expr: Expr, other: Expr): FirestoreFunction; export function cosineDistance( - expr: ScalarExpr, - other: ScalarExpr -): FirestoreFunction; -export function cosineDistance( - expr: ScalarExpr | string, - other: ScalarExpr | number[] | VectorValue + expr: Expr | string, + other: Expr | number[] | VectorValue ): FirestoreFunction { const expr1 = fieldOfOrExpr(expr); const expr2 = vectorToExpr(other); @@ -6370,7 +6252,7 @@ export function dotProduct(expr: string, other: VectorValue): FirestoreFunction; * @param other The other vector (represented as an Expr) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: string, other: ScalarExpr): FirestoreFunction; +export function dotProduct(expr: string, other: Expr): FirestoreFunction; /** * @beta @@ -6386,10 +6268,7 @@ export function dotProduct(expr: string, other: ScalarExpr): FirestoreFunction; * @param other The other vector (as an array of doubles) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct( - expr: ScalarExpr, - other: number[] -): FirestoreFunction; +export function dotProduct(expr: Expr, other: number[]): FirestoreFunction; /** * @beta @@ -6405,10 +6284,7 @@ export function dotProduct( * @param other The other vector (as a VectorValue) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct( - expr: ScalarExpr, - other: VectorValue -): FirestoreFunction; +export function dotProduct(expr: Expr, other: VectorValue): FirestoreFunction; /** * @beta @@ -6424,13 +6300,10 @@ export function dotProduct( * @param other The other vector (represented as an Expr) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ +export function dotProduct(expr: Expr, other: Expr): FirestoreFunction; export function dotProduct( - expr: ScalarExpr, - other: ScalarExpr -): FirestoreFunction; -export function dotProduct( - expr: ScalarExpr | string, - other: ScalarExpr | number[] | VectorValue + expr: Expr | string, + other: Expr | number[] | VectorValue ): FirestoreFunction { const expr1 = fieldOfOrExpr(expr); const expr2 = vectorToExpr(other); @@ -6489,10 +6362,7 @@ export function euclideanDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ -export function euclideanDistance( - expr: string, - other: ScalarExpr -): FirestoreFunction; +export function euclideanDistance(expr: string, other: Expr): FirestoreFunction; /** * @beta @@ -6510,7 +6380,7 @@ export function euclideanDistance( * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ export function euclideanDistance( - expr: ScalarExpr, + expr: Expr, other: number[] ): FirestoreFunction; @@ -6529,7 +6399,7 @@ export function euclideanDistance( * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ export function euclideanDistance( - expr: ScalarExpr, + expr: Expr, other: VectorValue ): FirestoreFunction; @@ -6547,13 +6417,10 @@ export function euclideanDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ +export function euclideanDistance(expr: Expr, other: Expr): FirestoreFunction; export function euclideanDistance( - expr: ScalarExpr, - other: ScalarExpr -): FirestoreFunction; -export function euclideanDistance( - expr: ScalarExpr | string, - other: ScalarExpr | number[] | VectorValue + expr: Expr | string, + other: Expr | number[] | VectorValue ): FirestoreFunction { const expr1 = fieldOfOrExpr(expr); const expr2 = vectorToExpr(other); @@ -6612,10 +6479,7 @@ export function manhattanDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ -export function manhattanDistance( - expr: string, - other: ScalarExpr -): FirestoreFunction; +export function manhattanDistance(expr: string, other: Expr): FirestoreFunction; /** * @beta @@ -6633,7 +6497,7 @@ export function manhattanDistance( * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ export function manhattanDistance( - expr: ScalarExpr, + expr: Expr, other: number[] ): FirestoreFunction; @@ -6652,7 +6516,7 @@ export function manhattanDistance( * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ export function manhattanDistance( - expr: ScalarExpr, + expr: Expr, other: VectorValue ): FirestoreFunction; @@ -6670,13 +6534,10 @@ export function manhattanDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ +export function manhattanDistance(expr: Expr, other: Expr): FirestoreFunction; export function manhattanDistance( - expr: ScalarExpr, - other: ScalarExpr -): FirestoreFunction; -export function manhattanDistance( - fieldOrExpr: ScalarExpr | string, - other: ScalarExpr | number[] | VectorValue + fieldOrExpr: Expr | string, + other: Expr | number[] | VectorValue ): FirestoreFunction { const expr1 = fieldOfOrExpr(fieldOrExpr); const expr2 = vectorToExpr(other); @@ -6696,7 +6557,7 @@ export function manhattanDistance( * @param expr The expression representing the Firestore Vector. * @return A new {@code Expr} representing the length of the array. */ -export function vectorLength(expr: ScalarExpr): FirestoreFunction; +export function vectorLength(expr: Expr): FirestoreFunction; /** * @beta @@ -6712,7 +6573,7 @@ export function vectorLength(expr: ScalarExpr): FirestoreFunction; * @return A new {@code Expr} representing the length of the array. */ export function vectorLength(field: string): FirestoreFunction; -export function vectorLength(expr: ScalarExpr | string): FirestoreFunction { +export function vectorLength(expr: Expr | string): FirestoreFunction { return fieldOfOrExpr(expr).vectorLength(); } @@ -6730,7 +6591,7 @@ export function vectorLength(expr: ScalarExpr | string): FirestoreFunction { * @param expr The expression representing the number of microseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMicrosToTimestamp(expr: ScalarExpr): FirestoreFunction; +export function unixMicrosToTimestamp(expr: Expr): FirestoreFunction; /** * @beta @@ -6747,9 +6608,7 @@ export function unixMicrosToTimestamp(expr: ScalarExpr): FirestoreFunction; * @return A new {@code Expr} representing the timestamp. */ export function unixMicrosToTimestamp(field: string): FirestoreFunction; -export function unixMicrosToTimestamp( - expr: ScalarExpr | string -): FirestoreFunction { +export function unixMicrosToTimestamp(expr: Expr | string): FirestoreFunction { return fieldOfOrExpr(expr).unixMicrosToTimestamp(); } @@ -6766,7 +6625,7 @@ export function unixMicrosToTimestamp( * @param expr The expression representing the timestamp. * @return A new {@code Expr} representing the number of microseconds since epoch. */ -export function timestampToUnixMicros(expr: ScalarExpr): FirestoreFunction; +export function timestampToUnixMicros(expr: Expr): FirestoreFunction; /** * @beta @@ -6782,9 +6641,7 @@ export function timestampToUnixMicros(expr: ScalarExpr): FirestoreFunction; * @return A new {@code Expr} representing the number of microseconds since epoch. */ export function timestampToUnixMicros(field: string): FirestoreFunction; -export function timestampToUnixMicros( - expr: ScalarExpr | string -): FirestoreFunction { +export function timestampToUnixMicros(expr: Expr | string): FirestoreFunction { return fieldOfOrExpr(expr).timestampToUnixMicros(); } @@ -6802,7 +6659,7 @@ export function timestampToUnixMicros( * @param expr The expression representing the number of milliseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMillisToTimestamp(expr: ScalarExpr): FirestoreFunction; +export function unixMillisToTimestamp(expr: Expr): FirestoreFunction; /** * @beta @@ -6819,9 +6676,7 @@ export function unixMillisToTimestamp(expr: ScalarExpr): FirestoreFunction; * @return A new {@code Expr} representing the timestamp. */ export function unixMillisToTimestamp(field: string): FirestoreFunction; -export function unixMillisToTimestamp( - expr: ScalarExpr | string -): FirestoreFunction { +export function unixMillisToTimestamp(expr: Expr | string): FirestoreFunction { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.unixMillisToTimestamp(); } @@ -6839,7 +6694,7 @@ export function unixMillisToTimestamp( * @param expr The expression representing the timestamp. * @return A new {@code Expr} representing the number of milliseconds since epoch. */ -export function timestampToUnixMillis(expr: ScalarExpr): FirestoreFunction; +export function timestampToUnixMillis(expr: Expr): FirestoreFunction; /** * @beta @@ -6855,9 +6710,7 @@ export function timestampToUnixMillis(expr: ScalarExpr): FirestoreFunction; * @return A new {@code Expr} representing the number of milliseconds since epoch. */ export function timestampToUnixMillis(field: string): FirestoreFunction; -export function timestampToUnixMillis( - expr: ScalarExpr | string -): FirestoreFunction { +export function timestampToUnixMillis(expr: Expr | string): FirestoreFunction { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.timestampToUnixMillis(); } @@ -6876,7 +6729,7 @@ export function timestampToUnixMillis( * @param expr The expression representing the number of seconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixSecondsToTimestamp(expr: ScalarExpr): FirestoreFunction; +export function unixSecondsToTimestamp(expr: Expr): FirestoreFunction; /** * @beta @@ -6893,9 +6746,7 @@ export function unixSecondsToTimestamp(expr: ScalarExpr): FirestoreFunction; * @return A new {@code Expr} representing the timestamp. */ export function unixSecondsToTimestamp(field: string): FirestoreFunction; -export function unixSecondsToTimestamp( - expr: ScalarExpr | string -): FirestoreFunction { +export function unixSecondsToTimestamp(expr: Expr | string): FirestoreFunction { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.unixSecondsToTimestamp(); } @@ -6913,7 +6764,7 @@ export function unixSecondsToTimestamp( * @param expr The expression representing the timestamp. * @return A new {@code Expr} representing the number of seconds since epoch. */ -export function timestampToUnixSeconds(expr: ScalarExpr): FirestoreFunction; +export function timestampToUnixSeconds(expr: Expr): FirestoreFunction; /** * @beta @@ -6929,9 +6780,7 @@ export function timestampToUnixSeconds(expr: ScalarExpr): FirestoreFunction; * @return A new {@code Expr} representing the number of seconds since epoch. */ export function timestampToUnixSeconds(field: string): FirestoreFunction; -export function timestampToUnixSeconds( - expr: ScalarExpr | string -): FirestoreFunction { +export function timestampToUnixSeconds(expr: Expr | string): FirestoreFunction { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.timestampToUnixSeconds(); } @@ -6952,9 +6801,9 @@ export function timestampToUnixSeconds( * @return A new {@code Expr} representing the resulting timestamp. */ export function timestampAdd( - timestamp: ScalarExpr, - unit: ScalarExpr, - amount: ScalarExpr + timestamp: Expr, + unit: Expr, + amount: Expr ): FirestoreFunction; /** @@ -6973,7 +6822,7 @@ export function timestampAdd( * @return A new {@code Expr} representing the resulting timestamp. */ export function timestampAdd( - timestamp: ScalarExpr, + timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number ): FirestoreFunction; @@ -6999,16 +6848,16 @@ export function timestampAdd( amount: number ): FirestoreFunction; export function timestampAdd( - timestamp: ScalarExpr | string, + timestamp: Expr | string, unit: - | ScalarExpr + | Expr | 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', - amount: ScalarExpr | number + amount: Expr | number ): FirestoreFunction { const normalizedTimestamp = fieldOfOrExpr(timestamp); const normalizedUnit = valueToDefaultExpr(unit); @@ -7032,9 +6881,9 @@ export function timestampAdd( * @return A new {@code Expr} representing the resulting timestamp. */ export function timestampSub( - timestamp: ScalarExpr, - unit: ScalarExpr, - amount: ScalarExpr + timestamp: Expr, + unit: Expr, + amount: Expr ): FirestoreFunction; /** @@ -7053,7 +6902,7 @@ export function timestampSub( * @return A new {@code Expr} representing the resulting timestamp. */ export function timestampSub( - timestamp: ScalarExpr, + timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number ): FirestoreFunction; @@ -7079,16 +6928,16 @@ export function timestampSub( amount: number ): FirestoreFunction; export function timestampSub( - timestamp: ScalarExpr | string, + timestamp: Expr | string, unit: - | ScalarExpr + | Expr | 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', - amount: ScalarExpr | number + amount: Expr | number ): FirestoreFunction { const normalizedTimestamp = fieldOfOrExpr(timestamp); const normalizedUnit = valueToDefaultExpr(unit); @@ -7221,7 +7070,7 @@ export function orFunction( * @param expr The expression to create an ascending ordering for. * @return A new `Ordering` for ascending sorting. */ -export function ascending(expr: ScalarExpr): Ordering { +export function ascending(expr: Expr): Ordering { return new Ordering(expr, 'ascending'); } @@ -7239,9 +7088,9 @@ export function ascending(expr: ScalarExpr): Ordering { * @param expr The expression to create a descending ordering for. * @return A new `Ordering` for descending sorting. */ -export function descending(expr: ScalarExpr): Ordering; +export function descending(expr: Expr): Ordering; export function descending(fieldName: string): Ordering; -export function descending(field: ScalarExpr | string): Ordering { +export function descending(field: Expr | string): Ordering { return new Ordering(fieldOfOrExpr(field), 'descending'); } @@ -7254,7 +7103,7 @@ export function descending(field: ScalarExpr | string): Ordering { */ export class Ordering { constructor( - readonly expr: ScalarExpr, + readonly expr: Expr, readonly direction: 'ascending' | 'descending' ) {} diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index 5b6c6d578fe..e4260058c22 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -33,13 +33,12 @@ import { AggregateFunction, AggregateFunctionWithAlias, Constant, - ScalarExpr, + Expr, ExprWithAlias, Field, BooleanExpr, Ordering, - Selectable, - Expr + Selectable } from './expressions'; import { PipelineResult } from './pipeline-result'; import { DocumentReference } from './reference'; @@ -158,7 +157,7 @@ export class Pipeline implements ProtoSerializable { * * - {@link Field}: References an existing document field. * - {@link Function}: Performs a calculation using functions like `add`, `multiply` with - * assigned aliases using {@link ScalarExpr#as}. + * assigned aliases using {@link Expr#as}. * * Example: * @@ -215,7 +214,7 @@ export class Pipeline implements ProtoSerializable { *
  • {@code string}: Name of an existing field
  • *
  • {@link Field}: References an existing field.
  • *
  • {@link Function}: Represents the result of a function with an assigned alias name using - * {@link ScalarExpr#as}
  • + * {@link Expr#as} * * *

    If no selections are provided, the output of this stage is empty. Use {@link @@ -238,8 +237,7 @@ export class Pipeline implements ProtoSerializable { * @return A new Pipeline object with this stage appended to the stage list. */ select(...selections: Array): Pipeline { - let projections: Map = - this.selectablesToMap(selections); + let projections: Map = this.selectablesToMap(selections); projections = this.readUserData('select', projections); return this._addStage(new Select(projections)); } @@ -348,10 +346,10 @@ export class Pipeline implements ProtoSerializable { } /** - * Returns a set of distinct {@link ScalarExpr} values from the inputs to this stage. + * Returns a set of distinct {@link Expr} values from the inputs to this stage. * *

    This stage run through the results from previous stages to include only results with unique - * combinations of {@link ScalarExpr} values ({@link Field}, {@link Function}, etc). + * combinations of {@link Expr} values ({@link Field}, {@link Function}, etc). * *

    The parameters to this stage are defined using {@link Selectable} expressions or {@code string}s: * @@ -359,7 +357,7 @@ export class Pipeline implements ProtoSerializable { *

  • {@code string}: Name of an existing field
  • *
  • {@link Field}: References an existing document field.
  • *
  • {@link Function}: Represents the result of a function with an assigned alias name using - * {@link ScalarExpr#as}
  • + * {@link Expr#as} * * *

    Example: @@ -388,7 +386,7 @@ export class Pipeline implements ProtoSerializable { * *

    This stage allows you to calculate aggregate values over a set of documents. You define the * aggregations to perform using {@link AggregateFunctionWithAlias} expressions which are typically results of - * calling {@link ScalarExpr#as} on {@link AggregateFunction} instances. + * calling {@link Expr#as} on {@link AggregateFunction} instances. * *

    Example: * @@ -419,7 +417,7 @@ export class Pipeline implements ProtoSerializable { * specifying groups is the same as putting the entire inputs into one group. *

  • **Accumulators:** One or more accumulation operations to perform within each group. These * are defined using {@link AggregateFunctionWithAlias} expressions, which are typically created by - * calling {@link ScalarExpr#as} on {@link AggregateFunction} instances. Each aggregation + * calling {@link Expr#as} on {@link AggregateFunction} instances. Each aggregation * calculates a value (e.g., sum, average, count) based on the documents within its group.
  • * * @@ -484,7 +482,7 @@ export class Pipeline implements ProtoSerializable { ) ]) ), - new Map() + new Map() ) ); } @@ -708,14 +706,12 @@ export class Pipeline implements ProtoSerializable { * @return A new {@code Pipeline} object with this stage appended to the stage list. */ unnest(selectable: Selectable, indexField?: string): Pipeline { - const field = - selectable instanceof ExprWithAlias ? selectable.expr : selectable; - this.readUserData('unnest', field); + this.readUserData('unnest', selectable.expr); const alias = Field.of(selectable.alias); this.readUserData('unnest', alias); - return this._addStage(new Unnest(field, alias, indexField)); + return this._addStage(new Unnest(selectable.expr, alias, indexField)); } /** @@ -746,6 +742,9 @@ export class Pipeline implements ProtoSerializable { const expressionParams = params.map((value: any) => { if (value instanceof Expr) { return value; + } + if (value instanceof AggregateFunction) { + return value; } else if (isPlainObject(value)) { return _mapValue(value); } else { @@ -841,15 +840,15 @@ export class Pipeline implements ProtoSerializable { private selectablesToMap( selectables: Array - ): Map { - const result = new Map(); + ): Map { + const result = new Map(); for (const selectable of selectables) { if (typeof selectable === 'string') { result.set(selectable as string, Field.of(selectable)); } else if (selectable instanceof Field) { result.set((selectable as Field).fieldName(), selectable); } else if (selectable instanceof ExprWithAlias) { - const expr = selectable as ExprWithAlias; + const expr = selectable as ExprWithAlias; result.set(expr.alias, expr.expr); } } diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index 88c5e2d8d7a..99c7f156140 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -32,11 +32,10 @@ import { hardAssert } from '../util/assert'; import { AggregateFunction, - ScalarExpr, + Expr, Field, BooleanExpr, - Ordering, - Expr + Ordering } from './expressions'; import { Pipeline } from './pipeline'; import { DocumentReference } from './reference'; @@ -55,7 +54,7 @@ export interface Stage extends ProtoSerializable { export class AddFields implements Stage { name = 'add_fields'; - constructor(private fields: Map) {} + constructor(private fields: Map) {} /** * @internal @@ -97,7 +96,7 @@ export class Aggregate implements Stage { constructor( private accumulators: Map, - private groups: Map + private groups: Map ) {} /** @@ -121,7 +120,7 @@ export class Aggregate implements Stage { export class Distinct implements Stage { name = 'distinct'; - constructor(private groups: Map) {} + constructor(private groups: Map) {} /** * @internal @@ -245,7 +244,7 @@ export class Where implements Stage { _toProto(serializer: JsonProtoSerializer): ProtoStage { return { name: this.name, - args: [(this.condition as unknown as ScalarExpr)._toProto(serializer)] + args: [(this.condition as unknown as Expr)._toProto(serializer)] }; } } @@ -369,7 +368,7 @@ export class Offset implements Stage { export class Select implements Stage { name = 'select'; - constructor(private projections: Map) {} + constructor(private projections: Map) {} /** * @internal @@ -441,7 +440,7 @@ export class Union implements Stage { export class Unnest implements Stage { name = 'unnest'; constructor( - private expr: ScalarExpr, + private expr: Expr, private alias: Field, private indexField?: string ) {} @@ -492,7 +491,10 @@ export class GenericStage implements Stage { * @private * @internal */ - constructor(public name: string, private params: Expr[]) {} + constructor( + public name: string, + private params: Array + ) {} /** * @internal diff --git a/packages/firestore/src/lite-api/user_data_reader.ts b/packages/firestore/src/lite-api/user_data_reader.ts index 7d24482c95e..576d17c6f84 100644 --- a/packages/firestore/src/lite-api/user_data_reader.ts +++ b/packages/firestore/src/lite-api/user_data_reader.ts @@ -65,7 +65,7 @@ import { Dict, forEach, isEmpty } from '../util/obj'; import { Bytes } from './bytes'; import { Firestore } from './database'; -import { Expr } from './expressions'; +import { AggregateFunction, Expr } from './expressions'; import { FieldPath } from './field_path'; import { FieldValue } from './field_value'; import { GeoPoint } from './geo_point'; @@ -912,6 +912,8 @@ export function parseScalarValue( return parseVectorValue(value, context); } else if (value instanceof Expr) { return value._toProto(context.serializer); + } else if (value instanceof AggregateFunction) { + return value._toProto(context.serializer); } else { throw context.createError( `Unsupported field value: ${valueDescription(value)}` @@ -970,7 +972,8 @@ export function looksLikeJsonObject(input: unknown): boolean { !(input instanceof DocumentReference) && !(input instanceof FieldValue) && !(input instanceof VectorValue) && - !(input instanceof Expr) + !(input instanceof Expr) && + !(input instanceof AggregateFunction) ); } From 3b386886061e81ce629605a56a2871a56b0e51d1 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 26 Feb 2025 11:43:54 -0700 Subject: [PATCH 36/75] Remove deleted Expr classes from the pipelines exports --- .../firestore/lite/pipelines/pipelines.ts | 61 ------------- packages/firestore/src/api_pipelines.ts | 91 ------------------- 2 files changed, 152 deletions(-) diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index 1109b41755d..26592a34e35 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -139,67 +139,6 @@ export { Field, Constant, FirestoreFunction, - Add, - Subtract, - Multiply, - Divide, - Mod, - Eq, - Neq, - Lt, - Lte, - Gt, - Gte, - ArrayConcat, - ArrayReverse, - ArrayContains, - ArrayContainsAll, - ArrayContainsAny, - ArrayLength, - ArrayElement, - EqAny, - IsNan, - Exists, - Not, - And, - Or, - Xor, - Cond, - LogicalMaximum, - LogicalMinimum, - Reverse, - ReplaceFirst, - ReplaceAll, - CharLength, - ByteLength, - Like, - RegexContains, - RegexMatch, - StrContains, - StartsWith, - EndsWith, - ToLower, - ToUpper, - Trim, - StrConcat, - MapGet, - Count, - Sum, - Avg, - Minimum, - Maximum, - CosineDistance, - DotProduct, - EuclideanDistance, - VectorLength, - UnixMicrosToTimestamp, - TimestampToUnixMicros, - UnixMillisToTimestamp, - TimestampToUnixMillis, - UnixSecondsToTimestamp, - TimestampToUnixSeconds, - TimestampAdd, - TimestampSub, Ordering, ExprType, AggregateFunctionWithAlias, diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index 1e1b118ef9e..66dec15ce22 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -129,105 +129,14 @@ export { map, mapRemove, mapMerge, - parentFunction, - collectionId, documentIdFunction, - key, substr, manhattanDistance, - CountIf, - BitAnd, - BitOr, - BitXor, - BitNot, - BitLeftShift, - BitRightShift, - Rand, - ArrayFunction, - ArrayOffset, - CurrentContext, - IsError, - IfError, - IsAbsent, - IsNull, - IsNotNull, - IsNotNan, - MapFunction, - MapRemove, - MapMerge, - Parent, - CollectionId, - DocumentId, - Key, - Substr, - ManhattanDistance, Expr, ExprWithAlias, Field, Constant, FirestoreFunction, - Add, - Subtract, - Multiply, - Divide, - Mod, - Eq, - Neq, - Lt, - Lte, - Gt, - Gte, - ArrayConcat, - ArrayReverse, - ArrayContains, - ArrayContainsAll, - ArrayContainsAny, - ArrayLength, - ArrayElement, - EqAny, - NotEqAny, - IsNan, - Exists, - Not, - And, - Or, - Xor, - Cond, - LogicalMaximum, - LogicalMinimum, - Reverse, - ReplaceFirst, - ReplaceAll, - CharLength, - ByteLength, - Like, - RegexContains, - RegexMatch, - StrContains, - StartsWith, - EndsWith, - ToLower, - ToUpper, - Trim, - StrConcat, - MapGet, - Count, - Sum, - Avg, - Minimum, - Maximum, - CosineDistance, - DotProduct, - EuclideanDistance, - VectorLength, - UnixMicrosToTimestamp, - TimestampToUnixMicros, - UnixMillisToTimestamp, - TimestampToUnixMillis, - UnixSecondsToTimestamp, - TimestampToUnixSeconds, - TimestampAdd, - TimestampSub, Ordering } from './lite-api/expressions'; From 83e2cfe185a4af51a0bb69d9d84eac7ae4bb836d Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 26 Feb 2025 11:44:50 -0700 Subject: [PATCH 37/75] Replace not(fn()) with notFn() in the query to pipeline conversion --- packages/firestore/src/core/pipeline-util.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index 06b14a6306e..20d9ab9373c 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -20,7 +20,6 @@ import { Constant, Field, BooleanExpr, - not, andFunction, orFunction, Ordering, @@ -61,13 +60,13 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { if (f.op === Operator.EQUAL) { return andFunction(field.exists(), field.isNan()); } else { - return andFunction(field.exists(), not(field.isNan())); + return andFunction(field.exists(), field.isNotNan()); } } else if (isNullValue(f.value)) { if (f.op === Operator.EQUAL) { return andFunction(field.exists(), field.eq(null)); } else { - return andFunction(field.exists(), not(field.eq(null))); + return andFunction(field.exists(), field.neq(null)); } } else { // Comparison filters @@ -124,7 +123,7 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { const values = value?.arrayValue?.values?.map((val: any) => Constant._fromProto(val) ); - return andFunction(field.exists(), not(field.eqAny(...values!))); + return andFunction(field.exists(), field.notEqAny(...values!)); } default: fail('Unexpected operator'); From 4526ad1bf7cbe0f091bc0b437427ee6d8b484701 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 26 Feb 2025 11:46:01 -0700 Subject: [PATCH 38/75] Fix circular dependency between user_data_reader and expressions --- packages/firestore/src/lite-api/expressions.ts | 16 ++++++---------- .../firestore/src/lite-api/user_data_reader.ts | 11 ++++------- packages/firestore/src/remote/serializer.ts | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index b9b8f75cdeb..8aaf0973860 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -25,6 +25,7 @@ import { Value as ProtoValue } from '../protos/firestore_proto_api'; import { JsonProtoSerializer, ProtoSerializable, + ProtoValueSerializable, toMapValue, toStringValue, UserData @@ -129,7 +130,7 @@ function fieldOfOrExpr(value: any): Expr { * The `Expr` class provides a fluent API for building expressions. You can chain together * method calls to create complex expressions. */ -export abstract class Expr implements ProtoSerializable, UserData { +export abstract class Expr implements ProtoValueSerializable, UserData { abstract exprType: ExprType; /** @@ -137,6 +138,7 @@ export abstract class Expr implements ProtoSerializable, UserData { * @internal */ abstract _toProto(serializer: JsonProtoSerializer): ProtoValue; + _protoValueType = 'ProtoValue' as const; /** * @private @@ -2088,20 +2090,12 @@ export interface Selectable { readonly expr: Expr; } -export function _isSelectable(value: any): value is Selectable { - return value.selectable && - typeof value.alias === 'string' && - value.expr instanceof Expr; -} - /** * @beta * * A class that represents an aggregate function. */ -export class AggregateFunction - implements ProtoSerializable, UserData -{ +export class AggregateFunction implements ProtoValueSerializable, UserData { exprType: ExprType = 'AggregateFunction'; constructor(private name: string, private params: Expr[]) {} @@ -2137,6 +2131,8 @@ export class AggregateFunction }; } + _protoValueType = 'ProtoValue' as const; + /** * @private * @internal diff --git a/packages/firestore/src/lite-api/user_data_reader.ts b/packages/firestore/src/lite-api/user_data_reader.ts index 576d17c6f84..733fa9050cd 100644 --- a/packages/firestore/src/lite-api/user_data_reader.ts +++ b/packages/firestore/src/lite-api/user_data_reader.ts @@ -56,7 +56,8 @@ import { JsonProtoSerializer, toBytes, toResourceName, - toTimestamp + toTimestamp, + isProtoValueSerializable } from '../remote/serializer'; import { debugAssert, fail } from '../util/assert'; import { Code, FirestoreError } from '../util/error'; @@ -65,7 +66,6 @@ import { Dict, forEach, isEmpty } from '../util/obj'; import { Bytes } from './bytes'; import { Firestore } from './database'; -import { AggregateFunction, Expr } from './expressions'; import { FieldPath } from './field_path'; import { FieldValue } from './field_value'; import { GeoPoint } from './geo_point'; @@ -910,9 +910,7 @@ export function parseScalarValue( }; } else if (value instanceof VectorValue) { return parseVectorValue(value, context); - } else if (value instanceof Expr) { - return value._toProto(context.serializer); - } else if (value instanceof AggregateFunction) { + } else if (isProtoValueSerializable(value)) { return value._toProto(context.serializer); } else { throw context.createError( @@ -972,8 +970,7 @@ export function looksLikeJsonObject(input: unknown): boolean { !(input instanceof DocumentReference) && !(input instanceof FieldValue) && !(input instanceof VectorValue) && - !(input instanceof Expr) && - !(input instanceof AggregateFunction) + !isProtoValueSerializable(input) ); } diff --git a/packages/firestore/src/remote/serializer.ts b/packages/firestore/src/remote/serializer.ts index 617816615aa..e0688db9d90 100644 --- a/packages/firestore/src/remote/serializer.ts +++ b/packages/firestore/src/remote/serializer.ts @@ -1434,6 +1434,21 @@ export interface ProtoSerializable { _toProto(serializer: JsonProtoSerializer): ProtoType; } +export interface ProtoValueSerializable extends ProtoSerializable { + // Supports runtime identification of the ProtoSerializable type. + _protoValueType: 'ProtoValue'; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function isProtoValueSerializable( + value: any +): value is ProtoValueSerializable { + return ( + typeof value._toProto === 'function' && + value._protoValueType === 'ProtoValue' + ); +} + export interface UserData { _readUserData(dataReader: UserDataReader): void; } From 2e981af032ee646742d26fc60d0cbd18758577e3 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:03:22 -0700 Subject: [PATCH 39/75] removing modular pipeline creation and removing fluent pipline execution. This was a decision from API review --- packages/firestore/src/api/pipeline.ts | 63 +- packages/firestore/src/api/pipeline_impl.ts | 107 +- packages/firestore/src/api_pipelines.ts | 2 +- packages/firestore/src/lite-api/pipeline.ts | 75 +- .../firestore/src/lite-api/pipeline_impl.ts | 123 +- .../test/integration/api/pipeline.test.ts | 1719 +++++++++-------- .../integration/api/query_to_pipeline.test.ts | 58 +- 7 files changed, 1054 insertions(+), 1093 deletions(-) diff --git a/packages/firestore/src/api/pipeline.ts b/packages/firestore/src/api/pipeline.ts index 500dd1afba6..e7cd6e875eb 100644 --- a/packages/firestore/src/api/pipeline.ts +++ b/packages/firestore/src/api/pipeline.ts @@ -15,16 +15,12 @@ * limitations under the License. */ -import { firestoreClientExecutePipeline } from '../core/firestore_client'; import { Pipeline as LitePipeline } from '../lite-api/pipeline'; -import { PipelineResult } from '../lite-api/pipeline-result'; -import { DocumentReference } from '../lite-api/reference'; import { Stage } from '../lite-api/stage'; import { UserDataReader } from '../lite-api/user_data_reader'; import { AbstractUserDataWriter } from '../lite-api/user_data_writer'; -import { cast } from '../util/input_validation'; -import { ensureFirestoreConfigured, Firestore } from './database'; +import { Firestore } from './database'; export class Pipeline extends LitePipeline { /** @@ -45,61 +41,4 @@ export class Pipeline extends LitePipeline { ): Pipeline { return new Pipeline(db, userDataReader, userDataWriter, stages); } - - /** - * Executes this pipeline and returns a Promise to represent the asynchronous operation. - * - *

    The returned Promise can be used to track the progress of the pipeline execution - * and retrieve the results (or handle any errors) asynchronously. - * - *

    The pipeline results are returned as a list of {@link PipelineResult} objects. Each {@link - * PipelineResult} typically represents a single key/value map that has passed through all the - * stages of the pipeline, however this might differ depending on the stages involved in the - * pipeline. For example: - * - *

      - *
    • If there are no stages or only transformation stages, each {@link PipelineResult} - * represents a single document.
    • - *
    • If there is an aggregation, only a single {@link PipelineResult} is returned, - * representing the aggregated results over the entire dataset .
    • - *
    • If there is an aggregation stage with grouping, each {@link PipelineResult} represents a - * distinct group and its associated aggregated values.
    • - *
    - * - *

    Example: - * - * ```typescript - * const futureResults = await firestore.pipeline().collection("books") - * .where(gt(Field.of("rating"), 4.5)) - * .select("title", "author", "rating") - * .execute(); - * ``` - * - * @return A Promise representing the asynchronous pipeline execution. - */ - execute(): Promise { - const firestore = cast(this._db, Firestore); - const client = ensureFirestoreConfigured(firestore); - return firestoreClientExecutePipeline(client, this).then(result => { - const docs = result - // Currently ignore any response from ExecutePipeline that does - // not contain any document data in the `fields` property. - .filter(element => !!element.fields) - .map( - element => - new PipelineResult( - this._userDataWriter, - element.key?.path - ? new DocumentReference(firestore, null, element.key) - : undefined, - element.fields, - element.executionTime?.toTimestamp(), - element.createTime?.toTimestamp(), - element.updateTime?.toTimestamp() - ) - ); - - return docs; - }); - } } diff --git a/packages/firestore/src/api/pipeline_impl.ts b/packages/firestore/src/api/pipeline_impl.ts index 458669246d1..fc79ef2e5c5 100644 --- a/packages/firestore/src/api/pipeline_impl.ts +++ b/packages/firestore/src/api/pipeline_impl.ts @@ -16,6 +16,7 @@ */ import { Pipeline } from '../api/pipeline'; +import { firestoreClientExecutePipeline } from '../core/firestore_client'; import { toPipeline } from '../core/pipeline-util'; import { Pipeline as LitePipeline } from '../lite-api/pipeline'; import { PipelineResult } from '../lite-api/pipeline-result'; @@ -24,8 +25,8 @@ import { Stage } from '../lite-api/stage'; import { newUserDataReader } from '../lite-api/user_data_reader'; import { cast } from '../util/input_validation'; -import { Firestore } from './database'; -import { Query } from './reference'; +import { ensureFirestoreConfigured, Firestore } from './database'; +import { DocumentReference, Query } from './reference'; import { ExpUserDataWriter } from './user_data_writer'; declare module './database' { @@ -35,52 +36,78 @@ declare module './database' { } /** - * Experimental Modular API for console testing. - * @param firestore - */ -export function pipeline(firestore: Firestore): PipelineSource; - -/** - * Experimental Modular API for console testing. - * @param query + * Executes this pipeline and returns a Promise to represent the asynchronous operation. + * + *

    The returned Promise can be used to track the progress of the pipeline execution + * and retrieve the results (or handle any errors) asynchronously. + * + *

    The pipeline results are returned as a list of {@link PipelineResult} objects. Each {@link + * PipelineResult} typically represents a single key/value map that has passed through all the + * stages of the pipeline, however this might differ depending on the stages involved in the + * pipeline. For example: + * + *

      + *
    • If there are no stages or only transformation stages, each {@link PipelineResult} + * represents a single document.
    • + *
    • If there is an aggregation, only a single {@link PipelineResult} is returned, + * representing the aggregated results over the entire dataset .
    • + *
    • If there is an aggregation stage with grouping, each {@link PipelineResult} represents a + * distinct group and its associated aggregated values.
    • + *
    + * + *

    Example: + * + * ```typescript + * const futureResults = await execute(firestore.pipeline().collection("books") + * .where(gt(Field.of("rating"), 4.5)) + * .select("title", "author", "rating")); + * ``` + * + * @param pipeline The pipeline to execute. + * @return A Promise representing the asynchronous pipeline execution. */ -export function pipeline(query: Query): Pipeline; - -export function pipeline( - firestoreOrQuery: Firestore | Query -): PipelineSource | Pipeline { - if (firestoreOrQuery instanceof Firestore) { - const firestore = firestoreOrQuery; - return new PipelineSource( - firestore._databaseId, - (stages: Stage[]) => { - return new Pipeline( - firestore, - newUserDataReader(firestore), - new ExpUserDataWriter(firestore), - stages - ); - } - ); - } else { - const query = firestoreOrQuery; - const db = cast(query.firestore, Firestore); - - const litePipeline: LitePipeline = toPipeline(query._query, db); - return cast(litePipeline, Pipeline); - } -} - export function execute(pipeline: LitePipeline): Promise { - return pipeline.execute(); + const firestore = cast(pipeline._db, Firestore); + const client = ensureFirestoreConfigured(firestore); + return firestoreClientExecutePipeline(client, pipeline).then(result => { + const docs = result + // Currently ignore any response from ExecutePipeline that does + // not contain any document data in the `fields` property. + .filter(element => !!element.fields) + .map( + element => + new PipelineResult( + pipeline._userDataWriter, + element.key?.path + ? new DocumentReference(firestore, null, element.key) + : undefined, + element.fields, + element.executionTime?.toTimestamp(), + element.createTime?.toTimestamp(), + element.updateTime?.toTimestamp() + ) + ); + + return docs; + }); } // Augment the Firestore class with the pipeline() factory method Firestore.prototype.pipeline = function (): PipelineSource { - return pipeline(this); + return new PipelineSource(this._databaseId, (stages: Stage[]) => { + return new Pipeline( + this, + newUserDataReader(this), + new ExpUserDataWriter(this), + stages + ); + }); }; // Augment the Query class with the pipeline() factory method Query.prototype.pipeline = function (): Pipeline { - return pipeline(this); + const db = cast(this.firestore, Firestore); + + const litePipeline: LitePipeline = toPipeline(this._query, db); + return cast(litePipeline, Pipeline); }; diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index 66dec15ce22..9ece7bfad7e 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -21,7 +21,7 @@ export { PipelineResult } from './lite-api/pipeline-result'; export { Pipeline } from './api/pipeline'; -export { pipeline, execute } from './api/pipeline_impl'; +export { execute } from './api/pipeline_impl'; export { Stage, diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index e4260058c22..7ea14328387 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -22,11 +22,9 @@ import { Pipeline as ProtoPipeline, Stage as ProtoStage } from '../protos/firestore_proto_api'; -import { invokeExecutePipeline } from '../remote/datastore'; import { JsonProtoSerializer, ProtoSerializable } from '../remote/serializer'; import { isPlainObject } from '../util/input_validation'; -import { getDatastore } from './components'; import { Firestore } from './database'; import { _mapValue, @@ -40,8 +38,6 @@ import { Ordering, Selectable } from './expressions'; -import { PipelineResult } from './pipeline-result'; -import { DocumentReference } from './reference'; import { AddFields, Aggregate, @@ -99,23 +95,20 @@ function isReadableUserData(value: any): value is ReadableUserData { * const db: Firestore; // Assumes a valid firestore instance. * * // Example 1: Select specific fields and rename 'rating' to 'bookRating' - * const results1 = await db.pipeline() + * const results1 = await execute(db.pipeline() * .collection("books") - * .select("title", "author", Field.of("rating").as("bookRating")) - * .execute(); + * .select("title", "author", Field.of("rating").as("bookRating"))); * * // Example 2: Filter documents where 'genre' is "Science Fiction" and 'published' is after 1950 - * const results2 = await db.pipeline() + * const results2 = await execute(db.pipeline() * .collection("books") - * .where(and(Field.of("genre").eq("Science Fiction"), Field.of("published").gt(1950))) - * .execute(); + * .where(and(Field.of("genre").eq("Science Fiction"), Field.of("published").gt(1950)))); * * // Example 3: Calculate the average rating of books published after 1980 - * const results3 = await db.pipeline() + * const results3 = await execute(db.pipeline() * .collection("books") * .where(Field.of("published").gt(1980)) - * .aggregate(avg(Field.of("rating")).as("averageRating")) - * .execute(); + * .aggregate(avg(Field.of("rating")).as("averageRating"))); * ``` */ @@ -760,62 +753,6 @@ export class Pipeline implements ProtoSerializable { return this._addStage(new GenericStage(name, expressionParams)); } - /** - * Executes this pipeline and returns a Promise to represent the asynchronous operation. - * - *

    The returned Promise can be used to track the progress of the pipeline execution - * and retrieve the results (or handle any errors) asynchronously. - * - *

    The pipeline results are returned as a list of {@link PipelineResult} objects. Each {@link - * PipelineResult} typically represents a single key/value map that has passed through all the - * stages of the pipeline, however this might differ depending on the stages involved in the - * pipeline. For example: - * - *

      - *
    • If there are no stages or only transformation stages, each {@link PipelineResult} - * represents a single document.
    • - *
    • If there is an aggregation, only a single {@link PipelineResult} is returned, - * representing the aggregated results over the entire dataset .
    • - *
    • If there is an aggregation stage with grouping, each {@link PipelineResult} represents a - * distinct group and its associated aggregated values.
    • - *
    - * - *

    Example: - * - * ```typescript - * const futureResults = await firestore.pipeline().collection("books") - * .where(gt(Field.of("rating"), 4.5)) - * .select("title", "author", "rating") - * .execute(); - * ``` - * - * @return A Promise representing the asynchronous pipeline execution. - */ - execute(): Promise { - const datastore = getDatastore(this._db); - return invokeExecutePipeline(datastore, this).then(result => { - return ( - result - // Currently ignore any response from ExecutePipeline that does - // not contain any document data in the `fields` property. - .filter(element => !!element.fields) - .map( - element => - new PipelineResult( - this._userDataWriter, - element.key?.path - ? new DocumentReference(this._db, null, element.key) - : undefined, - element.fields, - element.executionTime?.toTimestamp(), - element.createTime?.toTimestamp(), - element.updateTime?.toTimestamp() - ) - ) - ); - }); - } - /** * @internal * @private diff --git a/packages/firestore/src/lite-api/pipeline_impl.ts b/packages/firestore/src/lite-api/pipeline_impl.ts index 5050595e142..d00435055c7 100644 --- a/packages/firestore/src/lite-api/pipeline_impl.ts +++ b/packages/firestore/src/lite-api/pipeline_impl.ts @@ -15,11 +15,14 @@ * limitations under the License. */ +import { invokeExecutePipeline } from '../remote/datastore'; + +import { getDatastore } from './components'; import { Firestore } from './database'; import { Pipeline } from './pipeline'; import { PipelineResult } from './pipeline-result'; import { PipelineSource } from './pipeline-source'; -import { Query } from './reference'; +import { DocumentReference, Query } from './reference'; import { LiteUserDataWriter } from './reference_impl'; import { Stage } from './stage'; import { newUserDataReader } from './user_data_reader'; @@ -37,60 +40,84 @@ declare module './reference' { } /** - * Modular API for console experimentation. - * @param pipeline Execute this pipeline. - * @beta + * Executes this pipeline and returns a Promise to represent the asynchronous operation. + * + *

    The returned Promise can be used to track the progress of the pipeline execution + * and retrieve the results (or handle any errors) asynchronously. + * + *

    The pipeline results are returned as a list of {@link PipelineResult} objects. Each {@link + * PipelineResult} typically represents a single key/value map that has passed through all the + * stages of the pipeline, however this might differ depending on the stages involved in the + * pipeline. For example: + * + *

      + *
    • If there are no stages or only transformation stages, each {@link PipelineResult} + * represents a single document.
    • + *
    • If there is an aggregation, only a single {@link PipelineResult} is returned, + * representing the aggregated results over the entire dataset .
    • + *
    • If there is an aggregation stage with grouping, each {@link PipelineResult} represents a + * distinct group and its associated aggregated values.
    • + *
    + * + *

    Example: + * + * ```typescript + * const futureResults = await execute(firestore.pipeline().collection("books") + * .where(gt(Field.of("rating"), 4.5)) + * .select("title", "author", "rating")); + * ``` + * + * @param pipeline The pipeline to execute. + * @return A Promise representing the asynchronous pipeline execution. */ export function execute(pipeline: Pipeline): Promise { - return pipeline.execute(); + const datastore = getDatastore(pipeline._db); + return invokeExecutePipeline(datastore, pipeline).then(result => { + return ( + result + // Currently ignore any response from ExecutePipeline that does + // not contain any document data in the `fields` property. + .filter(element => !!element.fields) + .map( + element => + new PipelineResult( + pipeline._userDataWriter, + element.key?.path + ? new DocumentReference(pipeline._db, null, element.key) + : undefined, + element.fields, + element.executionTime?.toTimestamp(), + element.createTime?.toTimestamp(), + element.updateTime?.toTimestamp() + ) + ) + ); + }); } -/** - * Experimental Modular API for console testing. - * @param firestore - */ -export function pipeline(firestore: Firestore): PipelineSource; - -/** - * Experimental Modular API for console testing. - * @param query - */ -export function pipeline(query: Query): Pipeline; +Firestore.prototype.pipeline = function (): PipelineSource { + const userDataWriter = new LiteUserDataWriter(this); + const userDataReader = newUserDataReader(this); + return new PipelineSource(this._databaseId, (stages: Stage[]) => { + return new Pipeline(this, userDataReader, userDataWriter, stages); + }); +}; -export function pipeline( - firestoreOrQuery: Firestore | Query -): PipelineSource | Pipeline { - if (firestoreOrQuery instanceof Firestore) { - const db = firestoreOrQuery; - const userDataWriter = new LiteUserDataWriter(db); - const userDataReader = newUserDataReader(db); - return new PipelineSource(db._databaseId, (stages: Stage[]) => { - return new Pipeline(db, userDataReader, userDataWriter, stages); - }); +Query.prototype.pipeline = function (): Pipeline { + let pipeline; + const query = this; + if (query._query.collectionGroup) { + pipeline = query.firestore + .pipeline() + .collectionGroup(query._query.collectionGroup); } else { - let pipeline; - const query = firestoreOrQuery; - if (query._query.collectionGroup) { - pipeline = query.firestore - .pipeline() - .collectionGroup(query._query.collectionGroup); - } else { - pipeline = query.firestore - .pipeline() - .collection(query._query.path.canonicalString()); - } - - // TODO(pipeline) convert existing query filters, limits, etc into - // pipeline stages - - return pipeline; + pipeline = query.firestore + .pipeline() + .collection(query._query.path.canonicalString()); } -} -Firestore.prototype.pipeline = function (): PipelineSource { - return pipeline(this); -}; + // TODO(pipeline) convert existing query filters, limits, etc into + // pipeline stages -Query.prototype.pipeline = function (): Pipeline { - return pipeline(this); + return pipeline; }; diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 210a990d755..59b95345cf4 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -34,7 +34,6 @@ import { getFirestore, terminate, vector, - pipeline, execute, _internalPipelineToExecutePipelineRequestProto, add, @@ -281,38 +280,36 @@ apiDescribe.only('Pipelines', persistence => { }); it('empty results as expected', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .limit(0) - .execute(); + const result = await execute( + firestore.pipeline().collection(randomCol.path).limit(0) + ); expect(result.length).to.equal(0); }); it('full results as expected', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .execute(); + const result = await execute( + firestore.pipeline().collection(randomCol.path) + ); expect(result.length).to.equal(10); }); it('supports CollectionReference as source', async () => { - const result = await firestore.pipeline().collection(randomCol).execute(); + const result = await execute(firestore.pipeline().collection(randomCol)); expect(result.length).to.equal(10); }); it('supports list of documents as source', async () => { const collName = randomCol.id; - const result = await firestore - .pipeline() - .documents([ - `${collName}/book1`, - doc(randomCol, 'book2'), - doc(randomCol, 'book3').path - ]) - .execute(); + const result = await execute( + firestore + .pipeline() + .documents([ + `${collName}/book1`, + doc(randomCol, 'book2'), + doc(randomCol, 'book3').path + ]) + ); expect(result.length).to.equal(3); }); @@ -337,43 +334,23 @@ apiDescribe.only('Pipelines', persistence => { }); it('converts arrays and plain objects to functionValues if the customer intent is unspecified', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('rating').descending()) - .limit(1) - .select( - 'title', - 'author', - 'genre', - 'rating', - 'published', - 'tags', - 'awards' - ) - .addFields( - array([ - 1, - 2, - Field.of('genre'), - multiply('rating', 10), - [Field.of('title')], - { - published: Field.of('published') - } - ]).as('metadataArray'), - map({ - genre: Field.of('genre'), - rating: multiply('rating', 10), - nestedArray: [Field.of('title')], - nestedMap: { - published: Field.of('published') - } - }).as('metadata') - ) - .where( - andFunction( - eq('metadataArray', [ + const result = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + 'title', + 'author', + 'genre', + 'rating', + 'published', + 'tags', + 'awards' + ) + .addFields( + array([ 1, 2, Field.of('genre'), @@ -382,18 +359,39 @@ apiDescribe.only('Pipelines', persistence => { { published: Field.of('published') } - ]), - eq('metadata', { + ]).as('metadataArray'), + map({ genre: Field.of('genre'), rating: multiply('rating', 10), nestedArray: [Field.of('title')], nestedMap: { published: Field.of('published') } - }) + }).as('metadata') + ) + .where( + andFunction( + eq('metadataArray', [ + 1, + 2, + Field.of('genre'), + multiply('rating', 10), + [Field.of('title')], + { + published: Field.of('published') + } + ]), + eq('metadata', { + genre: Field.of('genre'), + rating: multiply('rating', 10), + nestedArray: [Field.of('title')], + nestedMap: { + published: Field.of('published') + } + }) + ) ) - ) - .execute(); + ); expect(result.length).to.equal(1); @@ -479,11 +477,12 @@ apiDescribe.only('Pipelines', persistence => { ]).as('array') ]; - const results = await randomCol - .pipeline() - .limit(1) - .select(...constants) - .execute(); + const results = await execute( + randomCol + .pipeline() + .limit(1) + .select(...constants) + ); expectResults(results, { 'number': 1, @@ -552,49 +551,53 @@ apiDescribe.only('Pipelines', persistence => { describe('stages', () => { describe('aggregate stage', () => { it('supports aggregate', async () => { - let result = await firestore - .pipeline() - .collection(randomCol.path) - .aggregate(countAll().as('count')) - .execute(); + let result = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .aggregate(countAll().as('count')) + ); expectResults(result, { count: 10 }); - result = await randomCol - .pipeline() - .where(eq('genre', 'Science Fiction')) - .aggregate( - countAll().as('count'), - avgFunction('rating').as('avgRating'), - Field.of('rating').maximum().as('maxRating') - ) - .execute(); + result = await execute( + randomCol + .pipeline() + .where(eq('genre', 'Science Fiction')) + .aggregate( + countAll().as('count'), + avgFunction('rating').as('avgRating'), + Field.of('rating').maximum().as('maxRating') + ) + ); expectResults(result, { count: 2, avgRating: 4.4, maxRating: 4.6 }); }); it('rejects groups without accumulators', async () => { await expect( + execute( + randomCol + .pipeline() + .where(lt('published', 1900)) + .aggregate({ + accumulators: [], + groups: ['genre'] + }) + ) + ).to.be.rejected; + }); + + it('returns group and accumulate results', async () => { + const results = await execute( randomCol .pipeline() - .where(lt('published', 1900)) + .where(lt(Field.of('published'), 1984)) .aggregate({ - accumulators: [], + accumulators: [avgFunction('rating').as('avgRating')], groups: ['genre'] }) - .execute() - ).to.be.rejected; - }); - - it('returns group and accumulate results', async () => { - const results = await randomCol - .pipeline() - .where(lt(Field.of('published'), 1984)) - .aggregate({ - accumulators: [avgFunction('rating').as('avgRating')], - groups: ['genre'] - }) - .where(gt('avgRating', 4.3)) - .sort(Field.of('avgRating').descending()) - .execute(); + .where(gt('avgRating', 4.3)) + .sort(Field.of('avgRating').descending()) + ); expectResults( results, { avgRating: 4.7, genre: 'Fantasy' }, @@ -604,14 +607,15 @@ apiDescribe.only('Pipelines', persistence => { }); it('returns min and max accumulations', async () => { - const results = await randomCol - .pipeline() - .aggregate( - countAll().as('count'), - Field.of('rating').maximum().as('maxRating'), - Field.of('published').minimum().as('minPublished') - ) - .execute(); + const results = await execute( + randomCol + .pipeline() + .aggregate( + countAll().as('count'), + Field.of('rating').maximum().as('maxRating'), + Field.of('published').minimum().as('minPublished') + ) + ); expectResults(results, { count: 10, maxRating: 4.7, @@ -620,30 +624,33 @@ apiDescribe.only('Pipelines', persistence => { }); it('returns countif accumulation', async () => { - let results = await randomCol - .pipeline() - .aggregate(countIf(Field.of('rating').gt(4.3)).as('count')) - .execute(); + let results = await execute( + randomCol + .pipeline() + .aggregate(countIf(Field.of('rating').gt(4.3)).as('count')) + ); const expectedResults = { count: 3 }; expectResults(results, expectedResults); - results = await randomCol - .pipeline() - .aggregate(Field.of('rating').gt(4.3).countIf().as('count')) - .execute(); + results = await execute( + randomCol + .pipeline() + .aggregate(Field.of('rating').gt(4.3).countIf().as('count')) + ); expectResults(results, expectedResults); }); }); describe('distinct stage', () => { it('returns distinct values as expected', async () => { - const results = await randomCol - .pipeline() - .distinct('genre', 'author') - .sort(Field.of('genre').ascending(), Field.of('author').ascending()) - .execute(); + const results = await execute( + randomCol + .pipeline() + .distinct('genre', 'author') + .sort(Field.of('genre').ascending(), Field.of('author').ascending()) + ); expectResults( results, { genre: 'Dystopian', author: 'George Orwell' }, @@ -662,12 +669,13 @@ apiDescribe.only('Pipelines', persistence => { describe('select stage', () => { it('can select fields', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author') - .sort(Field.of('author').ascending()) - .execute(); + const results = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .sort(Field.of('author').ascending()) + ); expectResults( results, { @@ -692,13 +700,14 @@ apiDescribe.only('Pipelines', persistence => { describe('addField stage', () => { it('can add fields', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author') - .addFields(Constant.of('bar').as('foo')) - .sort(Field.of('author').ascending()) - .execute(); + const results = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .addFields(Constant.of('bar').as('foo')) + .sort(Field.of('author').ascending()) + ); expectResults( results, { @@ -745,30 +754,32 @@ apiDescribe.only('Pipelines', persistence => { describe('where stage', () => { it('where with and', async () => { - const results = await randomCol - .pipeline() - .where( - andFunction( - gt('rating', 4.5), - eq('genre', 'Science Fiction'), - lte('published', 1965) + const results = await execute( + randomCol + .pipeline() + .where( + andFunction( + gt('rating', 4.5), + eq('genre', 'Science Fiction'), + lte('published', 1965) + ) ) - ) - .execute(); + ); expectResults(results, 'book10'); }); it('where with or', async () => { - const results = await randomCol - .pipeline() - .where( - orFunction( - eq('genre', 'Romance'), - eq('genre', 'Dystopian'), - eq('genre', 'Fantasy') + const results = await execute( + randomCol + .pipeline() + .where( + orFunction( + eq('genre', 'Romance'), + eq('genre', 'Dystopian'), + eq('genre', 'Fantasy') + ) ) - ) - .select('title') - .execute(); + .select('title') + ); expectResults( results, { title: 'Pride and Prejudice' }, @@ -779,18 +790,19 @@ apiDescribe.only('Pipelines', persistence => { }); it('where with xor', async () => { - const results = await randomCol - .pipeline() - .where( - xor( - eq('genre', 'Romance'), - eq('genre', 'Dystopian'), - eq('genre', 'Fantasy'), - eq('published', 1949) + const results = await execute( + randomCol + .pipeline() + .where( + xor( + eq('genre', 'Romance'), + eq('genre', 'Dystopian'), + eq('genre', 'Fantasy'), + eq('published', 1949) + ) ) - ) - .select('title') - .execute(); + .select('title') + ); expectResults( results, { title: 'Pride and Prejudice' }, @@ -802,14 +814,15 @@ apiDescribe.only('Pipelines', persistence => { describe('sort, offset, and limit stages', () => { it('supports sort, offset, and limits', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('author').ascending()) - .offset(5) - .limit(3) - .select('title', 'author') - .execute(); + const results = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('author').ascending()) + .offset(5) + .limit(3) + .select('title', 'author') + ); expectResults( results, { title: '1984', author: 'George Orwell' }, @@ -821,20 +834,21 @@ apiDescribe.only('Pipelines', persistence => { describe('generic stage', () => { it('can select fields', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .genericStage('select', [ - { - title: Field.of('title'), - metadata: { - 'author': Field.of('author') + const results = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .genericStage('select', [ + { + title: Field.of('title'), + metadata: { + 'author': Field.of('author') + } } - } - ]) - .sort(Field.of('author').ascending()) - .limit(1) - .execute(); + ]) + .sort(Field.of('author').ascending()) + .limit(1) + ); expectResults(results, { title: "The Hitchhiker's Guide to the Galaxy", metadata: { @@ -844,18 +858,19 @@ apiDescribe.only('Pipelines', persistence => { }); it('can add fields', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('author').ascending()) - .limit(1) - .select('title', 'author') - .genericStage('add_fields', [ - { - display: Field.of('title').strConcat(' - ', Field.of('author')) - } - ]) - .execute(); + const results = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('author').ascending()) + .limit(1) + .select('title', 'author') + .genericStage('add_fields', [ + { + display: Field.of('title').strConcat(' - ', Field.of('author')) + } + ]) + ); expectResults(results, { title: "The Hitchhiker's Guide to the Galaxy", author: 'Douglas Adams', @@ -864,12 +879,13 @@ apiDescribe.only('Pipelines', persistence => { }); it('can filter with where', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author') - .genericStage('where', [Field.of('author').eq('Douglas Adams')]) - .execute(); + const results = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .genericStage('where', [Field.of('author').eq('Douglas Adams')]) + ); expectResults(results, { title: "The Hitchhiker's Guide to the Galaxy", author: 'Douglas Adams' @@ -877,19 +893,20 @@ apiDescribe.only('Pipelines', persistence => { }); it('can limit, offset, and sort', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author') - .genericStage('sort', [ - { - direction: 'ascending', - expression: Field.of('author') - } - ]) - .genericStage('offset', [3]) - .genericStage('limit', [1]) - .execute(); + const results = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .genericStage('sort', [ + { + direction: 'ascending', + expression: Field.of('author') + } + ]) + .genericStage('offset', [3]) + .genericStage('limit', [1]) + ); expectResults(results, { author: 'Fyodor Dostoevsky', title: 'Crime and Punishment' @@ -897,28 +914,30 @@ apiDescribe.only('Pipelines', persistence => { }); it('can perform aggregate query', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author', 'rating') - .genericStage('aggregate', [ - { averageRating: Field.of('rating').avg() }, - {} - ]) - .execute(); + const results = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author', 'rating') + .genericStage('aggregate', [ + { averageRating: Field.of('rating').avg() }, + {} + ]) + ); expectResults(results, { averageRating: 4.3100000000000005 }); }); it('can perform distinct query', async () => { - const results = await firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'author', 'rating') - .genericStage('distinct', [{ rating: Field.of('rating') }]) - .sort(Field.of('rating').descending()) - .execute(); + const results = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author', 'rating') + .genericStage('distinct', [{ rating: Field.of('rating') }]) + .sort(Field.of('rating').descending()) + ); expectResults( results, { @@ -948,11 +967,12 @@ apiDescribe.only('Pipelines', persistence => { describe('replace stage', () => { it('run pipleine with replace', async () => { - const results = await randomCol - .pipeline() - .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) - .replaceWith('awards') - .execute(); + const results = await execute( + randomCol + .pipeline() + .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) + .replaceWith('awards') + ); expectResults(results, { hugo: true, nebula: false, @@ -963,15 +983,14 @@ apiDescribe.only('Pipelines', persistence => { describe('sample stage', () => { it('run pipeline with sample limit of 3', async () => { - const results = await randomCol.pipeline().sample(3).execute(); + const results = await execute(randomCol.pipeline().sample(3)); expect(results.length).to.equal(3); }); it('run pipeline with sample limit of {documents: 3}', async () => { - const results = await randomCol - .pipeline() - .sample({ documents: 3 }) - .execute(); + const results = await execute( + randomCol.pipeline().sample({ documents: 3 }) + ); expect(results.length).to.equal(3); }); @@ -979,10 +998,9 @@ apiDescribe.only('Pipelines', persistence => { let avgSize = 0; const numIterations = 20; for (let i = 0; i < numIterations; i++) { - const results = await randomCol - .pipeline() - .sample({ percentage: 0.6 }) - .execute(); + const results = await execute( + randomCol.pipeline().sample({ percentage: 0.6 }) + ); avgSize += results.length; } @@ -993,11 +1011,12 @@ apiDescribe.only('Pipelines', persistence => { describe('union stage', () => { it('run pipeline with union', async () => { - const results = await randomCol - .pipeline() - .union(randomCol.pipeline()) - .sort(Field.of(documentId()).ascending()) - .execute(); + const results = await execute( + randomCol + .pipeline() + .union(randomCol.pipeline()) + .sort(Field.of(documentId()).ascending()) + ); expectResults( results, 'book1', @@ -1026,11 +1045,12 @@ apiDescribe.only('Pipelines', persistence => { describe('unnest stage', () => { it('run pipeline with unnest', async () => { - const results = await randomCol - .pipeline() - .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) - .unnest(Field.of('tags').as('tag')) - .execute(); + const results = await execute( + randomCol + .pipeline() + .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) + .unnest(Field.of('tags').as('tag')) + ); expectResults( results, { @@ -1081,11 +1101,12 @@ apiDescribe.only('Pipelines', persistence => { ); }); it('unnest an expr', async () => { - const results = await randomCol - .pipeline() - .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) - .unnest(array([1, 2, 3]).as('copy')) - .execute(); + const results = await execute( + randomCol + .pipeline() + .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) + .unnest(array([1, 2, 3]).as('copy')) + ); expectResults( results, { @@ -1140,17 +1161,18 @@ apiDescribe.only('Pipelines', persistence => { describe('function expressions', () => { it('logical max works', async () => { - const results = await randomCol - .pipeline() - .select( - 'title', - logicalMaximum(Constant.of(1960), Field.of('published'), 1961).as( - 'published-safe' + const results = await execute( + randomCol + .pipeline() + .select( + 'title', + logicalMaximum(Constant.of(1960), Field.of('published'), 1961).as( + 'published-safe' + ) ) - ) - .sort(Field.of('title').ascending()) - .limit(3) - .execute(); + .sort(Field.of('title').ascending()) + .limit(3) + ); expectResults( results, { title: '1984', 'published-safe': 1961 }, @@ -1160,17 +1182,18 @@ apiDescribe.only('Pipelines', persistence => { }); it('logical min works', async () => { - const results = await randomCol - .pipeline() - .select( - 'title', - logicalMinimum(Constant.of(1960), Field.of('published'), 1961).as( - 'published-safe' + const results = await execute( + randomCol + .pipeline() + .select( + 'title', + logicalMinimum(Constant.of(1960), Field.of('published'), 1961).as( + 'published-safe' + ) ) - ) - .sort(Field.of('title').ascending()) - .limit(3) - .execute(); + .sort(Field.of('title').ascending()) + .limit(3) + ); expectResults( results, { title: '1984', 'published-safe': 1949 }, @@ -1180,19 +1203,20 @@ apiDescribe.only('Pipelines', persistence => { }); it('cond works', async () => { - const results = await randomCol - .pipeline() - .select( - 'title', - cond( - lt(Field.of('published'), 1960), - Constant.of(1960), - Field.of('published') - ).as('published-safe') - ) - .sort(Field.of('title').ascending()) - .limit(3) - .execute(); + const results = await execute( + randomCol + .pipeline() + .select( + 'title', + cond( + lt(Field.of('published'), 1960), + Constant.of(1960), + Field.of('published') + ).as('published-safe') + ) + .sort(Field.of('title').ascending()) + .limit(3) + ); expectResults( results, { title: '1984', 'published-safe': 1960 }, @@ -1202,11 +1226,12 @@ apiDescribe.only('Pipelines', persistence => { }); it('eqAny works', async () => { - const results = await randomCol - .pipeline() - .where(eqAny('published', [1979, 1999, 1967])) - .select('title') - .execute(); + const results = await execute( + randomCol + .pipeline() + .where(eqAny('published', [1979, 1999, 1967])) + .select('title') + ); expectResults( results, { title: "The Hitchhiker's Guide to the Galaxy" }, @@ -1215,36 +1240,39 @@ apiDescribe.only('Pipelines', persistence => { }); it('notEqAny works', async () => { - const results = await randomCol - .pipeline() - .where( - notEqAny( - 'published', - [1965, 1925, 1949, 1960, 1866, 1985, 1954, 1967, 1979] + const results = await execute( + randomCol + .pipeline() + .where( + notEqAny( + 'published', + [1965, 1925, 1949, 1960, 1866, 1985, 1954, 1967, 1979] + ) ) - ) - .select('title') - .execute(); + .select('title') + ); expectResults(results, { title: 'Pride and Prejudice' }); }); it('arrayContains works', async () => { - const results = await randomCol - .pipeline() - .where(arrayContains('tags', 'comedy')) - .select('title') - .execute(); + const results = await execute( + randomCol + .pipeline() + .where(arrayContains('tags', 'comedy')) + .select('title') + ); expectResults(results, { title: "The Hitchhiker's Guide to the Galaxy" }); }); it('arrayContainsAny works', async () => { - const results = await randomCol - .pipeline() - .where(arrayContainsAny('tags', ['comedy', 'classic'])) - .select('title') - .execute(); + const results = await execute( + randomCol + .pipeline() + .where(arrayContainsAny('tags', ['comedy', 'classic'])) + .select('title') + ); expectResults( results, { title: "The Hitchhiker's Guide to the Galaxy" }, @@ -1253,43 +1281,49 @@ apiDescribe.only('Pipelines', persistence => { }); it('arrayContainsAll works', async () => { - const results = await randomCol - .pipeline() - .where(Field.of('tags').arrayContainsAll('adventure', 'magic')) - .select('title') - .execute(); + const results = await execute( + randomCol + .pipeline() + .where(Field.of('tags').arrayContainsAll('adventure', 'magic')) + .select('title') + ); expectResults(results, { title: 'The Lord of the Rings' }); }); it('arrayLength works', async () => { - const results = await randomCol - .pipeline() - .select(Field.of('tags').arrayLength().as('tagsCount')) - .where(eq('tagsCount', 3)) - .execute(); + const results = await execute( + randomCol + .pipeline() + .select(Field.of('tags').arrayLength().as('tagsCount')) + .where(eq('tagsCount', 3)) + ); expect(results.length).to.equal(10); }); it('testStrConcat', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('author').strConcat(' - ', Field.of('title')).as('bookInfo') - ) - .limit(1) - .execute(); + const results = await execute( + randomCol + .pipeline() + .select( + Field.of('author') + .strConcat(' - ', Field.of('title')) + .as('bookInfo') + ) + .limit(1) + ); expectResults(results, { bookInfo: "Douglas Adams - The Hitchhiker's Guide to the Galaxy" }); }); it('testStartsWith', async () => { - const results = await randomCol - .pipeline() - .where(startsWith('title', 'The')) - .select('title') - .sort(Field.of('title').ascending()) - .execute(); + const results = await execute( + randomCol + .pipeline() + .where(startsWith('title', 'The')) + .select('title') + .sort(Field.of('title').ascending()) + ); expectResults( results, { title: 'The Great Gatsby' }, @@ -1300,12 +1334,13 @@ apiDescribe.only('Pipelines', persistence => { }); it('testEndsWith', async () => { - const results = await randomCol - .pipeline() - .where(endsWith('title', 'y')) - .select('title') - .sort(Field.of('title').descending()) - .execute(); + const results = await execute( + randomCol + .pipeline() + .where(endsWith('title', 'y')) + .select('title') + .sort(Field.of('title').descending()) + ); expectResults( results, { title: "The Hitchhiker's Guide to the Galaxy" }, @@ -1314,15 +1349,16 @@ apiDescribe.only('Pipelines', persistence => { }); it('testLength', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('title').charLength().as('titleLength'), - Field.of('title') - ) - .where(gt('titleLength', 20)) - .sort(Field.of('title').ascending()) - .execute(); + const results = await execute( + randomCol + .pipeline() + .select( + Field.of('title').charLength().as('titleLength'), + Field.of('title') + ) + .where(gt('titleLength', 20)) + .sort(Field.of('title').ascending()) + ); expectResults( results, @@ -1347,45 +1383,42 @@ apiDescribe.only('Pipelines', persistence => { }); it('testLike', async () => { - const results = await randomCol - .pipeline() - .where(like('title', '%Guide%')) - .select('title') - .execute(); + const results = await execute( + randomCol.pipeline().where(like('title', '%Guide%')).select('title') + ); expectResults(results, { title: "The Hitchhiker's Guide to the Galaxy" }); }); it('testRegexContains', async () => { - const results = await randomCol - .pipeline() - .where(regexContains('title', '(?i)(the|of)')) - .execute(); + const results = await execute( + randomCol.pipeline().where(regexContains('title', '(?i)(the|of)')) + ); expect(results.length).to.equal(5); }); it('testRegexMatches', async () => { - const results = await randomCol - .pipeline() - .where(regexMatch('title', '.*(?i)(the|of).*')) - .execute(); + const results = await execute( + randomCol.pipeline().where(regexMatch('title', '.*(?i)(the|of).*')) + ); expect(results.length).to.equal(5); }); it('testArithmeticOperations', async () => { - const results = await randomCol - .pipeline() - .select( - add(Field.of('rating'), 1).as('ratingPlusOne'), - subtract(Field.of('published'), 1900).as('yearsSince1900'), - Field.of('rating').multiply(10).as('ratingTimesTen'), - Field.of('rating').divide(2).as('ratingDividedByTwo'), - multiply('rating', 10, 2).as('ratingTimes20'), - add('rating', 1, 2).as('ratingPlus3') - ) - .limit(1) - .execute(); + const results = await execute( + randomCol + .pipeline() + .select( + add(Field.of('rating'), 1).as('ratingPlusOne'), + subtract(Field.of('published'), 1900).as('yearsSince1900'), + Field.of('rating').multiply(10).as('ratingTimesTen'), + Field.of('rating').divide(2).as('ratingDividedByTwo'), + multiply('rating', 10, 2).as('ratingTimes20'), + add('rating', 1, 2).as('ratingPlus3') + ) + .limit(1) + ); expectResults(results, { ratingPlusOne: 5.2, yearsSince1900: 79, @@ -1397,18 +1430,19 @@ apiDescribe.only('Pipelines', persistence => { }); it('testComparisonOperators', async () => { - const results = await randomCol - .pipeline() - .where( - andFunction( - gt('rating', 4.2), - lte(Field.of('rating'), 4.5), - neq('genre', 'Science Fiction') + const results = await execute( + randomCol + .pipeline() + .where( + andFunction( + gt('rating', 4.2), + lte(Field.of('rating'), 4.5), + neq('genre', 'Science Fiction') + ) ) - ) - .select('rating', 'title') - .sort(Field.of('title').ascending()) - .execute(); + .select('rating', 'title') + .sort(Field.of('title').ascending()) + ); expectResults( results, { rating: 4.3, title: 'Crime and Punishment' }, @@ -1421,17 +1455,18 @@ apiDescribe.only('Pipelines', persistence => { }); it('testLogicalOperators', async () => { - const results = await randomCol - .pipeline() - .where( - orFunction( - andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')), - lt('published', 1900) + const results = await execute( + randomCol + .pipeline() + .where( + orFunction( + andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')), + lt('published', 1900) + ) ) - ) - .select('title') - .sort(Field.of('title').ascending()) - .execute(); + .select('title') + .sort(Field.of('title').ascending()) + ); expectResults( results, { title: 'Crime and Punishment' }, @@ -1441,22 +1476,23 @@ apiDescribe.only('Pipelines', persistence => { }); it('testChecks', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select( - isNull('rating').as('ratingIsNull'), - isNan('rating').as('ratingIsNaN'), - isError(arrayOffset('title', 0)).as('isError'), - ifError(arrayOffset('title', 0), Constant.of('was error')).as( - 'ifError' - ), - isAbsent('foo').as('isAbsent'), - isNotNull('title').as('titleIsNotNull'), - isNotNan('cost').as('costIsNotNan') - ) - .execute(); + let results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select( + isNull('rating').as('ratingIsNull'), + isNan('rating').as('ratingIsNaN'), + isError(arrayOffset('title', 0)).as('isError'), + ifError(arrayOffset('title', 0), Constant.of('was error')).as( + 'ifError' + ), + isAbsent('foo').as('isAbsent'), + isNotNull('title').as('titleIsNotNull'), + isNotNan('cost').as('costIsNotNan') + ) + ); expectResults(results, { ratingIsNull: false, ratingIsNaN: false, @@ -1467,22 +1503,23 @@ apiDescribe.only('Pipelines', persistence => { costIsNotNan: false }); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select( - Field.of('rating').isNull().as('ratingIsNull'), - Field.of('rating').isNan().as('ratingIsNaN'), - arrayOffset('title', 0).isError().as('isError'), - arrayOffset('title', 0) - .ifError(Constant.of('was error')) - .as('ifError'), - Field.of('foo').isAbsent().as('isAbsent'), - Field.of('title').isNotNull().as('titleIsNotNull'), - Field.of('cost').isNotNan().as('costIsNotNan') - ) - .execute(); + results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select( + Field.of('rating').isNull().as('ratingIsNull'), + Field.of('rating').isNan().as('ratingIsNaN'), + arrayOffset('title', 0).isError().as('isError'), + arrayOffset('title', 0) + .ifError(Constant.of('was error')) + .as('ifError'), + Field.of('foo').isAbsent().as('isAbsent'), + Field.of('title').isNotNull().as('titleIsNotNull'), + Field.of('cost').isNotNan().as('costIsNotNan') + ) + ); expectResults(results, { ratingIsNull: false, ratingIsNaN: false, @@ -1495,16 +1532,17 @@ apiDescribe.only('Pipelines', persistence => { }); it('testMapGet', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('published').descending()) - .select( - Field.of('awards').mapGet('hugo').as('hugoAward'), - Field.of('awards').mapGet('others').as('others'), - Field.of('title') - ) - .where(eq('hugoAward', true)) - .execute(); + const results = await execute( + randomCol + .pipeline() + .sort(Field.of('published').descending()) + .select( + Field.of('awards').mapGet('hugo').as('hugoAward'), + Field.of('awards').mapGet('others').as('others'), + Field.of('title') + ) + .where(eq('hugoAward', true)) + ); expectResults( results, { @@ -1519,24 +1557,25 @@ apiDescribe.only('Pipelines', persistence => { it('testDistanceFunctions', async () => { const sourceVector = [0.1, 0.1]; const targetVector = [0.5, 0.8]; - let results = await randomCol - .pipeline() - .select( - cosineDistance(Constant.vector(sourceVector), targetVector).as( - 'cosineDistance' - ), - dotProduct(Constant.vector(sourceVector), targetVector).as( - 'dotProductDistance' - ), - euclideanDistance(Constant.vector(sourceVector), targetVector).as( - 'euclideanDistance' - ), - manhattanDistance(Constant.vector(sourceVector), targetVector).as( - 'manhattanDistance' + let results = await execute( + randomCol + .pipeline() + .select( + cosineDistance(Constant.vector(sourceVector), targetVector).as( + 'cosineDistance' + ), + dotProduct(Constant.vector(sourceVector), targetVector).as( + 'dotProductDistance' + ), + euclideanDistance(Constant.vector(sourceVector), targetVector).as( + 'euclideanDistance' + ), + manhattanDistance(Constant.vector(sourceVector), targetVector).as( + 'manhattanDistance' + ) ) - ) - .limit(1) - .execute(); + .limit(1) + ); expectResults(results, { cosineDistance: 0.02560880430538015, @@ -1545,24 +1584,25 @@ apiDescribe.only('Pipelines', persistence => { manhattanDistance: 1.1 }); - results = await randomCol - .pipeline() - .select( - Constant.vector(sourceVector) - .cosineDistance(targetVector) - .as('cosineDistance'), - Constant.vector(sourceVector) - .dotProduct(targetVector) - .as('dotProductDistance'), - Constant.vector(sourceVector) - .euclideanDistance(targetVector) - .as('euclideanDistance'), - Constant.vector(sourceVector) - .manhattanDistance(targetVector) - .as('manhattanDistance') - ) - .limit(1) - .execute(); + results = await execute( + randomCol + .pipeline() + .select( + Constant.vector(sourceVector) + .cosineDistance(targetVector) + .as('cosineDistance'), + Constant.vector(sourceVector) + .dotProduct(targetVector) + .as('dotProductDistance'), + Constant.vector(sourceVector) + .euclideanDistance(targetVector) + .as('euclideanDistance'), + Constant.vector(sourceVector) + .manhattanDistance(targetVector) + .as('manhattanDistance') + ) + .limit(1) + ); expectResults(results, { cosineDistance: 0.02560880430538015, @@ -1573,11 +1613,12 @@ apiDescribe.only('Pipelines', persistence => { }); it('testNestedFields', async () => { - const results = await randomCol - .pipeline() - .where(eq('awards.hugo', true)) - .select('title', 'awards.hugo') - .execute(); + const results = await execute( + randomCol + .pipeline() + .where(eq('awards.hugo', true)) + .select('title', 'awards.hugo') + ); expectResults( results, { @@ -1589,15 +1630,16 @@ apiDescribe.only('Pipelines', persistence => { }); it('test mapGet with field name including . notation', async () => { - const results = await randomCol - .pipeline() - .where(eq('awards.hugo', true)) - .select( - 'title', - Field.of('nestedField.level.1'), - mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') - ) - .execute(); + const results = await execute( + randomCol + .pipeline() + .where(eq('awards.hugo', true)) + .select( + 'title', + Field.of('nestedField.level.1'), + mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') + ) + ); expectResults( results, { @@ -1611,78 +1653,83 @@ apiDescribe.only('Pipelines', persistence => { describe('genericFunction', () => { it('add selectable', async () => { - const results = await randomCol - .pipeline() - .sort(descending('rating')) - .limit(1) - .select( - genericFunction('add', [Field.of('rating'), Constant.of(1)]).as( - 'rating' + const results = await execute( + randomCol + .pipeline() + .sort(descending('rating')) + .limit(1) + .select( + genericFunction('add', [Field.of('rating'), Constant.of(1)]).as( + 'rating' + ) ) - ) - .execute(); + ); expectResults(results, { rating: 5.7 }); }); it('and (variadic) selectable', async () => { - const results = await randomCol - .pipeline() - .where( - genericBooleanExpr('and', [ - Field.of('rating').gt(0), - Field.of('title').charLength().lt(5), - Field.of('tags').arrayContains('propaganda') - ]) - ) - .select('title') - .execute(); + const results = await execute( + randomCol + .pipeline() + .where( + genericBooleanExpr('and', [ + Field.of('rating').gt(0), + Field.of('title').charLength().lt(5), + Field.of('tags').arrayContains('propaganda') + ]) + ) + .select('title') + ); expectResults(results, { title: '1984' }); }); it('array contains any', async () => { - const results = await randomCol - .pipeline() - .where( - genericBooleanExpr('array_contains_any', [ - Field.of('tags'), - ['politics'] - ]) - ) - .select('title') - .execute(); + const results = await execute( + randomCol + .pipeline() + .where( + genericBooleanExpr('array_contains_any', [ + Field.of('tags'), + ['politics'] + ]) + ) + .select('title') + ); expectResults(results, { title: 'Dune' }); }); it('countif aggregate', async () => { - const results = await randomCol - .pipeline() - .aggregate( - genericAggregateFunction('count_if', [ - Field.of('rating').gte(4.5) - ]).as('countOfBest') - ) - .execute(); + const results = await execute( + randomCol + .pipeline() + .aggregate( + genericAggregateFunction('count_if', [ + Field.of('rating').gte(4.5) + ]).as('countOfBest') + ) + ); expectResults(results, { countOfBest: 3 }); }); it('sort by char_len', async () => { - const results = await randomCol - .pipeline() - .sort( - genericFunction('char_length', [Field.of('title')]).ascending(), - descending('__name__') - ) - .limit(3) - .select('title') - .execute(); + const results = await execute( + randomCol + .pipeline() + .sort( + genericFunction('char_length', [Field.of('title')]).ascending(), + descending('__name__') + ) + .limit(3) + .select('title') + ); expectResults( results, { @@ -1700,219 +1747,238 @@ apiDescribe.only('Pipelines', persistence => { describe.skip('not implemented in backend', () => { it('supports Bit_and', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select(bitAnd(Constant.of(5), 12).as('result')) - .execute(); + const results = await execute( + randomCol + .pipeline() + .limit(1) + .select(bitAnd(Constant.of(5), 12).as('result')) + ); expectResults(results, { result: 4 }); it('supports Bit_and', async () => { - const results = await randomCol - .pipeline() - .limit(1) - .select(Constant.of(5).bitAnd(12).as('result')) - .execute(); + const results = await execute( + randomCol + .pipeline() + .limit(1) + .select(Constant.of(5).bitAnd(12).as('result')) + ); expectResults(results, { result: 4 }); }); it('supports Bit_or', async () => { - let results = await randomCol - .pipeline() - .limit(1) - .select(bitOr(Constant.of(5), 12).as('result')) - .execute(); + let results = await execute( + randomCol + .pipeline() + .limit(1) + .select(bitOr(Constant.of(5), 12).as('result')) + ); expectResults(results, { result: 13 }); - results = await randomCol - .pipeline() - .limit(1) - .select(Constant.of(5).bitOr(12).as('result')) - .execute(); + results = await execute( + randomCol + .pipeline() + .limit(1) + .select(Constant.of(5).bitOr(12).as('result')) + ); expectResults(results, { result: 13 }); }); it('supports Bit_xor', async () => { - let results = await randomCol - .pipeline() - .limit(1) - .select(bitXor(Constant.of(5), 12).as('result')) - .execute(); + let results = await execute( + randomCol + .pipeline() + .limit(1) + .select(bitXor(Constant.of(5), 12).as('result')) + ); expectResults(results, { result: 9 }); - results = await randomCol - .pipeline() - .limit(1) - .select(Constant.of(5).bitXor(12).as('result')) - .execute(); + results = await execute( + randomCol + .pipeline() + .limit(1) + .select(Constant.of(5).bitXor(12).as('result')) + ); expectResults(results, { result: 9 }); }); it('supports Bit_not', async () => { - let results = await randomCol - .pipeline() - .limit(1) - .select( - bitNot(Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd)))).as( - 'result' + let results = await execute( + randomCol + .pipeline() + .limit(1) + .select( + bitNot( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd))) + ).as('result') ) - ) - .execute(); + ); expectResults(results, { result: Bytes.fromUint8Array(Uint8Array.of(0x02)) }); - results = await randomCol - .pipeline() - .limit(1) - .select( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd))) - .bitNot() - .as('result') - ) - .execute(); + results = await execute( + randomCol + .pipeline() + .limit(1) + .select( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd))) + .bitNot() + .as('result') + ) + ); expectResults(results, { result: Bytes.fromUint8Array(Uint8Array.of(0x02)) }); }); it('supports Bit_left_shift', async () => { - let results = await randomCol - .pipeline() - .limit(1) - .select( - bitLeftShift( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), - 2 - ).as('result') - ) - .execute(); + let results = await execute( + randomCol + .pipeline() + .limit(1) + .select( + bitLeftShift( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + ); expectResults(results, { result: Bytes.fromUint8Array(Uint8Array.of(0x04)) }); - results = await randomCol - .pipeline() - .limit(1) - .select( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))) - .bitLeftShift(2) - .as('result') - ) - .execute(); + results = await execute( + randomCol + .pipeline() + .limit(1) + .select( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))) + .bitLeftShift(2) + .as('result') + ) + ); expectResults(results, { result: Bytes.fromUint8Array(Uint8Array.of(0x04)) }); }); it('supports Bit_right_shift', async () => { - let results = await randomCol - .pipeline() - .limit(1) - .select( - bitRightShift( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), - 2 - ).as('result') - ) - .execute(); + let results = await execute( + randomCol + .pipeline() + .limit(1) + .select( + bitRightShift( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + ); expectResults(results, { result: Bytes.fromUint8Array(Uint8Array.of(0x01)) }); - results = await randomCol - .pipeline() - .limit(1) - .select( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))) - .bitRightShift(2) - .as('result') - ) - .execute(); + results = await execute( + randomCol + .pipeline() + .limit(1) + .select( + Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))) + .bitRightShift(2) + .as('result') + ) + ); expectResults(results, { result: Bytes.fromUint8Array(Uint8Array.of(0x01)) }); }); it('supports Document_id', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(documentIdFunction(Field.of('__path__')).as('docId')) - .execute(); + let results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(documentIdFunction(Field.of('__path__')).as('docId')) + ); expectResults(results, { docId: 'book4' }); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('__path__').documentId().as('docId')) - .execute(); + results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('__path__').documentId().as('docId')) + ); expectResults(results, { docId: 'book4' }); }); it('supports Substr', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(substr('title', 9, 2).as('of')) - .execute(); + let results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(substr('title', 9, 2).as('of')) + ); expectResults(results, { of: 'of' }); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('title').substr(9, 2).as('of')) - .execute(); + results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('title').substr(9, 2).as('of')) + ); expectResults(results, { of: 'of' }); }); it('supports Substr without length', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(substr('title', 9).as('of')) - .execute(); + let results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(substr('title', 9).as('of')) + ); expectResults(results, { of: 'of the Rings' }); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('title').substr(9).as('of')) - .execute(); + results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('title').substr(9).as('of')) + ); expectResults(results, { of: 'of the Rings' }); }); it('arrayConcat works', async () => { - const results = await randomCol - .pipeline() - .select( - Field.of('tags') - .arrayConcat(['newTag1', 'newTag2'], Field.of('tags'), [null]) - .as('modifiedTags') - ) - .limit(1) - .execute(); + const results = await execute( + randomCol + .pipeline() + .select( + Field.of('tags') + .arrayConcat(['newTag1', 'newTag2'], Field.of('tags'), [null]) + .as('modifiedTags') + ) + .limit(1) + ); expectResults(results, { modifiedTags: [ 'comedy', @@ -1929,39 +1995,42 @@ apiDescribe.only('Pipelines', persistence => { }); it('testToLowercase', async () => { - const results = await randomCol - .pipeline() - .select(Field.of('title').toLower().as('lowercaseTitle')) - .limit(1) - .execute(); + const results = await execute( + randomCol + .pipeline() + .select(Field.of('title').toLower().as('lowercaseTitle')) + .limit(1) + ); expectResults(results, { lowercaseTitle: "the hitchhiker's guide to the galaxy" }); }); it('testToUppercase', async () => { - const results = await randomCol - .pipeline() - .select(Field.of('author').toUpper().as('uppercaseAuthor')) - .limit(1) - .execute(); + const results = await execute( + randomCol + .pipeline() + .select(Field.of('author').toUpper().as('uppercaseAuthor')) + .limit(1) + ); expectResults(results, { uppercaseAuthor: 'DOUGLAS ADAMS' }); }); it('testTrim', async () => { - const results = await randomCol - .pipeline() - .addFields( - Constant.of(" The Hitchhiker's Guide to the Galaxy ").as( - 'spacedTitle' + const results = await execute( + randomCol + .pipeline() + .addFields( + Constant.of(" The Hitchhiker's Guide to the Galaxy ").as( + 'spacedTitle' + ) ) - ) - .select( - Field.of('spacedTitle').trim().as('trimmedTitle'), - Field.of('spacedTitle') - ) - .limit(1) - .execute(); + .select( + Field.of('spacedTitle').trim().as('trimmedTitle'), + Field.of('spacedTitle') + ) + .limit(1) + ); expectResults(results, { spacedTitle: " The Hitchhiker's Guide to the Galaxy ", trimmedTitle: "The Hitchhiker's Guide to the Galaxy" @@ -1970,11 +2039,9 @@ apiDescribe.only('Pipelines', persistence => { }); it('supports Rand', async () => { - const results = await randomCol - .pipeline() - .limit(10) - .select(rand().as('result')) - .execute(); + const results = await execute( + randomCol.pipeline().limit(10).select(rand().as('result')) + ); expect(results.length).to.equal(10); results.forEach(d => { expect(d.get('result')).to.be.lt(1); @@ -1983,13 +2050,14 @@ apiDescribe.only('Pipelines', persistence => { }); it('supports array', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('rating').descending()) - .limit(1) - .select(array([1, 2, 3, 4]).as('metadata')) - .execute(); + const result = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select(array([1, 2, 3, 4]).as('metadata')) + ); expect(result.length).to.equal(1); expectResults(result, { metadata: [1, 2, 3, 4] @@ -1997,17 +2065,18 @@ apiDescribe.only('Pipelines', persistence => { }); it('evaluates expression in array', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('rating').descending()) - .limit(1) - .select( - array([1, 2, Field.of('genre'), multiply('rating', 10)]).as( - 'metadata' + const result = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + array([1, 2, Field.of('genre'), multiply('rating', 10)]).as( + 'metadata' + ) ) - ) - .execute(); + ); expect(result.length).to.equal(1); expectResults(result, { metadata: [1, 2, 'Fantasy', 47] @@ -2015,12 +2084,13 @@ apiDescribe.only('Pipelines', persistence => { }); it('supports arrayOffset', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(3) - .select(arrayOffset('tags', 0).as('firstTag')) - .execute(); + let results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(3) + .select(arrayOffset('tags', 0).as('firstTag')) + ); const expectedResults = [ { firstTag: 'adventure' @@ -2034,41 +2104,44 @@ apiDescribe.only('Pipelines', persistence => { ]; expectResults(results, ...expectedResults); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(3) - .select(Field.of('tags').arrayOffset(0).as('firstTag')) - .execute(); + results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(3) + .select(Field.of('tags').arrayOffset(0).as('firstTag')) + ); expectResults(results, ...expectedResults); }); }); // TODO: current_context tests with are failing because of b/395937453 it.skip('supports currentContext', async () => { - const results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(currentContext().as('currentContext')) - .execute(); + const results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(currentContext().as('currentContext')) + ); expectResults(results, { currentContext: 'TODO' }); }); it('supports map', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('rating').descending()) - .limit(1) - .select( - map({ - foo: 'bar' - }).as('metadata') - ) - .execute(); + const result = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + map({ + foo: 'bar' + }).as('metadata') + ) + ); expect(result.length).to.equal(1); expectResults(result, { @@ -2079,18 +2152,19 @@ apiDescribe.only('Pipelines', persistence => { }); it('evaluates expression in map', async () => { - const result = await firestore - .pipeline() - .collection(randomCol.path) - .sort(Field.of('rating').descending()) - .limit(1) - .select( - map({ - genre: Field.of('genre'), - rating: Field.of('rating').multiply(10) - }).as('metadata') - ) - .execute(); + const result = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(Field.of('rating').descending()) + .limit(1) + .select( + map({ + genre: Field.of('genre'), + rating: Field.of('rating').multiply(10) + }).as('metadata') + ) + ); expect(result.length).to.equal(1); expectResults(result, { @@ -2102,42 +2176,46 @@ apiDescribe.only('Pipelines', persistence => { }); it('supports mapRemove', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(mapRemove('awards', 'hugo').as('awards')) - .execute(); + let results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(mapRemove('awards', 'hugo').as('awards')) + ); expectResults(results, { awards: { nebula: false } }); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('awards').mapRemove('hugo').as('awards')) - .execute(); + results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('awards').mapRemove('hugo').as('awards')) + ); expectResults(results, { awards: { nebula: false } }); }); it('supports mapMerge', async () => { - let results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(mapMerge('awards', { fakeAward: true }).as('awards')) - .execute(); + let results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(mapMerge('awards', { fakeAward: true }).as('awards')) + ); expectResults(results, { awards: { nebula: false, hugo: false, fakeAward: true } }); - results = await randomCol - .pipeline() - .sort(Field.of('rating').descending()) - .limit(1) - .select(Field.of('awards').mapMerge({ fakeAward: true }).as('awards')) - .execute(); + results = await execute( + randomCol + .pipeline() + .sort(Field.of('rating').descending()) + .limit(1) + .select(Field.of('awards').mapMerge({ fakeAward: true }).as('awards')) + ); expectResults(results, { awards: { nebula: false, hugo: false, fakeAward: true } }); @@ -2198,7 +2276,7 @@ apiDescribe.only('Pipelines', persistence => { Field.of('__name__').ascending() ); - let results = await pipeline.limit(pageSize).execute(); + let results = await execute(pipeline.limit(pageSize)); expectResults( results, { title: 'The Lord of the Rings', rating: 4.7 }, @@ -2207,18 +2285,19 @@ apiDescribe.only('Pipelines', persistence => { const lastDoc = results[results.length - 1]; - results = await pipeline - .where( - orFunction( - andFunction( - Field.of('rating').eq(lastDoc.get('rating')), - Field.of('__path__').gt(lastDoc.ref?.id) - ), - Field.of('rating').lt(lastDoc.get('rating')) + results = await execute( + pipeline + .where( + orFunction( + andFunction( + Field.of('rating').eq(lastDoc.get('rating')), + Field.of('__path__').gt(lastDoc.ref?.id) + ), + Field.of('rating').lt(lastDoc.get('rating')) + ) ) - ) - .limit(pageSize) - .execute(); + .limit(pageSize) + ); expectResults( results, { title: 'Pride and Prejudice', rating: 4.5 }, @@ -2242,10 +2321,9 @@ apiDescribe.only('Pipelines', persistence => { const pageSize = 2; let currPage = 0; - let results = await pipeline - .offset(currPage++ * pageSize) - .limit(pageSize) - .execute(); + let results = await execute( + pipeline.offset(currPage++ * pageSize).limit(pageSize) + ); expectResults( results, @@ -2256,10 +2334,9 @@ apiDescribe.only('Pipelines', persistence => { { title: 'Dune', rating: 4.6 } ); - results = await pipeline - .offset(currPage++ * pageSize) - .limit(pageSize) - .execute(); + results = await execute( + pipeline.offset(currPage++ * pageSize).limit(pageSize) + ); expectResults( results, { @@ -2269,10 +2346,9 @@ apiDescribe.only('Pipelines', persistence => { { title: 'The Master and Margarita', rating: 4.6 } ); - results = await pipeline - .offset(currPage++ * pageSize) - .limit(pageSize) - .execute(); + results = await execute( + pipeline.offset(currPage++ * pageSize).limit(pageSize) + ); expectResults( results, { @@ -2286,47 +2362,4 @@ apiDescribe.only('Pipelines', persistence => { ); }); }); - - describe('modular API', () => { - it('works when creating a pipeline from a Firestore instance', async () => { - const myPipeline = pipeline(firestore) - .collection(randomCol.path) - .where(lt(Field.of('published'), 1984)) - .aggregate({ - accumulators: [avgFunction('rating').as('avgRating')], - groups: ['genre'] - }) - .where(gt('avgRating', 4.3)) - .sort(Field.of('avgRating').descending()); - - const results = await execute(myPipeline); - - expectResults( - results, - { avgRating: 4.7, genre: 'Fantasy' }, - { avgRating: 4.5, genre: 'Romance' }, - { avgRating: 4.4, genre: 'Science Fiction' } - ); - }); - - it('works when creating a pipeline from a collection', async () => { - const myPipeline = pipeline(randomCol) - .where(lt(Field.of('published'), 1984)) - .aggregate({ - accumulators: [avgFunction('rating').as('avgRating')], - groups: ['genre'] - }) - .where(gt('avgRating', 4.3)) - .sort(Field.of('avgRating').descending()); - - const results = await execute(myPipeline); - - expectResults( - results, - { avgRating: 4.7, genre: 'Fantasy' }, - { avgRating: 4.5, genre: 'Romance' }, - { avgRating: 4.4, genre: 'Science Fiction' } - ); - }); - }); }); diff --git a/packages/firestore/test/integration/api/query_to_pipeline.test.ts b/packages/firestore/test/integration/api/query_to_pipeline.test.ts index 878aca4faa7..b5f7ddec90b 100644 --- a/packages/firestore/test/integration/api/query_to_pipeline.test.ts +++ b/packages/firestore/test/integration/api/query_to_pipeline.test.ts @@ -40,7 +40,8 @@ import { and, documentId, addDoc, - getDoc + getDoc, + execute } from '../util/firebase_export'; import { apiDescribe, @@ -73,7 +74,7 @@ apiDescribe('Query to Pipeline', persistence => { PERSISTENCE_MODE_UNSPECIFIED, { 1: { foo: 1 } }, async collRef => { - const result = await collRef.pipeline().execute(); + const result = await execute(collRef.pipeline()); verifyResults(result, { foo: 1 }); } ); @@ -88,7 +89,7 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, where('foo', '==', 1)); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults(result, { foo: 1 }); } ); @@ -103,7 +104,7 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, where(new FieldPath('foo'), '==', 1)); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults(result, { foo: 1 }); } ); @@ -118,7 +119,7 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo')); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults(result, { foo: 1 }, { foo: 2 }); } ); @@ -133,7 +134,7 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo', 'asc')); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults(result, { foo: 1 }, { foo: 2 }); } ); @@ -148,7 +149,7 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo', 'desc')); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults(result, { foo: 2 }, { foo: 1 }); } ); @@ -163,7 +164,7 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo'), limit(1)); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults(result, { foo: 1 }); } ); @@ -179,7 +180,7 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo'), limitToLast(2)); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults(result, { foo: 2 }, { foo: 3 }); } ); @@ -194,7 +195,7 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo'), startAt(2)); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults(result, { foo: 2 }); } ); @@ -226,7 +227,7 @@ apiDescribe('Query to Pipeline', persistence => { orderBy('baz'), startAfter(docRef) ); - let result = await query1.pipeline().execute(); + let result = await execute(query1.pipeline()); verifyResults( result, { id: 3, foo: 1, bar: 1, baz: 2 }, @@ -249,7 +250,7 @@ apiDescribe('Query to Pipeline', persistence => { orderBy('baz'), startAfter(docRef) ); - result = await query1.pipeline().execute(); + result = await execute(query1.pipeline()); verifyResults( result, { id: 4, foo: 1, bar: 2, baz: 1 }, @@ -292,7 +293,7 @@ apiDescribe('Query to Pipeline', persistence => { orderBy('baz'), startAt(docRef) ); - let result = await query1.pipeline().execute(); + let result = await execute(query1.pipeline()); verifyResults( result, { id: 2, foo: 1, bar: 1, baz: 2 }, @@ -316,7 +317,7 @@ apiDescribe('Query to Pipeline', persistence => { orderBy('baz'), startAt(docRef) ); - result = await query1.pipeline().execute(); + result = await execute(query1.pipeline()); verifyResults( result, { id: 3, foo: 1, bar: 1, baz: 2 }, @@ -343,7 +344,7 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo'), startAfter(1)); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults(result, { foo: 2 }); } ); @@ -358,7 +359,7 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo'), endAt(1)); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults(result, { foo: 1 }); } ); @@ -373,7 +374,7 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo'), endBefore(2)); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults(result, { foo: 1 }); } ); @@ -389,12 +390,12 @@ apiDescribe('Query to Pipeline', persistence => { async collRef => { let query1 = query(collRef, orderBy('foo'), limit(1)); const pipeline1 = query1.pipeline(); - let result = await pipeline1.execute(); + let result = await execute(pipeline1); verifyResults(result, { foo: 1 }); // Pass the document snapshot from the previous result query1 = query(query1, startAfter(result[0].get('foo'))); - result = await query1.pipeline().execute(); + result = await execute(query1.pipeline()); verifyResults(result, { foo: 2 }); } ); @@ -415,7 +416,7 @@ apiDescribe('Query to Pipeline', persistence => { limit(1) ); const pipeline1 = query1.pipeline(); - let result = await pipeline1.execute(); + let result = await execute(pipeline1); verifyResults(result, { foo: 1 }); // Pass the document snapshot from the previous result @@ -423,7 +424,7 @@ apiDescribe('Query to Pipeline', persistence => { query1, startAfter(result[0].get('foo'), result[0].ref?.id) ); - result = await query1.pipeline().execute(); + result = await execute(query1.pipeline()); verifyResults(result, { foo: 2 }); } ); @@ -448,7 +449,7 @@ apiDescribe('Query to Pipeline', persistence => { await setDoc(barDoc, { bar: 1 }); const query1 = collectionGroup(collRef.firestore, collectionGroupId); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults(result, { bar: 1 }, { foo: 1 }); } @@ -469,12 +470,9 @@ apiDescribe('Query to Pipeline', persistence => { await addDoc(collectionWithSpecials, { foo: 1 }); await addDoc(collectionWithSpecials, { foo: 2 }); - const result = await query( - collectionWithSpecials, - orderBy('foo', 'asc') - ) - .pipeline() - .execute(); + const result = await execute( + query(collectionWithSpecials, orderBy('foo', 'asc')).pipeline() + ); verifyResults(result, { foo: 1 }, { foo: 2 }); } @@ -503,7 +501,7 @@ apiDescribe('Query to Pipeline', persistence => { collRef, and(where('id', '>', 2), where('id', '<=', 10)) ); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults( result, { id: 3, foo: 1, bar: 1, baz: 2 }, @@ -541,7 +539,7 @@ apiDescribe('Query to Pipeline', persistence => { collRef, and(where('id', '>=', 2), where('baz', '<', 2)) ); - const result = await query1.pipeline().execute(); + const result = await execute(query1.pipeline()); verifyResults( result, { id: 4, foo: 1, bar: 2, baz: 1 }, From a42b0d1358b1e364b728ff3f039785b8fb154313 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 26 Feb 2025 16:00:52 -0700 Subject: [PATCH 40/75] Change return type of execute from PipelineResult[] to PipelineSnapshot --- packages/firestore/src/api/pipeline_impl.ts | 13 +- .../firestore/src/lite-api/pipeline-result.ts | 69 ++- .../firestore/src/lite-api/pipeline_impl.ts | 47 +- packages/firestore/src/lite-api/snapshot.ts | 5 +- .../test/integration/api/pipeline.test.ts | 449 +++++++++--------- .../integration/api/query_to_pipeline.test.ts | 118 ++--- 6 files changed, 372 insertions(+), 329 deletions(-) diff --git a/packages/firestore/src/api/pipeline_impl.ts b/packages/firestore/src/api/pipeline_impl.ts index fc79ef2e5c5..77bfaf5cf6b 100644 --- a/packages/firestore/src/api/pipeline_impl.ts +++ b/packages/firestore/src/api/pipeline_impl.ts @@ -19,7 +19,7 @@ import { Pipeline } from '../api/pipeline'; import { firestoreClientExecutePipeline } from '../core/firestore_client'; import { toPipeline } from '../core/pipeline-util'; import { Pipeline as LitePipeline } from '../lite-api/pipeline'; -import { PipelineResult } from '../lite-api/pipeline-result'; +import { PipelineResult, PipelineSnapshot } from '../lite-api/pipeline-result'; import { PipelineSource } from '../lite-api/pipeline-source'; import { Stage } from '../lite-api/stage'; import { newUserDataReader } from '../lite-api/user_data_reader'; @@ -66,10 +66,16 @@ declare module './database' { * @param pipeline The pipeline to execute. * @return A Promise representing the asynchronous pipeline execution. */ -export function execute(pipeline: LitePipeline): Promise { +export function execute(pipeline: LitePipeline): Promise { const firestore = cast(pipeline._db, Firestore); const client = ensureFirestoreConfigured(firestore); return firestoreClientExecutePipeline(client, pipeline).then(result => { + // Get the execution time from the first result. + // firestoreClientExecutePipeline returns at least one PipelineStreamElement + // even if the returned document set is empty. + const executionTime = + result.length > 0 ? result[0].executionTime?.toTimestamp() : undefined; + const docs = result // Currently ignore any response from ExecutePipeline that does // not contain any document data in the `fields` property. @@ -82,13 +88,12 @@ export function execute(pipeline: LitePipeline): Promise { ? new DocumentReference(firestore, null, element.key) : undefined, element.fields, - element.executionTime?.toTimestamp(), element.createTime?.toTimestamp(), element.updateTime?.toTimestamp() ) ); - return docs; + return new PipelineSnapshot(pipeline, docs, executionTime); }); } diff --git a/packages/firestore/src/lite-api/pipeline-result.ts b/packages/firestore/src/lite-api/pipeline-result.ts index dc0a6412481..27c41de1908 100644 --- a/packages/firestore/src/lite-api/pipeline-result.ts +++ b/packages/firestore/src/lite-api/pipeline-result.ts @@ -18,12 +18,58 @@ import { ObjectValue } from '../model/object_value'; import { isOptionalEqual } from '../util/misc'; +import { Field } from './expressions'; import { FieldPath } from './field_path'; +import { Pipeline } from './pipeline'; import { DocumentData, DocumentReference, refEqual } from './reference'; import { fieldPathFromArgument } from './snapshot'; import { Timestamp } from './timestamp'; import { AbstractUserDataWriter } from './user_data_writer'; +export class PipelineSnapshot { + private readonly _pipeline: Pipeline; + private readonly _executionTime: Timestamp | undefined; + private readonly _results: PipelineResult[]; + constructor( + pipeline: Pipeline, + results: PipelineResult[], + executionTime?: Timestamp + ) { + this._pipeline = pipeline; + this._executionTime = executionTime; + this._results = results; + } + + /** + * The Pipeline on which you called `execute()` in order to get this + * `PipelineSnapshot`. + */ + get pipeline(): Pipeline { + return this._pipeline; + } + + /** An array of all the results in the `PipelineSnapshot`. */ + get results(): PipelineResult[] { + return this._results; + } + + /** + * The time at which the pipeline producing this result is executed. + * + * @type {Timestamp} + * @readonly + * + */ + get executionTime(): Timestamp { + if (this._executionTime === undefined) { + throw new Error( + "'executionTime' is expected to exist, but it is undefined" + ); + } + return this._executionTime; + } +} + /** * @beta * @@ -36,7 +82,6 @@ import { AbstractUserDataWriter } from './user_data_writer'; export class PipelineResult { private readonly _userDataWriter: AbstractUserDataWriter; - private readonly _executionTime: Timestamp | undefined; private readonly _createTime: Timestamp | undefined; private readonly _updateTime: Timestamp | undefined; @@ -69,13 +114,11 @@ export class PipelineResult { userDataWriter: AbstractUserDataWriter, ref?: DocumentReference, fields?: ObjectValue, - executionTime?: Timestamp, createTime?: Timestamp, updateTime?: Timestamp ) { this._ref = ref; this._userDataWriter = userDataWriter; - this._executionTime = executionTime; this._createTime = createTime; this._updateTime = updateTime; this._fields = fields; @@ -120,22 +163,6 @@ export class PipelineResult { return this._updateTime; } - /** - * The time at which the pipeline producing this result is executed. - * - * @type {Timestamp} - * @readonly - * - */ - get executionTime(): Timestamp { - if (this._executionTime === undefined) { - throw new Error( - "'executionTime' is expected to exist, but it is undefined" - ); - } - return this._executionTime; - } - /** * Retrieves all fields in the result as an object. Returns 'undefined' if * the document doesn't exist. @@ -166,7 +193,7 @@ export class PipelineResult { /** * Retrieves the field specified by `field`. * - * @param {string|FieldPath} field The field path + * @param {string|FieldPath|Field} field The field path * (e.g. 'foo' or 'foo.bar') to a specific field. * @returns {*} The data at the specified field location or undefined if no * such field exists. @@ -184,7 +211,7 @@ export class PipelineResult { // We deliberately use `any` in the external API to not impose type-checking // on end users. // eslint-disable-next-line @typescript-eslint/no-explicit-any - get(fieldPath: string | FieldPath): any { + get(fieldPath: string | FieldPath | Field): any { if (this._fields === undefined) { return undefined; } diff --git a/packages/firestore/src/lite-api/pipeline_impl.ts b/packages/firestore/src/lite-api/pipeline_impl.ts index d00435055c7..d80c3cd96eb 100644 --- a/packages/firestore/src/lite-api/pipeline_impl.ts +++ b/packages/firestore/src/lite-api/pipeline_impl.ts @@ -20,7 +20,7 @@ import { invokeExecutePipeline } from '../remote/datastore'; import { getDatastore } from './components'; import { Firestore } from './database'; import { Pipeline } from './pipeline'; -import { PipelineResult } from './pipeline-result'; +import { PipelineResult, PipelineSnapshot } from './pipeline-result'; import { PipelineSource } from './pipeline-source'; import { DocumentReference, Query } from './reference'; import { LiteUserDataWriter } from './reference_impl'; @@ -70,28 +70,33 @@ declare module './reference' { * @param pipeline The pipeline to execute. * @return A Promise representing the asynchronous pipeline execution. */ -export function execute(pipeline: Pipeline): Promise { +export function execute(pipeline: Pipeline): Promise { const datastore = getDatastore(pipeline._db); return invokeExecutePipeline(datastore, pipeline).then(result => { - return ( - result - // Currently ignore any response from ExecutePipeline that does - // not contain any document data in the `fields` property. - .filter(element => !!element.fields) - .map( - element => - new PipelineResult( - pipeline._userDataWriter, - element.key?.path - ? new DocumentReference(pipeline._db, null, element.key) - : undefined, - element.fields, - element.executionTime?.toTimestamp(), - element.createTime?.toTimestamp(), - element.updateTime?.toTimestamp() - ) - ) - ); + // Get the execution time from the first result. + // firestoreClientExecutePipeline returns at least one PipelineStreamElement + // even if the returned document set is empty. + const executionTime = + result.length > 0 ? result[0].executionTime?.toTimestamp() : undefined; + + const docs = result + // Currently ignore any response from ExecutePipeline that does + // not contain any document data in the `fields` property. + .filter(element => !!element.fields) + .map( + element => + new PipelineResult( + pipeline._userDataWriter, + element.key?.path + ? new DocumentReference(pipeline._db, null, element.key) + : undefined, + element.fields, + element.createTime?.toTimestamp(), + element.updateTime?.toTimestamp() + ) + ); + + return new PipelineSnapshot(pipeline, docs, executionTime); }); } diff --git a/packages/firestore/src/lite-api/snapshot.ts b/packages/firestore/src/lite-api/snapshot.ts index 3024e2e9db0..66c3a1422e9 100644 --- a/packages/firestore/src/lite-api/snapshot.ts +++ b/packages/firestore/src/lite-api/snapshot.ts @@ -23,6 +23,7 @@ import { FieldPath as InternalFieldPath } from '../model/path'; import { arrayEquals } from '../util/misc'; import { Firestore } from './database'; +import { Field } from './expressions'; import { FieldPath } from './field_path'; import { DocumentData, @@ -515,12 +516,14 @@ export function snapshotEqual( */ export function fieldPathFromArgument( methodName: string, - arg: string | FieldPath | Compat + arg: string | FieldPath | Compat | Field ): InternalFieldPath { if (typeof arg === 'string') { return fieldPathFromDotSeparatedString(methodName, arg); } else if (arg instanceof FieldPath) { return arg._internalPath; + } else if (arg instanceof Field) { + return fieldPathFromDotSeparatedString(methodName, arg.fieldName()); } else { return arg._delegate._internalPath; } diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 59b95345cf4..66a8628805e 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -18,6 +18,7 @@ import { expect, use } from 'chai'; import chaiAsPromised from 'chai-as-promised'; +import { PipelineSnapshot } from '../../../src/lite-api/pipeline-result'; import { addEqualityMatcher } from '../../util/equality_matcher'; import { Deferred } from '../../util/promise'; import { @@ -60,7 +61,6 @@ import { mapGet, neq, orFunction, - PipelineResult, regexContains, regexMatch, setDoc, @@ -122,27 +122,26 @@ apiDescribe.only('Pipelines', persistence => { return randomCol; } - function expectResults( - result: Array>, - ...docs: string[] - ): void; - function expectResults( - result: Array>, + function expectResults(snapshot: PipelineSnapshot, ...docs: string[]): void; + function expectResults( + snapshot: PipelineSnapshot, ...data: DocumentData[] ): void; - function expectResults( - result: Array>, + function expectResults( + snapshot: PipelineSnapshot, ...data: DocumentData[] | string[] ): void { - expect(result.length).to.equal(data.length); + const docs = snapshot.results; + + expect(docs.length).to.equal(data.length); if (data.length > 0) { if (typeof data[0] === 'string') { - const actualIds = result.map(result => result.ref?.id); + const actualIds = docs.map(doc => doc.ref?.id); expect(actualIds).to.deep.equal(data); } else { - result.forEach(r => { + docs.forEach(r => { expect(r.data()).to.deep.equal(data.shift()); }); } @@ -279,29 +278,29 @@ apiDescribe.only('Pipelines', persistence => { await withTestCollectionPromise; }); - it('empty results as expected', async () => { - const result = await execute( + it('empty snapshot as expected', async () => { + const snapshot = await execute( firestore.pipeline().collection(randomCol.path).limit(0) ); - expect(result.length).to.equal(0); + expect(snapshot.results.length).to.equal(0); }); - it('full results as expected', async () => { - const result = await execute( + it('full snapshot as expected', async () => { + const snapshot = await execute( firestore.pipeline().collection(randomCol.path) ); - expect(result.length).to.equal(10); + expect(snapshot.results.length).to.equal(10); }); it('supports CollectionReference as source', async () => { - const result = await execute(firestore.pipeline().collection(randomCol)); - expect(result.length).to.equal(10); + const snapshot = await execute(firestore.pipeline().collection(randomCol)); + expect(snapshot.results.length).to.equal(10); }); it('supports list of documents as source', async () => { const collName = randomCol.id; - const result = await execute( + const snapshot = await execute( firestore .pipeline() .documents([ @@ -310,7 +309,7 @@ apiDescribe.only('Pipelines', persistence => { doc(randomCol, 'book3').path ]) ); - expect(result.length).to.equal(3); + expect(snapshot.results.length).to.equal(3); }); it('reject CollectionReference for another DB', async () => { @@ -334,7 +333,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('converts arrays and plain objects to functionValues if the customer intent is unspecified', async () => { - const result = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -393,9 +392,9 @@ apiDescribe.only('Pipelines', persistence => { ) ); - expect(result.length).to.equal(1); + expect(snapshot.results.length).to.equal(1); - expectResults(result, { + expectResults(snapshot, { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien', genre: 'Fantasy', @@ -477,14 +476,14 @@ apiDescribe.only('Pipelines', persistence => { ]).as('array') ]; - const results = await execute( + const snapshots = await execute( randomCol .pipeline() .limit(1) .select(...constants) ); - expectResults(results, { + expectResults(snapshots, { 'number': 1, 'string': 'a string', 'boolean': true, @@ -551,15 +550,15 @@ apiDescribe.only('Pipelines', persistence => { describe('stages', () => { describe('aggregate stage', () => { it('supports aggregate', async () => { - let result = await execute( + let snapshot = await execute( firestore .pipeline() .collection(randomCol.path) .aggregate(countAll().as('count')) ); - expectResults(result, { count: 10 }); + expectResults(snapshot, { count: 10 }); - result = await execute( + snapshot = await execute( randomCol .pipeline() .where(eq('genre', 'Science Fiction')) @@ -569,7 +568,7 @@ apiDescribe.only('Pipelines', persistence => { Field.of('rating').maximum().as('maxRating') ) ); - expectResults(result, { count: 2, avgRating: 4.4, maxRating: 4.6 }); + expectResults(snapshot, { count: 2, avgRating: 4.4, maxRating: 4.6 }); }); it('rejects groups without accumulators', async () => { @@ -587,7 +586,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('returns group and accumulate results', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where(lt(Field.of('published'), 1984)) @@ -599,7 +598,7 @@ apiDescribe.only('Pipelines', persistence => { .sort(Field.of('avgRating').descending()) ); expectResults( - results, + snapshot, { avgRating: 4.7, genre: 'Fantasy' }, { avgRating: 4.5, genre: 'Romance' }, { avgRating: 4.4, genre: 'Science Fiction' } @@ -607,7 +606,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('returns min and max accumulations', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .aggregate( @@ -616,7 +615,7 @@ apiDescribe.only('Pipelines', persistence => { Field.of('published').minimum().as('minPublished') ) ); - expectResults(results, { + expectResults(snapshot, { count: 10, maxRating: 4.7, minPublished: 1813 @@ -624,7 +623,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('returns countif accumulation', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .aggregate(countIf(Field.of('rating').gt(4.3)).as('count')) @@ -632,27 +631,27 @@ apiDescribe.only('Pipelines', persistence => { const expectedResults = { count: 3 }; - expectResults(results, expectedResults); + expectResults(snapshot, expectedResults); - results = await execute( + snapshot = await execute( randomCol .pipeline() .aggregate(Field.of('rating').gt(4.3).countIf().as('count')) ); - expectResults(results, expectedResults); + expectResults(snapshot, expectedResults); }); }); describe('distinct stage', () => { it('returns distinct values as expected', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .distinct('genre', 'author') .sort(Field.of('genre').ascending(), Field.of('author').ascending()) ); expectResults( - results, + snapshot, { genre: 'Dystopian', author: 'George Orwell' }, { genre: 'Dystopian', author: 'Margaret Atwood' }, { genre: 'Fantasy', author: 'J.R.R. Tolkien' }, @@ -669,7 +668,7 @@ apiDescribe.only('Pipelines', persistence => { describe('select stage', () => { it('can select fields', async () => { - const results = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -677,7 +676,7 @@ apiDescribe.only('Pipelines', persistence => { .sort(Field.of('author').ascending()) ); expectResults( - results, + snapshot, { title: "The Hitchhiker's Guide to the Galaxy", author: 'Douglas Adams' @@ -700,7 +699,7 @@ apiDescribe.only('Pipelines', persistence => { describe('addField stage', () => { it('can add fields', async () => { - const results = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -709,7 +708,7 @@ apiDescribe.only('Pipelines', persistence => { .sort(Field.of('author').ascending()) ); expectResults( - results, + snapshot, { title: "The Hitchhiker's Guide to the Galaxy", author: 'Douglas Adams', @@ -754,7 +753,7 @@ apiDescribe.only('Pipelines', persistence => { describe('where stage', () => { it('where with and', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where( @@ -765,10 +764,10 @@ apiDescribe.only('Pipelines', persistence => { ) ) ); - expectResults(results, 'book10'); + expectResults(snapshot, 'book10'); }); it('where with or', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where( @@ -781,7 +780,7 @@ apiDescribe.only('Pipelines', persistence => { .select('title') ); expectResults( - results, + snapshot, { title: 'Pride and Prejudice' }, { title: 'The Lord of the Rings' }, { title: "The Handmaid's Tale" }, @@ -790,7 +789,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('where with xor', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where( @@ -804,7 +803,7 @@ apiDescribe.only('Pipelines', persistence => { .select('title') ); expectResults( - results, + snapshot, { title: 'Pride and Prejudice' }, { title: 'The Lord of the Rings' }, { title: "The Handmaid's Tale" } @@ -814,7 +813,7 @@ apiDescribe.only('Pipelines', persistence => { describe('sort, offset, and limit stages', () => { it('supports sort, offset, and limits', async () => { - const results = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -824,7 +823,7 @@ apiDescribe.only('Pipelines', persistence => { .select('title', 'author') ); expectResults( - results, + snapshot, { title: '1984', author: 'George Orwell' }, { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' } @@ -834,7 +833,7 @@ apiDescribe.only('Pipelines', persistence => { describe('generic stage', () => { it('can select fields', async () => { - const results = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -849,7 +848,7 @@ apiDescribe.only('Pipelines', persistence => { .sort(Field.of('author').ascending()) .limit(1) ); - expectResults(results, { + expectResults(snapshot, { title: "The Hitchhiker's Guide to the Galaxy", metadata: { author: 'Douglas Adams' @@ -858,7 +857,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('can add fields', async () => { - const results = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -871,7 +870,7 @@ apiDescribe.only('Pipelines', persistence => { } ]) ); - expectResults(results, { + expectResults(snapshot, { title: "The Hitchhiker's Guide to the Galaxy", author: 'Douglas Adams', display: "The Hitchhiker's Guide to the Galaxy - Douglas Adams" @@ -879,21 +878,21 @@ apiDescribe.only('Pipelines', persistence => { }); it('can filter with where', async () => { - const results = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) .select('title', 'author') .genericStage('where', [Field.of('author').eq('Douglas Adams')]) ); - expectResults(results, { + expectResults(snapshot, { title: "The Hitchhiker's Guide to the Galaxy", author: 'Douglas Adams' }); }); it('can limit, offset, and sort', async () => { - const results = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -907,14 +906,14 @@ apiDescribe.only('Pipelines', persistence => { .genericStage('offset', [3]) .genericStage('limit', [1]) ); - expectResults(results, { + expectResults(snapshot, { author: 'Fyodor Dostoevsky', title: 'Crime and Punishment' }); }); it('can perform aggregate query', async () => { - const results = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -924,13 +923,13 @@ apiDescribe.only('Pipelines', persistence => { {} ]) ); - expectResults(results, { + expectResults(snapshot, { averageRating: 4.3100000000000005 }); }); it('can perform distinct query', async () => { - const results = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -939,7 +938,7 @@ apiDescribe.only('Pipelines', persistence => { .sort(Field.of('rating').descending()) ); expectResults( - results, + snapshot, { rating: 4.7 }, @@ -967,13 +966,13 @@ apiDescribe.only('Pipelines', persistence => { describe('replace stage', () => { it('run pipleine with replace', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) .replaceWith('awards') ); - expectResults(results, { + expectResults(snapshot, { hugo: true, nebula: false, others: { unknown: { year: 1980 } } @@ -983,26 +982,26 @@ apiDescribe.only('Pipelines', persistence => { describe('sample stage', () => { it('run pipeline with sample limit of 3', async () => { - const results = await execute(randomCol.pipeline().sample(3)); - expect(results.length).to.equal(3); + const snapshot = await execute(randomCol.pipeline().sample(3)); + expect(snapshot.results.length).to.equal(3); }); it('run pipeline with sample limit of {documents: 3}', async () => { - const results = await execute( + const snapshot = await execute( randomCol.pipeline().sample({ documents: 3 }) ); - expect(results.length).to.equal(3); + expect(snapshot.results.length).to.equal(3); }); it('run pipeline with sample limit of {percentage: 0.6}', async () => { let avgSize = 0; const numIterations = 20; for (let i = 0; i < numIterations; i++) { - const results = await execute( + const snapshot = await execute( randomCol.pipeline().sample({ percentage: 0.6 }) ); - avgSize += results.length; + avgSize += snapshot.results.length; } avgSize /= numIterations; expect(avgSize).to.be.closeTo(6, 1); @@ -1011,14 +1010,14 @@ apiDescribe.only('Pipelines', persistence => { describe('union stage', () => { it('run pipeline with union', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .union(randomCol.pipeline()) .sort(Field.of(documentId()).ascending()) ); expectResults( - results, + snapshot, 'book1', 'book1', 'book10', @@ -1045,14 +1044,14 @@ apiDescribe.only('Pipelines', persistence => { describe('unnest stage', () => { it('run pipeline with unnest', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) .unnest(Field.of('tags').as('tag')) ); expectResults( - results, + snapshot, { title: "The Hitchhiker's Guide to the Galaxy", author: 'Douglas Adams', @@ -1101,14 +1100,14 @@ apiDescribe.only('Pipelines', persistence => { ); }); it('unnest an expr', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) .unnest(array([1, 2, 3]).as('copy')) ); expectResults( - results, + snapshot, { title: "The Hitchhiker's Guide to the Galaxy", author: 'Douglas Adams', @@ -1161,7 +1160,7 @@ apiDescribe.only('Pipelines', persistence => { describe('function expressions', () => { it('logical max works', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .select( @@ -1174,7 +1173,7 @@ apiDescribe.only('Pipelines', persistence => { .limit(3) ); expectResults( - results, + snapshot, { title: '1984', 'published-safe': 1961 }, { title: 'Crime and Punishment', 'published-safe': 1961 }, { title: 'Dune', 'published-safe': 1965 } @@ -1182,7 +1181,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('logical min works', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .select( @@ -1195,7 +1194,7 @@ apiDescribe.only('Pipelines', persistence => { .limit(3) ); expectResults( - results, + snapshot, { title: '1984', 'published-safe': 1949 }, { title: 'Crime and Punishment', 'published-safe': 1866 }, { title: 'Dune', 'published-safe': 1960 } @@ -1203,7 +1202,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('cond works', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .select( @@ -1218,7 +1217,7 @@ apiDescribe.only('Pipelines', persistence => { .limit(3) ); expectResults( - results, + snapshot, { title: '1984', 'published-safe': 1960 }, { title: 'Crime and Punishment', 'published-safe': 1960 }, { title: 'Dune', 'published-safe': 1965 } @@ -1226,21 +1225,21 @@ apiDescribe.only('Pipelines', persistence => { }); it('eqAny works', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where(eqAny('published', [1979, 1999, 1967])) .select('title') ); expectResults( - results, + snapshot, { title: "The Hitchhiker's Guide to the Galaxy" }, { title: 'One Hundred Years of Solitude' } ); }); it('notEqAny works', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where( @@ -1251,57 +1250,57 @@ apiDescribe.only('Pipelines', persistence => { ) .select('title') ); - expectResults(results, { title: 'Pride and Prejudice' }); + expectResults(snapshot, { title: 'Pride and Prejudice' }); }); it('arrayContains works', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where(arrayContains('tags', 'comedy')) .select('title') ); - expectResults(results, { + expectResults(snapshot, { title: "The Hitchhiker's Guide to the Galaxy" }); }); it('arrayContainsAny works', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where(arrayContainsAny('tags', ['comedy', 'classic'])) .select('title') ); expectResults( - results, + snapshot, { title: "The Hitchhiker's Guide to the Galaxy" }, { title: 'Pride and Prejudice' } ); }); it('arrayContainsAll works', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where(Field.of('tags').arrayContainsAll('adventure', 'magic')) .select('title') ); - expectResults(results, { title: 'The Lord of the Rings' }); + expectResults(snapshot, { title: 'The Lord of the Rings' }); }); it('arrayLength works', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .select(Field.of('tags').arrayLength().as('tagsCount')) .where(eq('tagsCount', 3)) ); - expect(results.length).to.equal(10); + expect(snapshot.results.length).to.equal(10); }); it('testStrConcat', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .select( @@ -1311,13 +1310,13 @@ apiDescribe.only('Pipelines', persistence => { ) .limit(1) ); - expectResults(results, { + expectResults(snapshot, { bookInfo: "Douglas Adams - The Hitchhiker's Guide to the Galaxy" }); }); it('testStartsWith', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where(startsWith('title', 'The')) @@ -1325,7 +1324,7 @@ apiDescribe.only('Pipelines', persistence => { .sort(Field.of('title').ascending()) ); expectResults( - results, + snapshot, { title: 'The Great Gatsby' }, { title: "The Handmaid's Tale" }, { title: "The Hitchhiker's Guide to the Galaxy" }, @@ -1334,7 +1333,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('testEndsWith', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where(endsWith('title', 'y')) @@ -1342,14 +1341,14 @@ apiDescribe.only('Pipelines', persistence => { .sort(Field.of('title').descending()) ); expectResults( - results, + snapshot, { title: "The Hitchhiker's Guide to the Galaxy" }, { title: 'The Great Gatsby' } ); }); it('testLength', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .select( @@ -1361,7 +1360,7 @@ apiDescribe.only('Pipelines', persistence => { ); expectResults( - results, + snapshot, { titleLength: 29, @@ -1383,30 +1382,30 @@ apiDescribe.only('Pipelines', persistence => { }); it('testLike', async () => { - const results = await execute( + const snapshot = await execute( randomCol.pipeline().where(like('title', '%Guide%')).select('title') ); - expectResults(results, { + expectResults(snapshot, { title: "The Hitchhiker's Guide to the Galaxy" }); }); it('testRegexContains', async () => { - const results = await execute( + const snapshot = await execute( randomCol.pipeline().where(regexContains('title', '(?i)(the|of)')) ); - expect(results.length).to.equal(5); + expect(snapshot.results.length).to.equal(5); }); it('testRegexMatches', async () => { - const results = await execute( + const snapshot = await execute( randomCol.pipeline().where(regexMatch('title', '.*(?i)(the|of).*')) ); - expect(results.length).to.equal(5); + expect(snapshot.results.length).to.equal(5); }); it('testArithmeticOperations', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .select( @@ -1419,7 +1418,7 @@ apiDescribe.only('Pipelines', persistence => { ) .limit(1) ); - expectResults(results, { + expectResults(snapshot, { ratingPlusOne: 5.2, yearsSince1900: 79, ratingTimesTen: 42, @@ -1430,7 +1429,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('testComparisonOperators', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where( @@ -1444,7 +1443,7 @@ apiDescribe.only('Pipelines', persistence => { .sort(Field.of('title').ascending()) ); expectResults( - results, + snapshot, { rating: 4.3, title: 'Crime and Punishment' }, { rating: 4.3, @@ -1455,7 +1454,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('testLogicalOperators', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where( @@ -1468,7 +1467,7 @@ apiDescribe.only('Pipelines', persistence => { .sort(Field.of('title').ascending()) ); expectResults( - results, + snapshot, { title: 'Crime and Punishment' }, { title: 'Dune' }, { title: 'Pride and Prejudice' } @@ -1476,7 +1475,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('testChecks', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) @@ -1493,7 +1492,7 @@ apiDescribe.only('Pipelines', persistence => { isNotNan('cost').as('costIsNotNan') ) ); - expectResults(results, { + expectResults(snapshot, { ratingIsNull: false, ratingIsNaN: false, isError: true, @@ -1503,7 +1502,7 @@ apiDescribe.only('Pipelines', persistence => { costIsNotNan: false }); - results = await execute( + snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) @@ -1520,7 +1519,7 @@ apiDescribe.only('Pipelines', persistence => { Field.of('cost').isNotNan().as('costIsNotNan') ) ); - expectResults(results, { + expectResults(snapshot, { ratingIsNull: false, ratingIsNaN: false, isError: true, @@ -1532,7 +1531,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('testMapGet', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .sort(Field.of('published').descending()) @@ -1544,7 +1543,7 @@ apiDescribe.only('Pipelines', persistence => { .where(eq('hugoAward', true)) ); expectResults( - results, + snapshot, { hugoAward: true, title: "The Hitchhiker's Guide to the Galaxy", @@ -1557,7 +1556,7 @@ apiDescribe.only('Pipelines', persistence => { it('testDistanceFunctions', async () => { const sourceVector = [0.1, 0.1]; const targetVector = [0.5, 0.8]; - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .select( @@ -1577,14 +1576,14 @@ apiDescribe.only('Pipelines', persistence => { .limit(1) ); - expectResults(results, { + expectResults(snapshot, { cosineDistance: 0.02560880430538015, dotProductDistance: 0.13, euclideanDistance: 0.806225774829855, manhattanDistance: 1.1 }); - results = await execute( + snapshot = await execute( randomCol .pipeline() .select( @@ -1604,7 +1603,7 @@ apiDescribe.only('Pipelines', persistence => { .limit(1) ); - expectResults(results, { + expectResults(snapshot, { cosineDistance: 0.02560880430538015, dotProductDistance: 0.13, euclideanDistance: 0.806225774829855, @@ -1613,14 +1612,14 @@ apiDescribe.only('Pipelines', persistence => { }); it('testNestedFields', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where(eq('awards.hugo', true)) .select('title', 'awards.hugo') ); expectResults( - results, + snapshot, { title: "The Hitchhiker's Guide to the Galaxy", 'awards.hugo': true @@ -1630,7 +1629,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('test mapGet with field name including . notation', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where(eq('awards.hugo', true)) @@ -1641,7 +1640,7 @@ apiDescribe.only('Pipelines', persistence => { ) ); expectResults( - results, + snapshot, { title: "The Hitchhiker's Guide to the Galaxy", 'nestedField.level.`1`': null, @@ -1653,7 +1652,7 @@ apiDescribe.only('Pipelines', persistence => { describe('genericFunction', () => { it('add selectable', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .sort(descending('rating')) @@ -1664,13 +1663,13 @@ apiDescribe.only('Pipelines', persistence => { ) ) ); - expectResults(results, { + expectResults(snapshot, { rating: 5.7 }); }); it('and (variadic) selectable', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where( @@ -1682,13 +1681,13 @@ apiDescribe.only('Pipelines', persistence => { ) .select('title') ); - expectResults(results, { + expectResults(snapshot, { title: '1984' }); }); it('array contains any', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .where( @@ -1699,13 +1698,13 @@ apiDescribe.only('Pipelines', persistence => { ) .select('title') ); - expectResults(results, { + expectResults(snapshot, { title: 'Dune' }); }); it('countif aggregate', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .aggregate( @@ -1714,13 +1713,13 @@ apiDescribe.only('Pipelines', persistence => { ]).as('countOfBest') ) ); - expectResults(results, { + expectResults(snapshot, { countOfBest: 3 }); }); it('sort by char_len', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .sort( @@ -1731,7 +1730,7 @@ apiDescribe.only('Pipelines', persistence => { .select('title') ); expectResults( - results, + snapshot, { title: '1984' }, @@ -1747,71 +1746,71 @@ apiDescribe.only('Pipelines', persistence => { describe.skip('not implemented in backend', () => { it('supports Bit_and', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .limit(1) .select(bitAnd(Constant.of(5), 12).as('result')) ); - expectResults(results, { + expectResults(snapshot, { result: 4 }); it('supports Bit_and', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .limit(1) .select(Constant.of(5).bitAnd(12).as('result')) ); - expectResults(results, { + expectResults(snapshot, { result: 4 }); }); it('supports Bit_or', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .limit(1) .select(bitOr(Constant.of(5), 12).as('result')) ); - expectResults(results, { + expectResults(snapshot, { result: 13 }); - results = await execute( + snapshot = await execute( randomCol .pipeline() .limit(1) .select(Constant.of(5).bitOr(12).as('result')) ); - expectResults(results, { + expectResults(snapshot, { result: 13 }); }); it('supports Bit_xor', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .limit(1) .select(bitXor(Constant.of(5), 12).as('result')) ); - expectResults(results, { + expectResults(snapshot, { result: 9 }); - results = await execute( + snapshot = await execute( randomCol .pipeline() .limit(1) .select(Constant.of(5).bitXor(12).as('result')) ); - expectResults(results, { + expectResults(snapshot, { result: 9 }); }); it('supports Bit_not', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .limit(1) @@ -1821,10 +1820,10 @@ apiDescribe.only('Pipelines', persistence => { ).as('result') ) ); - expectResults(results, { + expectResults(snapshot, { result: Bytes.fromUint8Array(Uint8Array.of(0x02)) }); - results = await execute( + snapshot = await execute( randomCol .pipeline() .limit(1) @@ -1834,13 +1833,13 @@ apiDescribe.only('Pipelines', persistence => { .as('result') ) ); - expectResults(results, { + expectResults(snapshot, { result: Bytes.fromUint8Array(Uint8Array.of(0x02)) }); }); it('supports Bit_left_shift', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .limit(1) @@ -1851,10 +1850,10 @@ apiDescribe.only('Pipelines', persistence => { ).as('result') ) ); - expectResults(results, { + expectResults(snapshot, { result: Bytes.fromUint8Array(Uint8Array.of(0x04)) }); - results = await execute( + snapshot = await execute( randomCol .pipeline() .limit(1) @@ -1864,13 +1863,13 @@ apiDescribe.only('Pipelines', persistence => { .as('result') ) ); - expectResults(results, { + expectResults(snapshot, { result: Bytes.fromUint8Array(Uint8Array.of(0x04)) }); }); it('supports Bit_right_shift', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .limit(1) @@ -1881,10 +1880,10 @@ apiDescribe.only('Pipelines', persistence => { ).as('result') ) ); - expectResults(results, { + expectResults(snapshot, { result: Bytes.fromUint8Array(Uint8Array.of(0x01)) }); - results = await execute( + snapshot = await execute( randomCol .pipeline() .limit(1) @@ -1894,82 +1893,82 @@ apiDescribe.only('Pipelines', persistence => { .as('result') ) ); - expectResults(results, { + expectResults(snapshot, { result: Bytes.fromUint8Array(Uint8Array.of(0x01)) }); }); it('supports Document_id', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(documentIdFunction(Field.of('__path__')).as('docId')) ); - expectResults(results, { + expectResults(snapshot, { docId: 'book4' }); - results = await execute( + snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(Field.of('__path__').documentId().as('docId')) ); - expectResults(results, { + expectResults(snapshot, { docId: 'book4' }); }); it('supports Substr', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(substr('title', 9, 2).as('of')) ); - expectResults(results, { + expectResults(snapshot, { of: 'of' }); - results = await execute( + snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(Field.of('title').substr(9, 2).as('of')) ); - expectResults(results, { + expectResults(snapshot, { of: 'of' }); }); it('supports Substr without length', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(substr('title', 9).as('of')) ); - expectResults(results, { + expectResults(snapshot, { of: 'of the Rings' }); - results = await execute( + snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(Field.of('title').substr(9).as('of')) ); - expectResults(results, { + expectResults(snapshot, { of: 'of the Rings' }); }); it('arrayConcat works', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .select( @@ -1979,7 +1978,7 @@ apiDescribe.only('Pipelines', persistence => { ) .limit(1) ); - expectResults(results, { + expectResults(snapshot, { modifiedTags: [ 'comedy', 'space', @@ -1995,29 +1994,29 @@ apiDescribe.only('Pipelines', persistence => { }); it('testToLowercase', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .select(Field.of('title').toLower().as('lowercaseTitle')) .limit(1) ); - expectResults(results, { + expectResults(snapshot, { lowercaseTitle: "the hitchhiker's guide to the galaxy" }); }); it('testToUppercase', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .select(Field.of('author').toUpper().as('uppercaseAuthor')) .limit(1) ); - expectResults(results, { uppercaseAuthor: 'DOUGLAS ADAMS' }); + expectResults(snapshot, { uppercaseAuthor: 'DOUGLAS ADAMS' }); }); it('testTrim', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .addFields( @@ -2031,7 +2030,7 @@ apiDescribe.only('Pipelines', persistence => { ) .limit(1) ); - expectResults(results, { + expectResults(snapshot, { spacedTitle: " The Hitchhiker's Guide to the Galaxy ", trimmedTitle: "The Hitchhiker's Guide to the Galaxy" }); @@ -2039,18 +2038,18 @@ apiDescribe.only('Pipelines', persistence => { }); it('supports Rand', async () => { - const results = await execute( + const snapshot = await execute( randomCol.pipeline().limit(10).select(rand().as('result')) ); - expect(results.length).to.equal(10); - results.forEach(d => { + expect(snapshot.results.length).to.equal(10); + snapshot.results.forEach(d => { expect(d.get('result')).to.be.lt(1); expect(d.get('result')).to.be.gte(0); }); }); it('supports array', async () => { - const result = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -2058,14 +2057,14 @@ apiDescribe.only('Pipelines', persistence => { .limit(1) .select(array([1, 2, 3, 4]).as('metadata')) ); - expect(result.length).to.equal(1); - expectResults(result, { + expect(snapshot.results.length).to.equal(1); + expectResults(snapshot, { metadata: [1, 2, 3, 4] }); }); it('evaluates expression in array', async () => { - const result = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -2077,14 +2076,14 @@ apiDescribe.only('Pipelines', persistence => { ) ) ); - expect(result.length).to.equal(1); - expectResults(result, { + expect(snapshot.results.length).to.equal(1); + expectResults(snapshot, { metadata: [1, 2, 'Fantasy', 47] }); }); it('supports arrayOffset', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) @@ -2102,35 +2101,35 @@ apiDescribe.only('Pipelines', persistence => { firstTag: 'classic' } ]; - expectResults(results, ...expectedResults); + expectResults(snapshot, ...expectedResults); - results = await execute( + snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(3) .select(Field.of('tags').arrayOffset(0).as('firstTag')) ); - expectResults(results, ...expectedResults); + expectResults(snapshot, ...expectedResults); }); }); // TODO: current_context tests with are failing because of b/395937453 it.skip('supports currentContext', async () => { - const results = await execute( + const snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(currentContext().as('currentContext')) ); - expectResults(results, { + expectResults(snapshot, { currentContext: 'TODO' }); }); it('supports map', async () => { - const result = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -2143,8 +2142,8 @@ apiDescribe.only('Pipelines', persistence => { ) ); - expect(result.length).to.equal(1); - expectResults(result, { + expect(snapshot.results.length).to.equal(1); + expectResults(snapshot, { metadata: { foo: 'bar' } @@ -2152,7 +2151,7 @@ apiDescribe.only('Pipelines', persistence => { }); it('evaluates expression in map', async () => { - const result = await execute( + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) @@ -2166,8 +2165,8 @@ apiDescribe.only('Pipelines', persistence => { ) ); - expect(result.length).to.equal(1); - expectResults(result, { + expect(snapshot.results.length).to.equal(1); + expectResults(snapshot, { metadata: { genre: 'Fantasy', rating: 47 @@ -2176,47 +2175,47 @@ apiDescribe.only('Pipelines', persistence => { }); it('supports mapRemove', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(mapRemove('awards', 'hugo').as('awards')) ); - expectResults(results, { + expectResults(snapshot, { awards: { nebula: false } }); - results = await execute( + snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(Field.of('awards').mapRemove('hugo').as('awards')) ); - expectResults(results, { + expectResults(snapshot, { awards: { nebula: false } }); }); it('supports mapMerge', async () => { - let results = await execute( + let snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(mapMerge('awards', { fakeAward: true }).as('awards')) ); - expectResults(results, { + expectResults(snapshot, { awards: { nebula: false, hugo: false, fakeAward: true } }); - results = await execute( + snapshot = await execute( randomCol .pipeline() .sort(Field.of('rating').descending()) .limit(1) .select(Field.of('awards').mapMerge({ fakeAward: true }).as('awards')) ); - expectResults(results, { + expectResults(snapshot, { awards: { nebula: false, hugo: false, fakeAward: true } }); }); @@ -2276,16 +2275,16 @@ apiDescribe.only('Pipelines', persistence => { Field.of('__name__').ascending() ); - let results = await execute(pipeline.limit(pageSize)); + let snapshot = await execute(pipeline.limit(pageSize)); expectResults( - results, + snapshot, { title: 'The Lord of the Rings', rating: 4.7 }, { title: 'Jonathan Strange & Mr Norrell', rating: 4.6 } ); - const lastDoc = results[results.length - 1]; + const lastDoc = snapshot.results[snapshot.results.length - 1]; - results = await execute( + snapshot = await execute( pipeline .where( orFunction( @@ -2299,7 +2298,7 @@ apiDescribe.only('Pipelines', persistence => { .limit(pageSize) ); expectResults( - results, + snapshot, { title: 'Pride and Prejudice', rating: 4.5 }, { title: 'Crime and Punishment', rating: 4.3 } ); @@ -2321,12 +2320,12 @@ apiDescribe.only('Pipelines', persistence => { const pageSize = 2; let currPage = 0; - let results = await execute( + let snapshot = await execute( pipeline.offset(currPage++ * pageSize).limit(pageSize) ); expectResults( - results, + snapshot, { title: 'The Lord of the Rings', rating: 4.7 @@ -2334,11 +2333,11 @@ apiDescribe.only('Pipelines', persistence => { { title: 'Dune', rating: 4.6 } ); - results = await execute( + snapshot = await execute( pipeline.offset(currPage++ * pageSize).limit(pageSize) ); expectResults( - results, + snapshot, { title: 'Jonathan Strange & Mr Norrell', rating: 4.6 @@ -2346,11 +2345,11 @@ apiDescribe.only('Pipelines', persistence => { { title: 'The Master and Margarita', rating: 4.6 } ); - results = await execute( + snapshot = await execute( pipeline.offset(currPage++ * pageSize).limit(pageSize) ); expectResults( - results, + snapshot, { title: 'A Long Way to a Small, Angry Planet', rating: 4.6 diff --git a/packages/firestore/test/integration/api/query_to_pipeline.test.ts b/packages/firestore/test/integration/api/query_to_pipeline.test.ts index b5f7ddec90b..5a54e20c805 100644 --- a/packages/firestore/test/integration/api/query_to_pipeline.test.ts +++ b/packages/firestore/test/integration/api/query_to_pipeline.test.ts @@ -18,11 +18,11 @@ import { expect, use } from 'chai'; import chaiAsPromised from 'chai-as-promised'; +import { PipelineSnapshot } from '../../../src/lite-api/pipeline-result'; import { addEqualityMatcher } from '../../util/equality_matcher'; import { doc, DocumentData, - PipelineResult, setDoc, setLogLevel, query, @@ -55,17 +55,18 @@ setLogLevel('debug'); // This is the Query integration tests from the lite API (no cache support) // with some additional test cases added for more complete coverage. -apiDescribe('Query to Pipeline', persistence => { +apiDescribe.only('Query to Pipeline', persistence => { addEqualityMatcher(); function verifyResults( - actual: Array>, + actual: PipelineSnapshot, ...expected: DocumentData[] ): void { - expect(actual.length).to.equal(expected.length); + const results = actual.results; + expect(results.length).to.equal(expected.length); for (let i = 0; i < expected.length; ++i) { - expect(actual[i].data()).to.deep.equal(expected[i]); + expect(results[i].data()).to.deep.equal(expected[i]); } } @@ -74,8 +75,8 @@ apiDescribe('Query to Pipeline', persistence => { PERSISTENCE_MODE_UNSPECIFIED, { 1: { foo: 1 } }, async collRef => { - const result = await execute(collRef.pipeline()); - verifyResults(result, { foo: 1 }); + const snapshot = await execute(collRef.pipeline()); + verifyResults(snapshot, { foo: 1 }); } ); }); @@ -89,8 +90,8 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, where('foo', '==', 1)); - const result = await execute(query1.pipeline()); - verifyResults(result, { foo: 1 }); + const snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 1 }); } ); }); @@ -104,8 +105,8 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, where(new FieldPath('foo'), '==', 1)); - const result = await execute(query1.pipeline()); - verifyResults(result, { foo: 1 }); + const snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 1 }); } ); }); @@ -119,8 +120,8 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo')); - const result = await execute(query1.pipeline()); - verifyResults(result, { foo: 1 }, { foo: 2 }); + const snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 1 }, { foo: 2 }); } ); }); @@ -134,8 +135,8 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo', 'asc')); - const result = await execute(query1.pipeline()); - verifyResults(result, { foo: 1 }, { foo: 2 }); + const snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 1 }, { foo: 2 }); } ); }); @@ -149,8 +150,8 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo', 'desc')); - const result = await execute(query1.pipeline()); - verifyResults(result, { foo: 2 }, { foo: 1 }); + const snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 2 }, { foo: 1 }); } ); }); @@ -164,8 +165,8 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo'), limit(1)); - const result = await execute(query1.pipeline()); - verifyResults(result, { foo: 1 }); + const snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 1 }); } ); }); @@ -180,8 +181,8 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo'), limitToLast(2)); - const result = await execute(query1.pipeline()); - verifyResults(result, { foo: 2 }, { foo: 3 }); + const snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 2 }, { foo: 3 }); } ); }); @@ -195,8 +196,8 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo'), startAt(2)); - const result = await execute(query1.pipeline()); - verifyResults(result, { foo: 2 }); + const snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 2 }); } ); }); @@ -227,9 +228,9 @@ apiDescribe('Query to Pipeline', persistence => { orderBy('baz'), startAfter(docRef) ); - let result = await execute(query1.pipeline()); + let snapshot = await execute(query1.pipeline()); verifyResults( - result, + snapshot, { id: 3, foo: 1, bar: 1, baz: 2 }, { id: 4, foo: 1, bar: 2, baz: 1 }, { id: 5, foo: 1, bar: 2, baz: 2 }, @@ -250,9 +251,9 @@ apiDescribe('Query to Pipeline', persistence => { orderBy('baz'), startAfter(docRef) ); - result = await execute(query1.pipeline()); + snapshot = await execute(query1.pipeline()); verifyResults( - result, + snapshot, { id: 4, foo: 1, bar: 2, baz: 1 }, { id: 5, foo: 1, bar: 2, baz: 2 }, { id: 6, foo: 1, bar: 2, baz: 2 }, @@ -293,9 +294,9 @@ apiDescribe('Query to Pipeline', persistence => { orderBy('baz'), startAt(docRef) ); - let result = await execute(query1.pipeline()); + let snapshot = await execute(query1.pipeline()); verifyResults( - result, + snapshot, { id: 2, foo: 1, bar: 1, baz: 2 }, { id: 3, foo: 1, bar: 1, baz: 2 }, { id: 4, foo: 1, bar: 2, baz: 1 }, @@ -317,9 +318,9 @@ apiDescribe('Query to Pipeline', persistence => { orderBy('baz'), startAt(docRef) ); - result = await execute(query1.pipeline()); + snapshot = await execute(query1.pipeline()); verifyResults( - result, + snapshot, { id: 3, foo: 1, bar: 1, baz: 2 }, { id: 4, foo: 1, bar: 2, baz: 1 }, { id: 5, foo: 1, bar: 2, baz: 2 }, @@ -344,8 +345,8 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo'), startAfter(1)); - const result = await execute(query1.pipeline()); - verifyResults(result, { foo: 2 }); + const snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 2 }); } ); }); @@ -359,8 +360,8 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo'), endAt(1)); - const result = await execute(query1.pipeline()); - verifyResults(result, { foo: 1 }); + const snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 1 }); } ); }); @@ -374,8 +375,8 @@ apiDescribe('Query to Pipeline', persistence => { }, async collRef => { const query1 = query(collRef, orderBy('foo'), endBefore(2)); - const result = await execute(query1.pipeline()); - verifyResults(result, { foo: 1 }); + const snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 1 }); } ); }); @@ -390,13 +391,13 @@ apiDescribe('Query to Pipeline', persistence => { async collRef => { let query1 = query(collRef, orderBy('foo'), limit(1)); const pipeline1 = query1.pipeline(); - let result = await execute(pipeline1); - verifyResults(result, { foo: 1 }); + let snapshot = await execute(pipeline1); + verifyResults(snapshot, { foo: 1 }); - // Pass the document snapshot from the previous result - query1 = query(query1, startAfter(result[0].get('foo'))); - result = await execute(query1.pipeline()); - verifyResults(result, { foo: 2 }); + // Pass the document snapshot from the previous snapshot + query1 = query(query1, startAfter(snapshot.results[0].get('foo'))); + snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 2 }); } ); }); @@ -416,16 +417,19 @@ apiDescribe('Query to Pipeline', persistence => { limit(1) ); const pipeline1 = query1.pipeline(); - let result = await execute(pipeline1); - verifyResults(result, { foo: 1 }); + let snapshot = await execute(pipeline1); + verifyResults(snapshot, { foo: 1 }); - // Pass the document snapshot from the previous result + // Pass the document snapshot from the previous snapshot query1 = query( query1, - startAfter(result[0].get('foo'), result[0].ref?.id) + startAfter( + snapshot.results[0].get('foo'), + snapshot.results[0].ref?.id + ) ); - result = await execute(query1.pipeline()); - verifyResults(result, { foo: 2 }); + snapshot = await execute(query1.pipeline()); + verifyResults(snapshot, { foo: 2 }); } ); }); @@ -449,9 +453,9 @@ apiDescribe('Query to Pipeline', persistence => { await setDoc(barDoc, { bar: 1 }); const query1 = collectionGroup(collRef.firestore, collectionGroupId); - const result = await execute(query1.pipeline()); + const snapshot = await execute(query1.pipeline()); - verifyResults(result, { bar: 1 }, { foo: 1 }); + verifyResults(snapshot, { bar: 1 }, { foo: 1 }); } ); }); @@ -470,11 +474,11 @@ apiDescribe('Query to Pipeline', persistence => { await addDoc(collectionWithSpecials, { foo: 1 }); await addDoc(collectionWithSpecials, { foo: 2 }); - const result = await execute( + const snapshot = await execute( query(collectionWithSpecials, orderBy('foo', 'asc')).pipeline() ); - verifyResults(result, { foo: 1 }, { foo: 2 }); + verifyResults(snapshot, { foo: 1 }, { foo: 2 }); } ); }); @@ -501,9 +505,9 @@ apiDescribe('Query to Pipeline', persistence => { collRef, and(where('id', '>', 2), where('id', '<=', 10)) ); - const result = await execute(query1.pipeline()); + const snapshot = await execute(query1.pipeline()); verifyResults( - result, + snapshot, { id: 3, foo: 1, bar: 1, baz: 2 }, { id: 4, foo: 1, bar: 2, baz: 1 }, { id: 5, foo: 1, bar: 2, baz: 2 }, @@ -539,9 +543,9 @@ apiDescribe('Query to Pipeline', persistence => { collRef, and(where('id', '>=', 2), where('baz', '<', 2)) ); - const result = await execute(query1.pipeline()); + const snapshot = await execute(query1.pipeline()); verifyResults( - result, + snapshot, { id: 4, foo: 1, bar: 2, baz: 1 }, { id: 7, foo: 2, bar: 1, baz: 1 }, { id: 10, foo: 2, bar: 2, baz: 1 } From 8a06e25107b615778be579459a76397708830c5d Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 28 Feb 2025 14:01:19 -0700 Subject: [PATCH 41/75] Renames for API review: FunctionExpr, BooleanExpr, params --- .../firestore/lite/pipelines/pipelines.ts | 4 +- packages/firestore/src/api_pipelines.ts | 4 +- .../firestore/src/lite-api/expressions.ts | 742 ++++++++---------- packages/firestore/src/lite-api/pipeline.ts | 102 ++- 4 files changed, 401 insertions(+), 451 deletions(-) diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index 26592a34e35..197be8f7604 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -138,10 +138,10 @@ export { ExprWithAlias, Field, Constant, - FirestoreFunction, + FunctionExpr, Ordering, ExprType, - AggregateFunctionWithAlias, + AggregateWithAlias, Selectable, BooleanExpr, AggregateFunction diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index 9ece7bfad7e..8619d730491 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -136,13 +136,13 @@ export { ExprWithAlias, Field, Constant, - FirestoreFunction, + FunctionExpr, Ordering } from './lite-api/expressions'; export type { ExprType, - AggregateFunctionWithAlias, + AggregateWithAlias, Selectable, BooleanExpr, AggregateFunction diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 8aaf0973860..e5ee87f0e6b 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -158,9 +158,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param others Optional additional expressions or literals to add to this expression. * @return A new `Expr` representing the addition operation. */ - add(second: Expr | any, ...others: Array): FirestoreFunction { + add(second: Expr | any, ...others: Array): FunctionExpr { const values = [second, ...others]; - return new FirestoreFunction('add', [ + return new FunctionExpr('add', [ this, ...values.map(value => valueToDefaultExpr(value)) ]); @@ -177,7 +177,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The expression to subtract from this expression. * @return A new `Expr` representing the subtraction operation. */ - subtract(other: Expr): FirestoreFunction; + subtract(other: Expr): FunctionExpr; /** * Creates an expression that subtracts a constant value from this expression. @@ -190,9 +190,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The constant value to subtract. * @return A new `Expr` representing the subtraction operation. */ - subtract(other: any): FirestoreFunction; - subtract(other: any): FirestoreFunction { - return new FirestoreFunction('subtract', [this, valueToDefaultExpr(other)]); + subtract(other: any): FunctionExpr; + subtract(other: any): FunctionExpr { + return new FunctionExpr('subtract', [this, valueToDefaultExpr(other)]); } /** @@ -207,11 +207,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param others Optional additional expressions or literals to multiply by. * @return A new `Expr` representing the multiplication operation. */ - multiply( - second: Expr | any, - ...others: Array - ): FirestoreFunction { - return new FirestoreFunction('multiply', [ + multiply(second: Expr | any, ...others: Array): FunctionExpr { + return new FunctionExpr('multiply', [ this, valueToDefaultExpr(second), ...others.map(value => valueToDefaultExpr(value)) @@ -229,7 +226,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The expression to divide by. * @return A new `Expr` representing the division operation. */ - divide(other: Expr): FirestoreFunction; + divide(other: Expr): FunctionExpr; /** * Creates an expression that divides this expression by a constant value. @@ -242,9 +239,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The constant value to divide by. * @return A new `Expr` representing the division operation. */ - divide(other: any): FirestoreFunction; - divide(other: any): FirestoreFunction { - return new FirestoreFunction('divide', [this, valueToDefaultExpr(other)]); + divide(other: any): FunctionExpr; + divide(other: any): FunctionExpr { + return new FunctionExpr('divide', [this, valueToDefaultExpr(other)]); } /** @@ -258,7 +255,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The expression to divide by. * @return A new `Expr` representing the modulo operation. */ - mod(other: Expr): FirestoreFunction; + mod(other: Expr): FunctionExpr; /** * Creates an expression that calculates the modulo (remainder) of dividing this expression by a constant value. @@ -271,9 +268,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The constant value to divide by. * @return A new `Expr` representing the modulo operation. */ - mod(other: any): FirestoreFunction; - mod(other: any): FirestoreFunction { - return new FirestoreFunction('mod', [this, valueToDefaultExpr(other)]); + mod(other: any): FunctionExpr; + mod(other: any): FunctionExpr { + return new FunctionExpr('mod', [this, valueToDefaultExpr(other)]); } /** @@ -467,10 +464,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { arrayConcat( secondArray: Expr | any[], ...otherArrays: Array - ): FirestoreFunction { + ): FunctionExpr { const elements = [secondArray, ...otherArrays]; const exprValues = elements.map(value => valueToDefaultExpr(value)); - return new FirestoreFunction('array_concat', [this, ...exprValues]); + return new FunctionExpr('array_concat', [this, ...exprValues]); } /** @@ -582,8 +579,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new `Expr` representing the length of the array. */ - arrayLength(): FirestoreFunction { - return new FirestoreFunction('array_length', [this]); + arrayLength(): FunctionExpr { + return new FunctionExpr('array_length', [this]); } /** @@ -702,8 +699,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new `Expr` representing the length of the string. */ - charLength(): FirestoreFunction { - return new FirestoreFunction('char_length', [this]); + charLength(): FunctionExpr { + return new FunctionExpr('char_length', [this]); } /** @@ -717,7 +714,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new `Expr` representing the 'like' comparison. */ - like(pattern: string): FirestoreFunction; + like(pattern: string): FunctionExpr; /** * Creates an expression that performs a case-sensitive string comparison. @@ -730,12 +727,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new `Expr` representing the 'like' comparison. */ - like(pattern: Expr): FirestoreFunction; - like(stringOrExpr: string | Expr): FirestoreFunction { - return new FirestoreFunction('like', [ - this, - valueToDefaultExpr(stringOrExpr) - ]); + like(pattern: Expr): FunctionExpr; + like(stringOrExpr: string | Expr): FunctionExpr { + return new FunctionExpr('like', [this, valueToDefaultExpr(stringOrExpr)]); } /** @@ -912,8 +906,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new `Expr` representing the lowercase string. */ - toLower(): FirestoreFunction { - return new FirestoreFunction('to_lower', [this]); + toLower(): FunctionExpr { + return new FunctionExpr('to_lower', [this]); } /** @@ -926,8 +920,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new `Expr` representing the uppercase string. */ - toUpper(): FirestoreFunction { - return new FirestoreFunction('to_upper', [this]); + toUpper(): FunctionExpr { + return new FunctionExpr('to_upper', [this]); } /** @@ -940,8 +934,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new `Expr` representing the trimmed string. */ - trim(): FirestoreFunction { - return new FirestoreFunction('trim', [this]); + trim(): FunctionExpr { + return new FunctionExpr('trim', [this]); } /** @@ -959,10 +953,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { strConcat( secondString: Expr | string, ...otherStrings: Array - ): FirestoreFunction { + ): FunctionExpr { const elements = [secondString, ...otherStrings]; const exprs = elements.map(valueToDefaultExpr); - return new FirestoreFunction('str_concat', [this, ...exprs]); + return new FunctionExpr('str_concat', [this, ...exprs]); } /** @@ -975,8 +969,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new {@code Expr} representing the reversed string. */ - reverse(): FirestoreFunction { - return new FirestoreFunction('reverse', [this]); + reverse(): FunctionExpr { + return new FunctionExpr('reverse', [this]); } /** @@ -991,7 +985,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param replace The substring to replace the first occurrence of 'find' with. * @return A new {@code Expr} representing the string with the first occurrence replaced. */ - replaceFirst(find: string, replace: string): FirestoreFunction; + replaceFirst(find: string, replace: string): FunctionExpr; /** * Creates an expression that replaces the first occurrence of a substring within this string expression with another substring, @@ -1006,9 +1000,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param replace The expression representing the substring to replace the first occurrence of 'find' with. * @return A new {@code Expr} representing the string with the first occurrence replaced. */ - replaceFirst(find: Expr, replace: Expr): FirestoreFunction; - replaceFirst(find: Expr | string, replace: Expr | string): FirestoreFunction { - return new FirestoreFunction('replace_first', [ + replaceFirst(find: Expr, replace: Expr): FunctionExpr; + replaceFirst(find: Expr | string, replace: Expr | string): FunctionExpr { + return new FunctionExpr('replace_first', [ this, valueToDefaultExpr(find), valueToDefaultExpr(replace) @@ -1027,7 +1021,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param replace The substring to replace all occurrences of 'find' with. * @return A new {@code Expr} representing the string with all occurrences replaced. */ - replaceAll(find: string, replace: string): FirestoreFunction; + replaceAll(find: string, replace: string): FunctionExpr; /** * Creates an expression that replaces all occurrences of a substring within this string expression with another substring, @@ -1042,9 +1036,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param replace The expression representing the substring to replace all occurrences of 'find' with. * @return A new {@code Expr} representing the string with all occurrences replaced. */ - replaceAll(find: Expr, replace: Expr): FirestoreFunction; - replaceAll(find: Expr | string, replace: Expr | string): FirestoreFunction { - return new FirestoreFunction('replace_all', [ + replaceAll(find: Expr, replace: Expr): FunctionExpr; + replaceAll(find: Expr | string, replace: Expr | string): FunctionExpr { + return new FunctionExpr('replace_all', [ this, valueToDefaultExpr(find), valueToDefaultExpr(replace) @@ -1061,8 +1055,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new {@code Expr} representing the length of the string in bytes. */ - byteLength(): FirestoreFunction { - return new FirestoreFunction('byte_length', [this]); + byteLength(): FunctionExpr { + return new FunctionExpr('byte_length', [this]); } /** @@ -1076,8 +1070,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param subfield The key to access in the map. * @return A new `Expr` representing the value associated with the given key in the map. */ - mapGet(subfield: string): FirestoreFunction { - return new FirestoreFunction('map_get', [this, Constant.of(subfield)]); + mapGet(subfield: string): FunctionExpr { + return new FunctionExpr('map_get', [this, Constant.of(subfield)]); } /** @@ -1167,9 +1161,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { logicalMaximum( second: Expr | any, ...others: Array - ): FirestoreFunction { + ): FunctionExpr { const values = [second, ...others]; - return new FirestoreFunction('logical_maximum', [ + return new FunctionExpr('logical_maximum', [ this, ...values.map(valueToDefaultExpr) ]); @@ -1190,9 +1184,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { logicalMinimum( second: Expr | any, ...others: Array - ): FirestoreFunction { + ): FunctionExpr { const values = [second, ...others]; - return new FirestoreFunction('logical_min', [ + return new FunctionExpr('logical_min', [ this, ...values.map(valueToDefaultExpr) ]); @@ -1208,8 +1202,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new {@code Expr} representing the length of the vector. */ - vectorLength(): FirestoreFunction { - return new FirestoreFunction('vector_length', [this]); + vectorLength(): FunctionExpr { + return new FunctionExpr('vector_length', [this]); } /** @@ -1223,7 +1217,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The other vector (represented as an Expr) to compare against. * @return A new `Expr` representing the cosine distance between the two vectors. */ - cosineDistance(other: Expr): FirestoreFunction; + cosineDistance(other: Expr): FunctionExpr; /** * Calculates the Cosine distance between two vectors. * @@ -1235,7 +1229,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The other vector (as a VectorValue) to compare against. * @return A new `Expr` representing the Cosine* distance between the two vectors. */ - cosineDistance(other: VectorValue): FirestoreFunction; + cosineDistance(other: VectorValue): FunctionExpr; /** * Calculates the Cosine distance between two vectors. * @@ -1247,12 +1241,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The other vector (as an array of numbers) to compare against. * @return A new `Expr` representing the Cosine distance between the two vectors. */ - cosineDistance(other: number[]): FirestoreFunction; - cosineDistance(other: Expr | VectorValue | number[]): FirestoreFunction { - return new FirestoreFunction('cosine_distance', [ - this, - vectorToExpr(other) - ]); + cosineDistance(other: number[]): FunctionExpr; + cosineDistance(other: Expr | VectorValue | number[]): FunctionExpr { + return new FunctionExpr('cosine_distance', [this, vectorToExpr(other)]); } /** @@ -1266,7 +1257,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the dot product between the two vectors. */ - dotProduct(other: Expr): FirestoreFunction; + dotProduct(other: Expr): FunctionExpr; /** * Calculates the dot product between two vectors. @@ -1279,7 +1270,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the dot product between the two vectors. */ - dotProduct(other: VectorValue): FirestoreFunction; + dotProduct(other: VectorValue): FunctionExpr; /** * Calculates the dot product between two vectors. @@ -1292,9 +1283,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the dot product between the two vectors. */ - dotProduct(other: number[]): FirestoreFunction; - dotProduct(other: Expr | VectorValue | number[]): FirestoreFunction { - return new FirestoreFunction('dot_product', [this, vectorToExpr(other)]); + dotProduct(other: number[]): FunctionExpr; + dotProduct(other: Expr | VectorValue | number[]): FunctionExpr { + return new FunctionExpr('dot_product', [this, vectorToExpr(other)]); } /** @@ -1308,7 +1299,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the Euclidean distance between the two vectors. */ - euclideanDistance(other: Expr): FirestoreFunction; + euclideanDistance(other: Expr): FunctionExpr; /** * Calculates the Euclidean distance between two vectors. @@ -1321,7 +1312,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The other vector (as a VectorValue) to compare against. * @return A new `Expr` representing the Euclidean distance between the two vectors. */ - euclideanDistance(other: VectorValue): FirestoreFunction; + euclideanDistance(other: VectorValue): FunctionExpr; /** * Calculates the Euclidean distance between two vectors. @@ -1334,12 +1325,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The other vector (as an array of numbers) to compare against. * @return A new `Expr` representing the Euclidean distance between the two vectors. */ - euclideanDistance(other: number[]): FirestoreFunction; - euclideanDistance(other: Expr | VectorValue | number[]): FirestoreFunction { - return new FirestoreFunction('euclidean_distance', [ - this, - vectorToExpr(other) - ]); + euclideanDistance(other: number[]): FunctionExpr; + euclideanDistance(other: Expr | VectorValue | number[]): FunctionExpr { + return new FunctionExpr('euclidean_distance', [this, vectorToExpr(other)]); } /** * @beta @@ -1354,7 +1342,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The other vector (as a VectorValue) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ - manhattanDistance(other: VectorValue): FirestoreFunction; + manhattanDistance(other: VectorValue): FunctionExpr; /** * @beta @@ -1369,7 +1357,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The other vector (as an array of doubles) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ - manhattanDistance(other: number[]): FirestoreFunction; + manhattanDistance(other: number[]): FunctionExpr; /** * @beta @@ -1384,12 +1372,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ - manhattanDistance(other: Expr): FirestoreFunction; - manhattanDistance(other: Expr | number[] | VectorValue): FirestoreFunction { - return new FirestoreFunction('manhattan_distance', [ - this, - vectorToExpr(other) - ]); + manhattanDistance(other: Expr): FunctionExpr; + manhattanDistance(other: Expr | number[] | VectorValue): FunctionExpr { + return new FunctionExpr('manhattan_distance', [this, vectorToExpr(other)]); } /** @@ -1403,8 +1388,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new {@code Expr} representing the timestamp. */ - unixMicrosToTimestamp(): FirestoreFunction { - return new FirestoreFunction('unix_micros_to_timestamp', [this]); + unixMicrosToTimestamp(): FunctionExpr { + return new FunctionExpr('unix_micros_to_timestamp', [this]); } /** @@ -1417,8 +1402,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new {@code Expr} representing the number of microseconds since epoch. */ - timestampToUnixMicros(): FirestoreFunction { - return new FirestoreFunction('timestamp_to_unix_micros', [this]); + timestampToUnixMicros(): FunctionExpr { + return new FunctionExpr('timestamp_to_unix_micros', [this]); } /** @@ -1432,8 +1417,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new {@code Expr} representing the timestamp. */ - unixMillisToTimestamp(): FirestoreFunction { - return new FirestoreFunction('unix_millis_to_timestamp', [this]); + unixMillisToTimestamp(): FunctionExpr { + return new FunctionExpr('unix_millis_to_timestamp', [this]); } /** @@ -1446,8 +1431,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new {@code Expr} representing the number of milliseconds since epoch. */ - timestampToUnixMillis(): FirestoreFunction { - return new FirestoreFunction('timestamp_to_unix_millis', [this]); + timestampToUnixMillis(): FunctionExpr { + return new FunctionExpr('timestamp_to_unix_millis', [this]); } /** @@ -1461,8 +1446,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new {@code Expr} representing the timestamp. */ - unixSecondsToTimestamp(): FirestoreFunction { - return new FirestoreFunction('unix_seconds_to_timestamp', [this]); + unixSecondsToTimestamp(): FunctionExpr { + return new FunctionExpr('unix_seconds_to_timestamp', [this]); } /** @@ -1475,8 +1460,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new {@code Expr} representing the number of seconds since epoch. */ - timestampToUnixSeconds(): FirestoreFunction { - return new FirestoreFunction('timestamp_to_unix_seconds', [this]); + timestampToUnixSeconds(): FunctionExpr { + return new FunctionExpr('timestamp_to_unix_seconds', [this]); } /** @@ -1491,7 +1476,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param amount The expression evaluates to amount of the unit. * @return A new {@code Expr} representing the resulting timestamp. */ - timestampAdd(unit: Expr, amount: Expr): FirestoreFunction; + timestampAdd(unit: Expr, amount: Expr): FunctionExpr; /** * Creates an expression that adds a specified amount of time to this timestamp expression. @@ -1508,7 +1493,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { timestampAdd( unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number - ): FirestoreFunction; + ): FunctionExpr; timestampAdd( unit: | Expr @@ -1519,8 +1504,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { | 'hour' | 'day', amount: Expr | number - ): FirestoreFunction { - return new FirestoreFunction('timestamp_add', [ + ): FunctionExpr { + return new FunctionExpr('timestamp_add', [ this, valueToDefaultExpr(unit), valueToDefaultExpr(amount) @@ -1539,7 +1524,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param amount The expression evaluates to amount of the unit. * @return A new {@code Expr} representing the resulting timestamp. */ - timestampSub(unit: Expr, amount: Expr): FirestoreFunction; + timestampSub(unit: Expr, amount: Expr): FunctionExpr; /** * Creates an expression that subtracts a specified amount of time from this timestamp expression. @@ -1556,7 +1541,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { timestampSub( unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number - ): FirestoreFunction; + ): FunctionExpr; timestampSub( unit: | Expr @@ -1567,8 +1552,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { | 'hour' | 'day', amount: Expr | number - ): FirestoreFunction { - return new FirestoreFunction('timestamp_sub', [ + ): FunctionExpr { + return new FunctionExpr('timestamp_sub', [ this, valueToDefaultExpr(unit), valueToDefaultExpr(amount) @@ -1588,7 +1573,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise AND operation. */ - bitAnd(otherBits: number | Bytes): FirestoreFunction; + bitAnd(otherBits: number | Bytes): FunctionExpr; /** * @beta * @@ -1602,9 +1587,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise AND operation. */ - bitAnd(bitsExpression: Expr): FirestoreFunction; - bitAnd(bitsOrExpression: number | Expr | Bytes): FirestoreFunction { - return new FirestoreFunction('bit_and', [ + bitAnd(bitsExpression: Expr): FunctionExpr; + bitAnd(bitsOrExpression: number | Expr | Bytes): FunctionExpr { + return new FunctionExpr('bit_and', [ this, valueToDefaultExpr(bitsOrExpression) ]); @@ -1623,7 +1608,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise OR operation. */ - bitOr(otherBits: number | Bytes): FirestoreFunction; + bitOr(otherBits: number | Bytes): FunctionExpr; /** * @beta * @@ -1637,9 +1622,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise OR operation. */ - bitOr(bitsExpression: Expr): FirestoreFunction; - bitOr(bitsOrExpression: number | Expr | Bytes): FirestoreFunction { - return new FirestoreFunction('bit_or', [ + bitOr(bitsExpression: Expr): FunctionExpr; + bitOr(bitsOrExpression: number | Expr | Bytes): FunctionExpr { + return new FunctionExpr('bit_or', [ this, valueToDefaultExpr(bitsOrExpression) ]); @@ -1658,7 +1643,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise XOR operation. */ - bitXor(otherBits: number | Bytes): FirestoreFunction; + bitXor(otherBits: number | Bytes): FunctionExpr; /** * @beta * @@ -1672,9 +1657,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise XOR operation. */ - bitXor(bitsExpression: Expr): FirestoreFunction; - bitXor(bitsOrExpression: number | Expr | Bytes): FirestoreFunction { - return new FirestoreFunction('bit_xor', [ + bitXor(bitsExpression: Expr): FunctionExpr; + bitXor(bitsOrExpression: number | Expr | Bytes): FunctionExpr { + return new FunctionExpr('bit_xor', [ this, valueToDefaultExpr(bitsOrExpression) ]); @@ -1692,8 +1677,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new {@code Expr} representing the bitwise NOT operation. */ - bitNot(): FirestoreFunction { - return new FirestoreFunction('bit_not', [this]); + bitNot(): FunctionExpr { + return new FunctionExpr('bit_not', [this]); } /** @@ -1709,7 +1694,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param y The operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ - bitLeftShift(y: number): FirestoreFunction; + bitLeftShift(y: number): FunctionExpr; /** * @beta * @@ -1723,9 +1708,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param numberExpr The operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ - bitLeftShift(numberExpr: Expr): FirestoreFunction; - bitLeftShift(numberExpr: number | Expr): FirestoreFunction { - return new FirestoreFunction('bit_left_shift', [ + bitLeftShift(numberExpr: Expr): FunctionExpr; + bitLeftShift(numberExpr: number | Expr): FunctionExpr { + return new FunctionExpr('bit_left_shift', [ this, valueToDefaultExpr(numberExpr) ]); @@ -1744,7 +1729,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param right The operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ - bitRightShift(y: number): FirestoreFunction; + bitRightShift(y: number): FunctionExpr; /** * @beta * @@ -1758,9 +1743,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param numberExpr The operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ - bitRightShift(numberExpr: Expr): FirestoreFunction; - bitRightShift(numberExpr: number | Expr): FirestoreFunction { - return new FirestoreFunction('bit_right_shift', [ + bitRightShift(numberExpr: Expr): FunctionExpr; + bitRightShift(numberExpr: number | Expr): FunctionExpr { + return new FunctionExpr('bit_right_shift', [ this, valueToDefaultExpr(numberExpr) ]); @@ -1778,8 +1763,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * @return A new {@code Expr} representing the documentId operation. */ - documentId(): FirestoreFunction { - return new FirestoreFunction('document_id', [this]); + documentId(): FunctionExpr { + return new FunctionExpr('document_id', [this]); } /** @@ -1791,7 +1776,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param length Length of the substring. If not provided, the substring will * end at the end of the input. */ - substr(position: number, length?: number): FirestoreFunction; + substr(position: number, length?: number): FunctionExpr; /** * @beta @@ -1802,13 +1787,13 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param length An expression returning the length of the substring. If not provided the * substring will end at the end of the input. */ - substr(position: Expr, length?: Expr): FirestoreFunction; - substr(position: Expr | number, length?: Expr | number): FirestoreFunction { + substr(position: Expr, length?: Expr): FunctionExpr; + substr(position: Expr | number, length?: Expr | number): FunctionExpr { const positionExpr = valueToDefaultExpr(position); if (length === undefined) { - return new FirestoreFunction('substr', [this, positionExpr]); + return new FunctionExpr('substr', [this, positionExpr]); } else { - return new FirestoreFunction('substr', [ + return new FunctionExpr('substr', [ this, positionExpr, valueToDefaultExpr(length) @@ -1830,7 +1815,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param offset The index of the element to return. * @return A new Expr representing the 'arrayOffset' operation. */ - arrayOffset(offset: number): FirestoreFunction; + arrayOffset(offset: number): FunctionExpr; /** * @beta @@ -1847,12 +1832,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param offsetExpr An Expr evaluating to the index of the element to return. * @return A new Expr representing the 'arrayOffset' operation. */ - arrayOffset(offsetExpr: Expr): FirestoreFunction; - arrayOffset(offset: Expr | number): FirestoreFunction { - return new FirestoreFunction('array_offset', [ - this, - valueToDefaultExpr(offset) - ]); + arrayOffset(offsetExpr: Expr): FunctionExpr; + arrayOffset(offset: Expr | number): FunctionExpr { + return new FunctionExpr('array_offset', [this, valueToDefaultExpr(offset)]); } /** @@ -1887,7 +1869,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * returned if this expression produces an error. * @return A new {@code Expr} representing the 'ifError' operation. */ - ifError(catchExpr: Expr): FirestoreFunction; + ifError(catchExpr: Expr): FunctionExpr; /** * @beta @@ -1905,12 +1887,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * produces an error. * @return A new {@code Expr} representing the 'ifError' operation. */ - ifError(catchValue: any): FirestoreFunction; - ifError(catchValue: any): FirestoreFunction { - return new FirestoreFunction('if_error', [ - this, - valueToDefaultExpr(catchValue) - ]); + ifError(catchValue: any): FunctionExpr; + ifError(catchValue: any): FunctionExpr { + return new FunctionExpr('if_error', [this, valueToDefaultExpr(catchValue)]); } /** @@ -1975,7 +1954,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param key The name of the key to remove from the input map. * @returns A new {@code FirestoreFunction} representing the 'mapRemove' operation. */ - mapRemove(key: string): FirestoreFunction; + mapRemove(key: string): FunctionExpr; /** * @beta * @@ -1989,9 +1968,9 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param keyExpr An expression that produces the name of the key to remove from the input map. * @returns A new {@code FirestoreFunction} representing the 'mapRemove' operation. */ - mapRemove(keyExpr: Expr): FirestoreFunction; - mapRemove(stringExpr: Expr | string): FirestoreFunction { - return new FirestoreFunction('map_remove', [ + mapRemove(keyExpr: Expr): FunctionExpr; + mapRemove(stringExpr: Expr | string): FunctionExpr { + return new FunctionExpr('map_remove', [ this, valueToDefaultExpr(stringExpr) ]); @@ -2018,10 +1997,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { mapMerge( secondMap: Record | Expr, ...otherMaps: Array | Expr> - ): FirestoreFunction { + ): FunctionExpr { const secondMapExpr = valueToDefaultExpr(secondMap); const otherMapExprs = otherMaps.map(valueToDefaultExpr); - return new FirestoreFunction('map_merge', [ + return new FunctionExpr('map_merge', [ this, secondMapExpr, ...otherMapExprs @@ -2111,11 +2090,11 @@ export class AggregateFunction implements ProtoValueSerializable, UserData { * ``` * * @param name The alias to assign to this AggregateFunction. - * @return A new {@link AggregateFunctionWithAlias} that wraps this + * @return A new {@link AggregateWithAlias} that wraps this * AggregateFunction and associates it with the provided alias. */ - as(name: string): AggregateFunctionWithAlias { - return new AggregateFunctionWithAlias(this, name); + as(name: string): AggregateWithAlias { + return new AggregateWithAlias(this, name); } /** @@ -2149,10 +2128,10 @@ export class AggregateFunction implements ProtoValueSerializable, UserData { * * An AggregateFunction with alias. */ -export class AggregateFunctionWithAlias +export class AggregateWithAlias implements UserData, ProtoSerializable { - constructor(readonly expr: AggregateFunction, readonly alias: string) {} + constructor(readonly aggregate: AggregateFunction, readonly alias: string) {} /** * @private @@ -2167,7 +2146,7 @@ export class AggregateFunctionWithAlias * @internal */ _readUserData(dataReader: UserDataReader): void { - this.expr._readUserData(dataReader); + this.aggregate._readUserData(dataReader); } } @@ -2546,7 +2525,7 @@ export class MapValue extends Expr { * Typically, you would not use this class or its children directly. Use either the functions like {@link and}, {@link eq}, * or the methods on {@link Expr} ({@link Expr#eq}, {@link Expr#lt}, etc) to construct new Function instances. */ -export class FirestoreFunction extends Expr { +export class FunctionExpr extends Expr { exprType: ExprType = 'Function'; constructor(private name: string, private params: Expr[]) { @@ -2582,7 +2561,7 @@ export class FirestoreFunction extends Expr { * * An interface that represents a filter condition. */ -export class BooleanExpr extends FirestoreFunction { +export class BooleanExpr extends FunctionExpr { filterable: true = true; /** @@ -2639,8 +2618,8 @@ export function countIf(booleanExpr: BooleanExpr): AggregateFunction { * * @returns A new `Expr` representing the 'rand' function. */ -export function rand(): FirestoreFunction { - return new FirestoreFunction('rand', []); +export function rand(): FunctionExpr { + return new FunctionExpr('rand', []); } /** @@ -2657,10 +2636,7 @@ export function rand(): FirestoreFunction { * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise AND operation. */ -export function bitAnd( - field: string, - otherBits: number | Bytes -): FirestoreFunction; +export function bitAnd(field: string, otherBits: number | Bytes): FunctionExpr; /** * @beta * @@ -2675,7 +2651,7 @@ export function bitAnd( * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise AND operation. */ -export function bitAnd(field: string, bitsExpression: Expr): FirestoreFunction; +export function bitAnd(field: string, bitsExpression: Expr): FunctionExpr; /** * @beta * @@ -2693,7 +2669,7 @@ export function bitAnd(field: string, bitsExpression: Expr): FirestoreFunction; export function bitAnd( bitsExpression: Expr, otherBits: number | Bytes -): FirestoreFunction; +): FunctionExpr; /** * @beta * @@ -2711,11 +2687,11 @@ export function bitAnd( export function bitAnd( bitsExpression: Expr, otherBitsExpression: Expr -): FirestoreFunction; +): FunctionExpr; export function bitAnd( fieldOrExpression: string | Expr, bitsOrExpression: number | Expr | Bytes -): FirestoreFunction { +): FunctionExpr { return fieldOfOrExpr(fieldOrExpression).bitAnd( valueToDefaultExpr(bitsOrExpression) ); @@ -2735,10 +2711,7 @@ export function bitAnd( * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise OR operation. */ -export function bitOr( - field: string, - otherBits: number | Bytes -): FirestoreFunction; +export function bitOr(field: string, otherBits: number | Bytes): FunctionExpr; /** * @beta * @@ -2753,7 +2726,7 @@ export function bitOr( * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise OR operation. */ -export function bitOr(field: string, bitsExpression: Expr): FirestoreFunction; +export function bitOr(field: string, bitsExpression: Expr): FunctionExpr; /** * @beta * @@ -2771,7 +2744,7 @@ export function bitOr(field: string, bitsExpression: Expr): FirestoreFunction; export function bitOr( bitsExpression: Expr, otherBits: number | Bytes -): FirestoreFunction; +): FunctionExpr; /** * @beta * @@ -2789,11 +2762,11 @@ export function bitOr( export function bitOr( bitsExpression: Expr, otherBitsExpression: Expr -): FirestoreFunction; +): FunctionExpr; export function bitOr( fieldOrExpression: string | Expr, bitsOrExpression: number | Expr | Bytes -): FirestoreFunction { +): FunctionExpr { return fieldOfOrExpr(fieldOrExpression).bitOr( valueToDefaultExpr(bitsOrExpression) ); @@ -2813,10 +2786,7 @@ export function bitOr( * @param otherBits A constant representing bits. * @return A new {@code Expr} representing the bitwise XOR operation. */ -export function bitXor( - field: string, - otherBits: number | Bytes -): FirestoreFunction; +export function bitXor(field: string, otherBits: number | Bytes): FunctionExpr; /** * @beta * @@ -2831,7 +2801,7 @@ export function bitXor( * @param bitsExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise XOR operation. */ -export function bitXor(field: string, bitsExpression: Expr): FirestoreFunction; +export function bitXor(field: string, bitsExpression: Expr): FunctionExpr; /** * @beta * @@ -2849,7 +2819,7 @@ export function bitXor(field: string, bitsExpression: Expr): FirestoreFunction; export function bitXor( bitsExpression: Expr, otherBits: number | Bytes -): FirestoreFunction; +): FunctionExpr; /** * @beta * @@ -2867,11 +2837,11 @@ export function bitXor( export function bitXor( bitsExpression: Expr, otherBitsExpression: Expr -): FirestoreFunction; +): FunctionExpr; export function bitXor( fieldOrExpression: string | Expr, bitsOrExpression: number | Expr | Bytes -): FirestoreFunction { +): FunctionExpr { return fieldOfOrExpr(fieldOrExpression).bitXor( valueToDefaultExpr(bitsOrExpression) ); @@ -2890,7 +2860,7 @@ export function bitXor( * @param field The operand field name. * @return A new {@code Expr} representing the bitwise NOT operation. */ -export function bitNot(field: string): FirestoreFunction; +export function bitNot(field: string): FunctionExpr; /** * @beta * @@ -2904,8 +2874,8 @@ export function bitNot(field: string): FirestoreFunction; * @param bitsValueExpression An expression that returns bits when evaluated. * @return A new {@code Expr} representing the bitwise NOT operation. */ -export function bitNot(bitsValueExpression: Expr): FirestoreFunction; -export function bitNot(bits: string | Expr): FirestoreFunction { +export function bitNot(bitsValueExpression: Expr): FunctionExpr; +export function bitNot(bits: string | Expr): FunctionExpr { return fieldOfOrExpr(bits).bitNot(); } @@ -2923,7 +2893,7 @@ export function bitNot(bits: string | Expr): FirestoreFunction { * @param y The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ -export function bitLeftShift(field: string, y: number): FirestoreFunction; +export function bitLeftShift(field: string, y: number): FunctionExpr; /** * @beta * @@ -2938,10 +2908,7 @@ export function bitLeftShift(field: string, y: number): FirestoreFunction; * @param numberExpr The right operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ -export function bitLeftShift( - field: string, - numberExpr: Expr -): FirestoreFunction; +export function bitLeftShift(field: string, numberExpr: Expr): FunctionExpr; /** * @beta * @@ -2956,7 +2923,7 @@ export function bitLeftShift( * @param y The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ -export function bitLeftShift(xValue: Expr, y: number): FirestoreFunction; +export function bitLeftShift(xValue: Expr, y: number): FunctionExpr; /** * @beta * @@ -2971,11 +2938,11 @@ export function bitLeftShift(xValue: Expr, y: number): FirestoreFunction; * @param right The right operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ -export function bitLeftShift(xValue: Expr, numberExpr: Expr): FirestoreFunction; +export function bitLeftShift(xValue: Expr, numberExpr: Expr): FunctionExpr; export function bitLeftShift( xValue: string | Expr, numberExpr: number | Expr -): FirestoreFunction { +): FunctionExpr { return fieldOfOrExpr(xValue).bitLeftShift(valueToDefaultExpr(numberExpr)); } @@ -2993,7 +2960,7 @@ export function bitLeftShift( * @param right The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ -export function bitRightShift(field: string, y: number): FirestoreFunction; +export function bitRightShift(field: string, y: number): FunctionExpr; /** * @beta * @@ -3008,10 +2975,7 @@ export function bitRightShift(field: string, y: number): FirestoreFunction; * @param numberExpr The right operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ -export function bitRightShift( - field: string, - numberExpr: Expr -): FirestoreFunction; +export function bitRightShift(field: string, numberExpr: Expr): FunctionExpr; /** * @beta * @@ -3026,7 +2990,7 @@ export function bitRightShift( * @param y The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ -export function bitRightShift(xValue: Expr, y: number): FirestoreFunction; +export function bitRightShift(xValue: Expr, y: number): FunctionExpr; /** * @beta * @@ -3041,14 +3005,11 @@ export function bitRightShift(xValue: Expr, y: number): FirestoreFunction; * @param right The right operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ -export function bitRightShift( - xValue: Expr, - numberExpr: Expr -): FirestoreFunction; +export function bitRightShift(xValue: Expr, numberExpr: Expr): FunctionExpr; export function bitRightShift( xValue: string | Expr, numberExpr: number | Expr -): FirestoreFunction { +): FunctionExpr { return fieldOfOrExpr(xValue).bitRightShift(valueToDefaultExpr(numberExpr)); } @@ -3067,10 +3028,7 @@ export function bitRightShift( * @param offset The index of the element to return. * @return A new Expr representing the 'arrayOffset' operation. */ -export function arrayOffset( - arrayField: string, - offset: number -): FirestoreFunction; +export function arrayOffset(arrayField: string, offset: number): FunctionExpr; /** * @beta @@ -3088,10 +3046,7 @@ export function arrayOffset( * @param offsetExpr An Expr evaluating to the index of the element to return. * @return A new Expr representing the 'arrayOffset' operation. */ -export function arrayOffset( - arrayField: string, - offsetExpr: Expr -): FirestoreFunction; +export function arrayOffset(arrayField: string, offsetExpr: Expr): FunctionExpr; /** * @beta @@ -3111,7 +3066,7 @@ export function arrayOffset( export function arrayOffset( arrayExpression: Expr, offset: number -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -3132,11 +3087,11 @@ export function arrayOffset( export function arrayOffset( arrayExpression: Expr, offsetExpr: Expr -): FirestoreFunction; +): FunctionExpr; export function arrayOffset( array: Expr | string, offset: Expr | number -): FirestoreFunction { +): FunctionExpr { return fieldOfOrExpr(array).arrayOffset(valueToDefaultExpr(offset)); } @@ -3146,8 +3101,8 @@ export function arrayOffset( * * @return A new {@code Expr} representing the 'current_context' function. */ -export function currentContext(): FirestoreFunction { - return new FirestoreFunction('current_context', []); +export function currentContext(): FunctionExpr { + return new FunctionExpr('current_context', []); } /** @@ -3184,7 +3139,7 @@ export function isError(value: Expr): BooleanExpr { * returned if the tryExpr produces an error. * @return A new {@code Expr} representing the 'ifError' operation. */ -export function ifError(tryExpr: Expr, catchExpr: Expr): FirestoreFunction; +export function ifError(tryExpr: Expr, catchExpr: Expr): FunctionExpr; /** * @beta @@ -3203,8 +3158,8 @@ export function ifError(tryExpr: Expr, catchExpr: Expr): FirestoreFunction; * error. * @return A new {@code Expr} representing the 'ifError' operation. */ -export function ifError(tryExpr: Expr, catchValue: any): FirestoreFunction; -export function ifError(tryExpr: Expr, catchValue: any): FirestoreFunction { +export function ifError(tryExpr: Expr, catchValue: any): FunctionExpr; +export function ifError(tryExpr: Expr, catchValue: any): FunctionExpr { return tryExpr.ifError(valueToDefaultExpr(catchValue)); } @@ -3355,7 +3310,7 @@ export function isNotNan(value: Expr | string): BooleanExpr { * @param mapField The name of a field containing a map value. * @param key The name of the key to remove from the input map. */ -export function mapRemove(mapField: string, key: string): FirestoreFunction; +export function mapRemove(mapField: string, key: string): FunctionExpr; /** * @beta * @@ -3369,7 +3324,7 @@ export function mapRemove(mapField: string, key: string): FirestoreFunction; * @param mapExpr An expression return a map value. * @param key The name of the key to remove from the input map. */ -export function mapRemove(mapExpr: Expr, key: string): FirestoreFunction; +export function mapRemove(mapExpr: Expr, key: string): FunctionExpr; /** * @beta * @@ -3383,7 +3338,7 @@ export function mapRemove(mapExpr: Expr, key: string): FirestoreFunction; * @param mapField The name of a field containing a map value. * @param keyExpr An expression that produces the name of the key to remove from the input map. */ -export function mapRemove(mapField: string, keyExpr: Expr): FirestoreFunction; +export function mapRemove(mapField: string, keyExpr: Expr): FunctionExpr; /** * @beta * @@ -3397,12 +3352,12 @@ export function mapRemove(mapField: string, keyExpr: Expr): FirestoreFunction; * @param mapExpr An expression return a map value. * @param keyExpr An expression that produces the name of the key to remove from the input map. */ -export function mapRemove(mapExpr: Expr, keyExpr: Expr): FirestoreFunction; +export function mapRemove(mapExpr: Expr, keyExpr: Expr): FunctionExpr; export function mapRemove( mapExpr: Expr | string, stringExpr: Expr | string -): FirestoreFunction { +): FunctionExpr { return fieldOfOrExpr(mapExpr).mapRemove(valueToDefaultExpr(stringExpr)); } @@ -3427,7 +3382,7 @@ export function mapMerge( mapField: string, secondMap: Record | Expr, ...otherMaps: Array | Expr> -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -3450,13 +3405,13 @@ export function mapMerge( firstMap: Record | Expr, secondMap: Record | Expr, ...otherMaps: Array | Expr> -): FirestoreFunction; +): FunctionExpr; export function mapMerge( firstMap: string | Record | Expr, secondMap: Record | Expr, ...otherMaps: Array | Expr> -): FirestoreFunction { +): FunctionExpr { const secondMapExpr = valueToDefaultExpr(secondMap); const otherMapExprs = otherMaps.map(valueToDefaultExpr); return fieldOfOrExpr(firstMap).mapMerge(secondMapExpr, ...otherMapExprs); @@ -3476,7 +3431,7 @@ export function mapMerge( */ export function documentIdFunction( documentPath: string | DocumentReference -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -3490,11 +3445,11 @@ export function documentIdFunction( * * @return A new {@code Expr} representing the documentId operation. */ -export function documentIdFunction(documentPathExpr: Expr): FirestoreFunction; +export function documentIdFunction(documentPathExpr: Expr): FunctionExpr; export function documentIdFunction( documentPath: Expr | string | DocumentReference -): FirestoreFunction { +): FunctionExpr { // @ts-ignore const documentPathExpr = valueToDefaultExpr(documentPath); return documentPathExpr.documentId(); @@ -3513,7 +3468,7 @@ export function substr( field: string, position: number, length?: number -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -3528,7 +3483,7 @@ export function substr( input: Expr, position: number, length?: number -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -3543,7 +3498,7 @@ export function substr( field: string, position: Expr, length?: Expr -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -3558,13 +3513,13 @@ export function substr( input: Expr, position: Expr, length?: Expr -): FirestoreFunction; +): FunctionExpr; export function substr( field: Expr | string, position: Expr | number, length?: Expr | number -): FirestoreFunction { +): FunctionExpr { const fieldExpr = fieldOfOrExpr(field); const positionExpr = valueToDefaultExpr(position); const lengthExpr = @@ -3591,7 +3546,7 @@ export function add( first: Expr, second: Expr | any, ...others: Array -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -3612,13 +3567,13 @@ export function add( fieldName: string, second: Expr | any, ...others: Array -): FirestoreFunction; +): FunctionExpr; export function add( first: Expr | string, second: Expr | any, ...others: Array -): FirestoreFunction { +): FunctionExpr { return fieldOfOrExpr(first).add( valueToDefaultExpr(second), ...others.map(value => valueToDefaultExpr(value)) @@ -3639,7 +3594,7 @@ export function add( * @param right The expression to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: Expr, right: Expr): FirestoreFunction; +export function subtract(left: Expr, right: Expr): FunctionExpr; /** * @beta @@ -3655,7 +3610,7 @@ export function subtract(left: Expr, right: Expr): FirestoreFunction; * @param right The constant value to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: Expr, right: any): FirestoreFunction; +export function subtract(left: Expr, right: any): FunctionExpr; /** * @beta @@ -3671,7 +3626,7 @@ export function subtract(left: Expr, right: any): FirestoreFunction; * @param right The expression to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: string, right: Expr): FirestoreFunction; +export function subtract(left: string, right: Expr): FunctionExpr; /** * @beta @@ -3687,11 +3642,8 @@ export function subtract(left: string, right: Expr): FirestoreFunction; * @param right The constant value to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: string, right: any): FirestoreFunction; -export function subtract( - left: Expr | string, - right: Expr | any -): FirestoreFunction { +export function subtract(left: string, right: any): FunctionExpr; +export function subtract(left: Expr | string, right: Expr | any): FunctionExpr { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; const normalizedRight = valueToDefaultExpr(right); return normalizedLeft.subtract(normalizedRight); @@ -3716,7 +3668,7 @@ export function multiply( first: Expr, second: Expr | any, ...others: Array -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -3737,13 +3689,13 @@ export function multiply( fieldName: string, second: Expr | any, ...others: Array -): FirestoreFunction; +): FunctionExpr; export function multiply( first: Expr | string, second: Expr | any, ...others: Array -): FirestoreFunction { +): FunctionExpr { return fieldOfOrExpr(first).multiply( valueToDefaultExpr(second), ...others.map(valueToDefaultExpr) @@ -3764,7 +3716,7 @@ export function multiply( * @param right The expression to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: Expr, right: Expr): FirestoreFunction; +export function divide(left: Expr, right: Expr): FunctionExpr; /** * @beta @@ -3780,7 +3732,7 @@ export function divide(left: Expr, right: Expr): FirestoreFunction; * @param right The constant value to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: Expr, right: any): FirestoreFunction; +export function divide(left: Expr, right: any): FunctionExpr; /** * @beta @@ -3796,7 +3748,7 @@ export function divide(left: Expr, right: any): FirestoreFunction; * @param right The expression to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: string, right: Expr): FirestoreFunction; +export function divide(left: string, right: Expr): FunctionExpr; /** * @beta @@ -3812,11 +3764,8 @@ export function divide(left: string, right: Expr): FirestoreFunction; * @param right The constant value to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: string, right: any): FirestoreFunction; -export function divide( - left: Expr | string, - right: Expr | any -): FirestoreFunction { +export function divide(left: string, right: any): FunctionExpr; +export function divide(left: Expr | string, right: Expr | any): FunctionExpr { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; const normalizedRight = valueToDefaultExpr(right); return normalizedLeft.divide(normalizedRight); @@ -3836,7 +3785,7 @@ export function divide( * @param right The divisor expression. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: Expr, right: Expr): FirestoreFunction; +export function mod(left: Expr, right: Expr): FunctionExpr; /** * @beta @@ -3852,7 +3801,7 @@ export function mod(left: Expr, right: Expr): FirestoreFunction; * @param right The divisor constant. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: Expr, right: any): FirestoreFunction; +export function mod(left: Expr, right: any): FunctionExpr; /** * @beta @@ -3868,7 +3817,7 @@ export function mod(left: Expr, right: any): FirestoreFunction; * @param right The divisor expression. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: string, right: Expr): FirestoreFunction; +export function mod(left: string, right: Expr): FunctionExpr; /** * @beta @@ -3884,14 +3833,14 @@ export function mod(left: string, right: Expr): FirestoreFunction; * @param right The divisor constant. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: string, right: any): FirestoreFunction; -export function mod(left: Expr | string, right: Expr | any): FirestoreFunction { +export function mod(left: string, right: any): FunctionExpr; +export function mod(left: Expr | string, right: Expr | any): FunctionExpr { const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; const normalizedRight = valueToDefaultExpr(right); return normalizedLeft.mod(normalizedRight); } -export function map(elements: Record): FirestoreFunction { +export function map(elements: Record): FunctionExpr { const result: any[] = []; for (const key in elements) { if (Object.prototype.hasOwnProperty.call(elements, key)) { @@ -3900,7 +3849,7 @@ export function map(elements: Record): FirestoreFunction { result.push(valueToDefaultExpr(value)); } } - return new FirestoreFunction('map', result); + return new FunctionExpr('map', result); } /** @@ -3925,8 +3874,8 @@ export function _mapValue(plainObject: Record): MapValue { return new MapValue(result); } -export function array(elements: any[]): FirestoreFunction { - return new FirestoreFunction( +export function array(elements: any[]): FunctionExpr { + return new FunctionExpr( 'array', elements.map(element => valueToDefaultExpr(element)) ); @@ -4368,7 +4317,7 @@ export function arrayConcat( firstArray: Expr, secondArray: Expr | any, ...otherArrays: Array -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -4389,13 +4338,13 @@ export function arrayConcat( firstArrayField: string, secondArray: Expr | any[], ...otherArrays: Array -): FirestoreFunction; +): FunctionExpr; export function arrayConcat( firstArray: Expr | string, secondArray: Expr | any[], ...otherArrays: Array -): FirestoreFunction { +): FunctionExpr { const exprValues = otherArrays.map(element => valueToDefaultExpr(element)); return fieldOfOrExpr(firstArray).arrayConcat( fieldOfOrExpr(secondArray), @@ -4417,7 +4366,7 @@ export function arrayConcat( * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains(array: Expr, element: Expr): FirestoreFunction; +export function arrayContains(array: Expr, element: Expr): FunctionExpr; /** * @beta @@ -4433,7 +4382,7 @@ export function arrayContains(array: Expr, element: Expr): FirestoreFunction; * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains(array: Expr, element: any): FirestoreFunction; +export function arrayContains(array: Expr, element: any): FunctionExpr; /** * @beta @@ -4449,7 +4398,7 @@ export function arrayContains(array: Expr, element: any): FirestoreFunction; * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains(array: string, element: Expr): FirestoreFunction; +export function arrayContains(array: string, element: Expr): FunctionExpr; /** * @beta @@ -4637,7 +4586,7 @@ export function arrayContainsAll( * @param array The array expression to calculate the length of. * @return A new {@code Expr} representing the length of the array. */ -export function arrayLength(array: Expr): FirestoreFunction { +export function arrayLength(array: Expr): FunctionExpr { return array.arrayLength(); } @@ -4836,7 +4785,7 @@ export function cond( condition: BooleanExpr, thenExpr: Expr, elseExpr: Expr -): FirestoreFunction { +): FunctionExpr { return new BooleanExpr('cond', [condition, thenExpr, elseExpr]); } @@ -4876,7 +4825,7 @@ export function logicalMaximum( first: Expr, second: Expr | any, ...others: Array -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -4897,13 +4846,13 @@ export function logicalMaximum( left: string, second: Expr | any, ...others: Array -): FirestoreFunction; +): FunctionExpr; export function logicalMaximum( first: Expr | string, second: Expr | any, ...others: Array -): FirestoreFunction { +): FunctionExpr { return fieldOfOrExpr(first).logicalMaximum( valueToDefaultExpr(second), ...others.map(value => valueToDefaultExpr(value)) @@ -4929,7 +4878,7 @@ export function logicalMinimum( first: Expr, second: Expr | any, ...others: Array -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -4950,13 +4899,13 @@ export function logicalMinimum( fieldName: string, second: Expr | any, ...others: Array -): FirestoreFunction; +): FunctionExpr; export function logicalMinimum( first: Expr | string, second: Expr | any, ...others: Array -): FirestoreFunction { +): FunctionExpr { return fieldOfOrExpr(first).logicalMinimum( valueToDefaultExpr(second), ...others.map(value => valueToDefaultExpr(value)) @@ -5042,7 +4991,7 @@ export function isNan(value: Expr | string): BooleanExpr { * @param expr The expression representing the string to reverse. * @return A new {@code Expr} representing the reversed string. */ -export function reverse(expr: Expr): FirestoreFunction; +export function reverse(expr: Expr): FunctionExpr; /** * @beta @@ -5057,8 +5006,8 @@ export function reverse(expr: Expr): FirestoreFunction; * @param field The name of the field representing the string to reverse. * @return A new {@code Expr} representing the reversed string. */ -export function reverse(field: string): FirestoreFunction; -export function reverse(expr: Expr | string): FirestoreFunction { +export function reverse(field: string): FunctionExpr; +export function reverse(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).reverse(); } @@ -5081,7 +5030,7 @@ export function replaceFirst( value: Expr, find: string, replace: string -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -5103,7 +5052,7 @@ export function replaceFirst( value: Expr, find: Expr, replace: Expr -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -5124,12 +5073,12 @@ export function replaceFirst( field: string, find: string, replace: string -): FirestoreFunction; +): FunctionExpr; export function replaceFirst( value: Expr | string, find: Expr | string, replace: Expr | string -): FirestoreFunction { +): FunctionExpr { const normalizedValue = fieldOfOrExpr(value); const normalizedFind = valueToDefaultExpr(find); const normalizedReplace = valueToDefaultExpr(replace); @@ -5155,7 +5104,7 @@ export function replaceAll( value: Expr, find: string, replace: string -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -5177,7 +5126,7 @@ export function replaceAll( value: Expr, find: Expr, replace: Expr -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -5198,12 +5147,12 @@ export function replaceAll( field: string, find: string, replace: string -): FirestoreFunction; +): FunctionExpr; export function replaceAll( value: Expr | string, find: Expr | string, replace: Expr | string -): FirestoreFunction { +): FunctionExpr { const normalizedValue = fieldOfOrExpr(value); const normalizedFind = valueToDefaultExpr(find); const normalizedReplace = valueToDefaultExpr(replace); @@ -5223,7 +5172,7 @@ export function replaceAll( * @param expr The expression representing the string. * @return A new {@code Expr} representing the length of the string in bytes. */ -export function byteLength(expr: Expr): FirestoreFunction; +export function byteLength(expr: Expr): FunctionExpr; /** * @beta @@ -5238,8 +5187,8 @@ export function byteLength(expr: Expr): FirestoreFunction; * @param field The name of the field representing the string. * @return A new {@code Expr} representing the length of the string in bytes. */ -export function byteLength(field: string): FirestoreFunction; -export function byteLength(expr: Expr | string): FirestoreFunction { +export function byteLength(field: string): FunctionExpr; +export function byteLength(expr: Expr | string): FunctionExpr { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.byteLength(); } @@ -5257,7 +5206,7 @@ export function byteLength(expr: Expr | string): FirestoreFunction { * @param field The name of the field containing the string. * @return A new {@code Expr} representing the length of the string. */ -export function charLength(field: string): FirestoreFunction; +export function charLength(field: string): FunctionExpr; /** * @beta @@ -5272,8 +5221,8 @@ export function charLength(field: string): FirestoreFunction; * @param expr The expression representing the string to calculate the length of. * @return A new {@code Expr} representing the length of the string. */ -export function charLength(expr: Expr): FirestoreFunction; -export function charLength(value: Expr | string): FirestoreFunction { +export function charLength(expr: Expr): FunctionExpr; +export function charLength(value: Expr | string): FunctionExpr { const valueExpr = fieldOfOrExpr(value); return valueExpr.charLength(); } @@ -5346,7 +5295,7 @@ export function like(left: Expr, pattern: Expr): BooleanExpr; export function like( left: Expr | string, pattern: Expr | string -): FirestoreFunction { +): FunctionExpr { const leftExpr = fieldOfOrExpr(left); const patternExpr = valueToDefaultExpr(pattern); return leftExpr.like(patternExpr); @@ -5727,7 +5676,7 @@ export function endsWith( * @param expr The name of the field containing the string. * @return A new {@code Expr} representing the lowercase string. */ -export function toLower(expr: string): FirestoreFunction; +export function toLower(expr: string): FunctionExpr; /** * @beta @@ -5742,8 +5691,8 @@ export function toLower(expr: string): FirestoreFunction; * @param expr The expression representing the string to convert to lowercase. * @return A new {@code Expr} representing the lowercase string. */ -export function toLower(expr: Expr): FirestoreFunction; -export function toLower(expr: Expr | string): FirestoreFunction { +export function toLower(expr: Expr): FunctionExpr; +export function toLower(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).toLower(); } @@ -5760,7 +5709,7 @@ export function toLower(expr: Expr | string): FirestoreFunction { * @param expr The name of the field containing the string. * @return A new {@code Expr} representing the uppercase string. */ -export function toUpper(expr: string): FirestoreFunction; +export function toUpper(expr: string): FunctionExpr; /** * @beta @@ -5775,8 +5724,8 @@ export function toUpper(expr: string): FirestoreFunction; * @param expr The expression representing the string to convert to uppercase. * @return A new {@code Expr} representing the uppercase string. */ -export function toUpper(expr: Expr): FirestoreFunction; -export function toUpper(expr: Expr | string): FirestoreFunction { +export function toUpper(expr: Expr): FunctionExpr; +export function toUpper(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).toUpper(); } @@ -5793,7 +5742,7 @@ export function toUpper(expr: Expr | string): FirestoreFunction { * @param expr The name of the field containing the string. * @return A new {@code Expr} representing the trimmed string. */ -export function trim(expr: string): FirestoreFunction; +export function trim(expr: string): FunctionExpr; /** * @beta @@ -5808,8 +5757,8 @@ export function trim(expr: string): FirestoreFunction; * @param expr The expression representing the string to trim. * @return A new {@code Expr} representing the trimmed string. */ -export function trim(expr: Expr): FirestoreFunction; -export function trim(expr: Expr | string): FirestoreFunction { +export function trim(expr: Expr): FunctionExpr; +export function trim(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).trim(); } @@ -5832,7 +5781,7 @@ export function strConcat( fieldName: string, secondString: Expr | string, ...otherStrings: Array -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -5852,12 +5801,12 @@ export function strConcat( firstString: Expr, secondString: Expr | string, ...otherStrings: Array -): FirestoreFunction; +): FunctionExpr; export function strConcat( first: string | Expr, second: string | Expr, ...elements: Array -): FirestoreFunction { +): FunctionExpr { return valueToDefaultExpr(first).strConcat( valueToDefaultExpr(second), ...elements.map(valueToDefaultExpr) @@ -5878,7 +5827,7 @@ export function strConcat( * @param subField The key to access in the map. * @return A new {@code Expr} representing the value associated with the given key in the map. */ -export function mapGet(mapField: string, subField: string): FirestoreFunction; +export function mapGet(mapField: string, subField: string): FunctionExpr; /** * @beta @@ -5894,11 +5843,11 @@ export function mapGet(mapField: string, subField: string): FirestoreFunction; * @param subField The key to access in the map. * @return A new {@code Expr} representing the value associated with the given key in the map. */ -export function mapGet(mapExpr: Expr, subField: string): FirestoreFunction; +export function mapGet(mapExpr: Expr, subField: string): FunctionExpr; export function mapGet( fieldOrExpr: string | Expr, subField: string -): FirestoreFunction { +): FunctionExpr { return fieldOfOrExpr(fieldOrExpr).mapGet(subField); } @@ -6103,10 +6052,7 @@ export function maximum(value: Expr | string): AggregateFunction { * @param other The other vector (as an array of doubles) to compare against. * @return A new {@code Expr} representing the Cosine distance between the two vectors. */ -export function cosineDistance( - expr: string, - other: number[] -): FirestoreFunction; +export function cosineDistance(expr: string, other: number[]): FunctionExpr; /** * @beta @@ -6122,10 +6068,7 @@ export function cosineDistance( * @param other The other vector (as a VectorValue) to compare against. * @return A new {@code Expr} representing the Cosine distance between the two vectors. */ -export function cosineDistance( - expr: string, - other: VectorValue -): FirestoreFunction; +export function cosineDistance(expr: string, other: VectorValue): FunctionExpr; /** * @beta @@ -6141,7 +6084,7 @@ export function cosineDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance(expr: string, other: Expr): FirestoreFunction; +export function cosineDistance(expr: string, other: Expr): FunctionExpr; /** * @beta @@ -6157,7 +6100,7 @@ export function cosineDistance(expr: string, other: Expr): FirestoreFunction; * @param other The other vector (as an array of doubles) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance(expr: Expr, other: number[]): FirestoreFunction; +export function cosineDistance(expr: Expr, other: number[]): FunctionExpr; /** * @beta @@ -6173,10 +6116,7 @@ export function cosineDistance(expr: Expr, other: number[]): FirestoreFunction; * @param other The other vector (as a VectorValue) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance( - expr: Expr, - other: VectorValue -): FirestoreFunction; +export function cosineDistance(expr: Expr, other: VectorValue): FunctionExpr; /** * @beta @@ -6192,11 +6132,11 @@ export function cosineDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance(expr: Expr, other: Expr): FirestoreFunction; +export function cosineDistance(expr: Expr, other: Expr): FunctionExpr; export function cosineDistance( expr: Expr | string, other: Expr | number[] | VectorValue -): FirestoreFunction { +): FunctionExpr { const expr1 = fieldOfOrExpr(expr); const expr2 = vectorToExpr(other); return expr1.cosineDistance(expr2); @@ -6216,7 +6156,7 @@ export function cosineDistance( * @param other The other vector (as an array of doubles) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: string, other: number[]): FirestoreFunction; +export function dotProduct(expr: string, other: number[]): FunctionExpr; /** * @beta @@ -6232,7 +6172,7 @@ export function dotProduct(expr: string, other: number[]): FirestoreFunction; * @param other The other vector (as a VectorValue) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: string, other: VectorValue): FirestoreFunction; +export function dotProduct(expr: string, other: VectorValue): FunctionExpr; /** * @beta @@ -6248,7 +6188,7 @@ export function dotProduct(expr: string, other: VectorValue): FirestoreFunction; * @param other The other vector (represented as an Expr) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: string, other: Expr): FirestoreFunction; +export function dotProduct(expr: string, other: Expr): FunctionExpr; /** * @beta @@ -6264,7 +6204,7 @@ export function dotProduct(expr: string, other: Expr): FirestoreFunction; * @param other The other vector (as an array of doubles) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: Expr, other: number[]): FirestoreFunction; +export function dotProduct(expr: Expr, other: number[]): FunctionExpr; /** * @beta @@ -6280,7 +6220,7 @@ export function dotProduct(expr: Expr, other: number[]): FirestoreFunction; * @param other The other vector (as a VectorValue) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: Expr, other: VectorValue): FirestoreFunction; +export function dotProduct(expr: Expr, other: VectorValue): FunctionExpr; /** * @beta @@ -6296,11 +6236,11 @@ export function dotProduct(expr: Expr, other: VectorValue): FirestoreFunction; * @param other The other vector (represented as an Expr) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: Expr, other: Expr): FirestoreFunction; +export function dotProduct(expr: Expr, other: Expr): FunctionExpr; export function dotProduct( expr: Expr | string, other: Expr | number[] | VectorValue -): FirestoreFunction { +): FunctionExpr { const expr1 = fieldOfOrExpr(expr); const expr2 = vectorToExpr(other); return expr1.dotProduct(expr2); @@ -6320,10 +6260,7 @@ export function dotProduct( * @param other The other vector (as an array of doubles) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ -export function euclideanDistance( - expr: string, - other: number[] -): FirestoreFunction; +export function euclideanDistance(expr: string, other: number[]): FunctionExpr; /** * @beta @@ -6342,7 +6279,7 @@ export function euclideanDistance( export function euclideanDistance( expr: string, other: VectorValue -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -6358,7 +6295,7 @@ export function euclideanDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ -export function euclideanDistance(expr: string, other: Expr): FirestoreFunction; +export function euclideanDistance(expr: string, other: Expr): FunctionExpr; /** * @beta @@ -6375,10 +6312,7 @@ export function euclideanDistance(expr: string, other: Expr): FirestoreFunction; * @param other The other vector (as an array of doubles) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ -export function euclideanDistance( - expr: Expr, - other: number[] -): FirestoreFunction; +export function euclideanDistance(expr: Expr, other: number[]): FunctionExpr; /** * @beta @@ -6394,10 +6328,7 @@ export function euclideanDistance( * @param other The other vector (as a VectorValue) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ -export function euclideanDistance( - expr: Expr, - other: VectorValue -): FirestoreFunction; +export function euclideanDistance(expr: Expr, other: VectorValue): FunctionExpr; /** * @beta @@ -6413,11 +6344,11 @@ export function euclideanDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ -export function euclideanDistance(expr: Expr, other: Expr): FirestoreFunction; +export function euclideanDistance(expr: Expr, other: Expr): FunctionExpr; export function euclideanDistance( expr: Expr | string, other: Expr | number[] | VectorValue -): FirestoreFunction { +): FunctionExpr { const expr1 = fieldOfOrExpr(expr); const expr2 = vectorToExpr(other); return expr1.euclideanDistance(expr2); @@ -6437,10 +6368,7 @@ export function euclideanDistance( * @param other The other vector (as an array of doubles) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ -export function manhattanDistance( - field: string, - other: number[] -): FirestoreFunction; +export function manhattanDistance(field: string, other: number[]): FunctionExpr; /** * @beta @@ -6459,7 +6387,7 @@ export function manhattanDistance( export function manhattanDistance( expr: string, other: VectorValue -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -6475,7 +6403,7 @@ export function manhattanDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ -export function manhattanDistance(expr: string, other: Expr): FirestoreFunction; +export function manhattanDistance(expr: string, other: Expr): FunctionExpr; /** * @beta @@ -6492,10 +6420,7 @@ export function manhattanDistance(expr: string, other: Expr): FirestoreFunction; * @param other The other vector (as an array of doubles) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ -export function manhattanDistance( - expr: Expr, - other: number[] -): FirestoreFunction; +export function manhattanDistance(expr: Expr, other: number[]): FunctionExpr; /** * @beta @@ -6511,10 +6436,7 @@ export function manhattanDistance( * @param other The other vector (as a VectorValue) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ -export function manhattanDistance( - expr: Expr, - other: VectorValue -): FirestoreFunction; +export function manhattanDistance(expr: Expr, other: VectorValue): FunctionExpr; /** * @beta @@ -6530,11 +6452,11 @@ export function manhattanDistance( * @param other The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ -export function manhattanDistance(expr: Expr, other: Expr): FirestoreFunction; +export function manhattanDistance(expr: Expr, other: Expr): FunctionExpr; export function manhattanDistance( fieldOrExpr: Expr | string, other: Expr | number[] | VectorValue -): FirestoreFunction { +): FunctionExpr { const expr1 = fieldOfOrExpr(fieldOrExpr); const expr2 = vectorToExpr(other); return expr1.manhattanDistance(expr2); @@ -6553,7 +6475,7 @@ export function manhattanDistance( * @param expr The expression representing the Firestore Vector. * @return A new {@code Expr} representing the length of the array. */ -export function vectorLength(expr: Expr): FirestoreFunction; +export function vectorLength(expr: Expr): FunctionExpr; /** * @beta @@ -6568,8 +6490,8 @@ export function vectorLength(expr: Expr): FirestoreFunction; * @param field The name of the field representing the Firestore Vector. * @return A new {@code Expr} representing the length of the array. */ -export function vectorLength(field: string): FirestoreFunction; -export function vectorLength(expr: Expr | string): FirestoreFunction { +export function vectorLength(field: string): FunctionExpr; +export function vectorLength(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).vectorLength(); } @@ -6587,7 +6509,7 @@ export function vectorLength(expr: Expr | string): FirestoreFunction { * @param expr The expression representing the number of microseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMicrosToTimestamp(expr: Expr): FirestoreFunction; +export function unixMicrosToTimestamp(expr: Expr): FunctionExpr; /** * @beta @@ -6603,8 +6525,8 @@ export function unixMicrosToTimestamp(expr: Expr): FirestoreFunction; * @param field The name of the field representing the number of microseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMicrosToTimestamp(field: string): FirestoreFunction; -export function unixMicrosToTimestamp(expr: Expr | string): FirestoreFunction { +export function unixMicrosToTimestamp(field: string): FunctionExpr; +export function unixMicrosToTimestamp(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).unixMicrosToTimestamp(); } @@ -6621,7 +6543,7 @@ export function unixMicrosToTimestamp(expr: Expr | string): FirestoreFunction { * @param expr The expression representing the timestamp. * @return A new {@code Expr} representing the number of microseconds since epoch. */ -export function timestampToUnixMicros(expr: Expr): FirestoreFunction; +export function timestampToUnixMicros(expr: Expr): FunctionExpr; /** * @beta @@ -6636,8 +6558,8 @@ export function timestampToUnixMicros(expr: Expr): FirestoreFunction; * @param field The name of the field representing the timestamp. * @return A new {@code Expr} representing the number of microseconds since epoch. */ -export function timestampToUnixMicros(field: string): FirestoreFunction; -export function timestampToUnixMicros(expr: Expr | string): FirestoreFunction { +export function timestampToUnixMicros(field: string): FunctionExpr; +export function timestampToUnixMicros(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).timestampToUnixMicros(); } @@ -6655,7 +6577,7 @@ export function timestampToUnixMicros(expr: Expr | string): FirestoreFunction { * @param expr The expression representing the number of milliseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMillisToTimestamp(expr: Expr): FirestoreFunction; +export function unixMillisToTimestamp(expr: Expr): FunctionExpr; /** * @beta @@ -6671,8 +6593,8 @@ export function unixMillisToTimestamp(expr: Expr): FirestoreFunction; * @param field The name of the field representing the number of milliseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMillisToTimestamp(field: string): FirestoreFunction; -export function unixMillisToTimestamp(expr: Expr | string): FirestoreFunction { +export function unixMillisToTimestamp(field: string): FunctionExpr; +export function unixMillisToTimestamp(expr: Expr | string): FunctionExpr { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.unixMillisToTimestamp(); } @@ -6690,7 +6612,7 @@ export function unixMillisToTimestamp(expr: Expr | string): FirestoreFunction { * @param expr The expression representing the timestamp. * @return A new {@code Expr} representing the number of milliseconds since epoch. */ -export function timestampToUnixMillis(expr: Expr): FirestoreFunction; +export function timestampToUnixMillis(expr: Expr): FunctionExpr; /** * @beta @@ -6705,8 +6627,8 @@ export function timestampToUnixMillis(expr: Expr): FirestoreFunction; * @param field The name of the field representing the timestamp. * @return A new {@code Expr} representing the number of milliseconds since epoch. */ -export function timestampToUnixMillis(field: string): FirestoreFunction; -export function timestampToUnixMillis(expr: Expr | string): FirestoreFunction { +export function timestampToUnixMillis(field: string): FunctionExpr; +export function timestampToUnixMillis(expr: Expr | string): FunctionExpr { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.timestampToUnixMillis(); } @@ -6725,7 +6647,7 @@ export function timestampToUnixMillis(expr: Expr | string): FirestoreFunction { * @param expr The expression representing the number of seconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixSecondsToTimestamp(expr: Expr): FirestoreFunction; +export function unixSecondsToTimestamp(expr: Expr): FunctionExpr; /** * @beta @@ -6741,8 +6663,8 @@ export function unixSecondsToTimestamp(expr: Expr): FirestoreFunction; * @param field The name of the field representing the number of seconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixSecondsToTimestamp(field: string): FirestoreFunction; -export function unixSecondsToTimestamp(expr: Expr | string): FirestoreFunction { +export function unixSecondsToTimestamp(field: string): FunctionExpr; +export function unixSecondsToTimestamp(expr: Expr | string): FunctionExpr { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.unixSecondsToTimestamp(); } @@ -6760,7 +6682,7 @@ export function unixSecondsToTimestamp(expr: Expr | string): FirestoreFunction { * @param expr The expression representing the timestamp. * @return A new {@code Expr} representing the number of seconds since epoch. */ -export function timestampToUnixSeconds(expr: Expr): FirestoreFunction; +export function timestampToUnixSeconds(expr: Expr): FunctionExpr; /** * @beta @@ -6775,8 +6697,8 @@ export function timestampToUnixSeconds(expr: Expr): FirestoreFunction; * @param field The name of the field representing the timestamp. * @return A new {@code Expr} representing the number of seconds since epoch. */ -export function timestampToUnixSeconds(field: string): FirestoreFunction; -export function timestampToUnixSeconds(expr: Expr | string): FirestoreFunction { +export function timestampToUnixSeconds(field: string): FunctionExpr; +export function timestampToUnixSeconds(expr: Expr | string): FunctionExpr { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.timestampToUnixSeconds(); } @@ -6800,7 +6722,7 @@ export function timestampAdd( timestamp: Expr, unit: Expr, amount: Expr -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -6821,7 +6743,7 @@ export function timestampAdd( timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -6842,7 +6764,7 @@ export function timestampAdd( field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number -): FirestoreFunction; +): FunctionExpr; export function timestampAdd( timestamp: Expr | string, unit: @@ -6854,7 +6776,7 @@ export function timestampAdd( | 'hour' | 'day', amount: Expr | number -): FirestoreFunction { +): FunctionExpr { const normalizedTimestamp = fieldOfOrExpr(timestamp); const normalizedUnit = valueToDefaultExpr(unit); const normalizedAmount = valueToDefaultExpr(amount); @@ -6880,7 +6802,7 @@ export function timestampSub( timestamp: Expr, unit: Expr, amount: Expr -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -6901,7 +6823,7 @@ export function timestampSub( timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number -): FirestoreFunction; +): FunctionExpr; /** * @beta @@ -6922,7 +6844,7 @@ export function timestampSub( field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number -): FirestoreFunction; +): FunctionExpr; export function timestampSub( timestamp: Expr | string, unit: @@ -6934,7 +6856,7 @@ export function timestampSub( | 'hour' | 'day', amount: Expr | number -): FirestoreFunction { +): FunctionExpr { const normalizedTimestamp = fieldOfOrExpr(timestamp); const normalizedUnit = valueToDefaultExpr(unit); const normalizedAmount = valueToDefaultExpr(amount); @@ -6958,8 +6880,8 @@ export function timestampSub( export function genericFunction( functionName: string, params: any[] -): FirestoreFunction { - return new FirestoreFunction(functionName, params.map(valueToDefaultExpr)); +): FunctionExpr { + return new FunctionExpr(functionName, params.map(valueToDefaultExpr)); } /** diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index 7ea14328387..3bdbcb00d53 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -29,7 +29,7 @@ import { Firestore } from './database'; import { _mapValue, AggregateFunction, - AggregateFunctionWithAlias, + AggregateWithAlias, Constant, Expr, ExprWithAlias, @@ -162,13 +162,17 @@ export class Pipeline implements ProtoSerializable { * ); * ``` * - * @param fields The fields to add to the documents, specified as {@link Selectable}s. + * @param field The first field to add to the documents, specified as a {@link Selectable}. + * @param additionalFields Optional additional fields to add to the documents, specified as {@link Selectable}s. * @return A new Pipeline object with this stage appended to the stage list. */ - addFields(...fields: Selectable[]): Pipeline { + addFields(field: Selectable, ...additionalFields: Selectable[]): Pipeline { return this._addStage( new AddFields( - this.readUserData('addFields', this.selectablesToMap(fields)) + this.readUserData( + 'addFields', + this.selectablesToMap([field, ...additionalFields]) + ) ) ); } @@ -187,11 +191,15 @@ export class Pipeline implements ProtoSerializable { * ); * ``` * - * @param fields The fields to remove. + * @param field The first field to remove. + * @param additionalFields Optional additional fields to remove. * @return A new Pipeline object with this stage appended to the stage list. */ - removeFields(...fields: Array): Pipeline { - const fieldExpressions = fields.map(f => + removeFields( + field: Field | string, + ...additionalFields: Array + ): Pipeline { + const fieldExpressions = [field, ...additionalFields].map(f => typeof f === 'string' ? Field.of(f) : (f as Field) ); this.readUserData('removeFields', fieldExpressions); @@ -211,7 +219,7 @@ export class Pipeline implements ProtoSerializable { * * *

    If no selections are provided, the output of this stage is empty. Use {@link - * com.google.cloud.firestore.Pipeline#addFields} instead if only additions are + * Pipeline#addFields} instead if only additions are * desired. * *

    Example: @@ -225,12 +233,20 @@ export class Pipeline implements ProtoSerializable { * ); * ``` * - * @param selections The fields to include in the output documents, specified as {@link + * @param selection The first field to include in the output documents, specified as {@link + * Selectable} expression or string value representing the field name. + * @param additionalSelections Optional additional fields to include in the output documents, specified as {@link * Selectable} expressions or {@code string} values representing field names. * @return A new Pipeline object with this stage appended to the stage list. */ - select(...selections: Array): Pipeline { - let projections: Map = this.selectablesToMap(selections); + select( + selection: Selectable | string, + ...additionalSelections: Array + ): Pipeline { + let projections: Map = this.selectablesToMap([ + selection, + ...additionalSelections + ]); projections = this.readUserData('select', projections); return this._addStage(new Select(projections)); } @@ -362,14 +378,22 @@ export class Pipeline implements ProtoSerializable { * .select("authorName"); * ``` * - * @param groups The {@link Selectable} expressions to consider when determining distinct - * value combinations or {@code string}s representing field names. + * @param group The first {@link Selectable} expression to consider when determining distinct + * value combinations or strings representing field names. + * @param additionalGroups Optional additional {@link Selectable} expressions to consider when determining distinct + * value combinations or strings representing field names. * @return A new {@code Pipeline} object with this stage appended to the stage list. */ - distinct(...groups: Array): Pipeline { + distinct( + group: string | Selectable, + ...additionalGroups: Array + ): Pipeline { return this._addStage( new Distinct( - this.readUserData('distinct', this.selectablesToMap(groups || [])) + this.readUserData( + 'distinct', + this.selectablesToMap([group, ...additionalGroups]) + ) ) ); } @@ -378,7 +402,7 @@ export class Pipeline implements ProtoSerializable { * Performs aggregation operations on the documents from previous stages. * *

    This stage allows you to calculate aggregate values over a set of documents. You define the - * aggregations to perform using {@link AggregateFunctionWithAlias} expressions which are typically results of + * aggregations to perform using {@link AggregateWithAlias} expressions which are typically results of * calling {@link Expr#as} on {@link AggregateFunction} instances. * *

    Example: @@ -392,11 +416,16 @@ export class Pipeline implements ProtoSerializable { * ); * ``` * - * @param accumulators The {@link AggregateFunctionWithAlias} expressions, each wrapping an {@link AggregateFunction} + * @param accumulator The first {@link AggregateWithAlias}, wrapping an {@link AggregateFunction} + * and provide a name for the accumulated results. + * @param additionalAccumulators Optional additional {@link AggregateWithAlias}, each wrapping an {@link AggregateFunction} * and provide a name for the accumulated results. * @return A new Pipeline object with this stage appended to the stage list. */ - aggregate(...accumulators: AggregateFunctionWithAlias[]): Pipeline; + aggregate( + accumulator: AggregateWithAlias, + ...additionalAccumulators: AggregateWithAlias[] + ): Pipeline; /** * Performs optionally grouped aggregation operations on the documents from previous stages. * @@ -409,7 +438,7 @@ export class Pipeline implements ProtoSerializable { * If no grouping fields are provided, a single group containing all documents is used. Not * specifying groups is the same as putting the entire inputs into one group. *

  • **Accumulators:** One or more accumulation operations to perform within each group. These - * are defined using {@link AggregateFunctionWithAlias} expressions, which are typically created by + * are defined using {@link AggregateWithAlias} expressions, which are typically created by * calling {@link Expr#as} on {@link AggregateFunction} instances. Each aggregation * calculates a value (e.g., sum, average, count) based on the documents within its group.
  • * @@ -431,31 +460,29 @@ export class Pipeline implements ProtoSerializable { * list. */ aggregate(options: { - accumulators: AggregateFunctionWithAlias[]; + accumulators: AggregateWithAlias[]; groups?: Array; }): Pipeline; aggregate( optionsOrTarget: - | AggregateFunctionWithAlias + | AggregateWithAlias | { - accumulators: AggregateFunctionWithAlias[]; + accumulators: AggregateWithAlias[]; groups?: Array; }, - ...rest: AggregateFunctionWithAlias[] + ...rest: AggregateWithAlias[] ): Pipeline { if ('accumulators' in optionsOrTarget) { return this._addStage( new Aggregate( new Map( - optionsOrTarget.accumulators.map( - (target: AggregateFunctionWithAlias) => [ - (target as unknown as AggregateFunctionWithAlias).alias, - this.readUserData( - 'aggregate', - (target as unknown as AggregateFunctionWithAlias).expr - ) - ] - ) + optionsOrTarget.accumulators.map((target: AggregateWithAlias) => [ + (target as unknown as AggregateWithAlias).alias, + this.readUserData( + 'aggregate', + (target as unknown as AggregateWithAlias).aggregate + ) + ]) ), this.readUserData( 'aggregate', @@ -468,10 +495,10 @@ export class Pipeline implements ProtoSerializable { new Aggregate( new Map( [optionsOrTarget, ...rest].map(target => [ - (target as unknown as AggregateFunctionWithAlias).alias, + (target as unknown as AggregateWithAlias).alias, this.readUserData( 'aggregate', - (target as unknown as AggregateFunctionWithAlias).expr + (target as unknown as AggregateWithAlias).aggregate ) ]) ), @@ -520,10 +547,11 @@ export class Pipeline implements ProtoSerializable { * ); * ``` * - * @param orderings One or more {@link Ordering} instances specifying the sorting criteria. + * @param ordering The first {@link Ordering} instance specifying the sorting criteria. + * @param additionalOrderings Optional additional {@link Ordering} instances specifying the additional sorting criteria. * @return A new {@code Pipeline} object with this stage appended to the stage list. */ - sort(...orderings: Ordering[]): Pipeline; + sort(ordering: Ordering, ...additionalOrderings: Ordering[]): Pipeline; sort( optionsOrOrderings: | Ordering @@ -533,7 +561,7 @@ export class Pipeline implements ProtoSerializable { ...rest: Ordering[] ): Pipeline { // Option object - if ('orderings' in optionsOrOrderings) { + if (optionsOrOrderings && 'orderings' in optionsOrOrderings) { return this._addStage( new Sort( this.readUserData( From 4e339ee8302740966074b698c0b02c808c1bdeb2 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 28 Feb 2025 14:02:08 -0700 Subject: [PATCH 42/75] missing readonly --- packages/firestore/src/lite-api/expressions.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index e5ee87f0e6b..f289ace38f5 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -131,7 +131,7 @@ function fieldOfOrExpr(value: any): Expr { * method calls to create complex expressions. */ export abstract class Expr implements ProtoValueSerializable, UserData { - abstract exprType: ExprType; + abstract readonly exprType: ExprType; /** * @private @@ -2218,7 +2218,7 @@ class ListOfExprs extends Expr { * ``` */ export class Field extends Expr implements Selectable { - exprType: ExprType = 'Field'; + readonly exprType: ExprType = 'Field'; selectable = true as const; private constructor(private fieldPath: InternalFieldPath) { @@ -2303,7 +2303,7 @@ export class Field extends Expr implements Selectable { * ``` */ export class Constant extends Expr { - exprType: ExprType = 'Constant'; + readonly exprType: ExprType = 'Constant'; private _protoValue?: ProtoValue; @@ -2526,7 +2526,7 @@ export class MapValue extends Expr { * or the methods on {@link Expr} ({@link Expr#eq}, {@link Expr#lt}, etc) to construct new Function instances. */ export class FunctionExpr extends Expr { - exprType: ExprType = 'Function'; + readonly exprType: ExprType = 'Function'; constructor(private name: string, private params: Expr[]) { super(); From b303ec5a386990d03fa0a8773bfbb2536ad6e834 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 28 Feb 2025 14:02:39 -0700 Subject: [PATCH 43/75] Build and test fixes --- packages/firestore/src/remote/serializer.ts | 2 +- .../test/integration/api/pipeline.test.ts | 43 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/packages/firestore/src/remote/serializer.ts b/packages/firestore/src/remote/serializer.ts index e0688db9d90..095e377eba6 100644 --- a/packages/firestore/src/remote/serializer.ts +++ b/packages/firestore/src/remote/serializer.ts @@ -1439,8 +1439,8 @@ export interface ProtoValueSerializable extends ProtoSerializable { _protoValueType: 'ProtoValue'; } -// eslint-disable-next-line @typescript-eslint/no-explicit-any export function isProtoValueSerializable( + // eslint-disable-next-line @typescript-eslint/no-explicit-any value: any ): value is ProtoValueSerializable { return ( diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 66a8628805e..e9e62985c1a 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -480,7 +480,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .limit(1) - .select(...constants) + .select(constants[0], ...constants.slice(1)) ); expectResults(snapshots, { @@ -751,6 +751,47 @@ apiDescribe.only('Pipelines', persistence => { }); }); + describe('removeFields stage', () => { + it('can remove fields', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .sort(Field.of('author').ascending()) + .removeFields(Field.of('author')) + .sort(Field.of('author').ascending()) + ); + expectResults( + snapshot, + { + title: "The Hitchhiker's Guide to the Galaxy" + }, + { + title: 'The Great Gatsby' + }, + { title: 'Dune' }, + { + title: 'Crime and Punishment' + }, + { + title: 'One Hundred Years of Solitude' + }, + { title: '1984' }, + { + title: 'To Kill a Mockingbird' + }, + { + title: 'The Lord of the Rings' + }, + { title: 'Pride and Prejudice' }, + { + title: "The Handmaid's Tale" + } + ); + }); + }); + describe('where stage', () => { it('where with and', async () => { const snapshot = await execute( From 67f15fbe1d6ead4cbba7ee140d16e48b20ecb6f2 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 28 Feb 2025 15:08:15 -0700 Subject: [PATCH 44/75] Replace Field.of() with field() --- .../firestore/lite/pipelines/pipelines.ts | 3 +- packages/firestore/src/api/pipeline_impl.ts | 2 +- packages/firestore/src/api_pipelines.ts | 1 + packages/firestore/src/core/pipeline-util.ts | 122 ++-- .../firestore/src/lite-api/expressions.ts | 646 +++++++++--------- packages/firestore/src/lite-api/pipeline.ts | 62 +- .../firestore/src/lite-api/pipeline_impl.ts | 2 +- packages/firestore/src/lite-api/stage.ts | 7 +- .../test/integration/api/pipeline.test.ts | 250 ++++--- .../integration/api/query_to_pipeline.test.ts | 2 +- 10 files changed, 554 insertions(+), 543 deletions(-) diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index 197be8f7604..a3b6358d4d4 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -54,7 +54,7 @@ export { PipelineResult } from '../../src/lite-api/pipeline-result'; export { Pipeline } from '../../src/lite-api/pipeline'; -export { pipeline, execute } from '../../src/lite-api/pipeline_impl'; +export { execute } from '../../src/lite-api/pipeline_impl'; export { Stage, @@ -76,6 +76,7 @@ export { } from '../../src/lite-api/stage'; export { + field, add, subtract, multiply, diff --git a/packages/firestore/src/api/pipeline_impl.ts b/packages/firestore/src/api/pipeline_impl.ts index 77bfaf5cf6b..8650140a444 100644 --- a/packages/firestore/src/api/pipeline_impl.ts +++ b/packages/firestore/src/api/pipeline_impl.ts @@ -59,7 +59,7 @@ declare module './database' { * * ```typescript * const futureResults = await execute(firestore.pipeline().collection("books") - * .where(gt(Field.of("rating"), 4.5)) + * .where(gt(field("rating"), 4.5)) * .select("title", "author", "rating")); * ``` * diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index 8619d730491..ec189c09b1c 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -43,6 +43,7 @@ export { } from './lite-api/stage'; export { + field, add, subtract, multiply, diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index 20d9ab9373c..933809e0957 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -27,7 +27,8 @@ import { gt, lte, gte, - eq + eq, + field } from '../lite-api/expressions'; import { Pipeline } from '../lite-api/pipeline'; import { doc } from '../lite-api/reference'; @@ -55,18 +56,18 @@ import { export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { if (f instanceof FieldFilterInternal) { - const field = Field.of(f.field.toString()); + const fieldValue = field(f.field.toString()); if (isNanValue(f.value)) { if (f.op === Operator.EQUAL) { - return andFunction(field.exists(), field.isNan()); + return andFunction(fieldValue.exists(), fieldValue.isNan()); } else { - return andFunction(field.exists(), field.isNotNan()); + return andFunction(fieldValue.exists(), fieldValue.isNotNan()); } } else if (isNullValue(f.value)) { if (f.op === Operator.EQUAL) { - return andFunction(field.exists(), field.eq(null)); + return andFunction(fieldValue.exists(), fieldValue.eq(null)); } else { - return andFunction(field.exists(), field.neq(null)); + return andFunction(fieldValue.exists(), fieldValue.neq(null)); } } else { // Comparison filters @@ -74,56 +75,62 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { switch (f.op) { case Operator.LESS_THAN: return andFunction( - field.exists(), - field.lt(Constant._fromProto(value)) + fieldValue.exists(), + fieldValue.lt(Constant._fromProto(value)) ); case Operator.LESS_THAN_OR_EQUAL: return andFunction( - field.exists(), - field.lte(Constant._fromProto(value)) + fieldValue.exists(), + fieldValue.lte(Constant._fromProto(value)) ); case Operator.GREATER_THAN: return andFunction( - field.exists(), - field.gt(Constant._fromProto(value)) + fieldValue.exists(), + fieldValue.gt(Constant._fromProto(value)) ); case Operator.GREATER_THAN_OR_EQUAL: return andFunction( - field.exists(), - field.gte(Constant._fromProto(value)) + fieldValue.exists(), + fieldValue.gte(Constant._fromProto(value)) ); case Operator.EQUAL: return andFunction( - field.exists(), - field.eq(Constant._fromProto(value)) + fieldValue.exists(), + fieldValue.eq(Constant._fromProto(value)) ); case Operator.NOT_EQUAL: return andFunction( - field.exists(), - field.neq(Constant._fromProto(value)) + fieldValue.exists(), + fieldValue.neq(Constant._fromProto(value)) ); case Operator.ARRAY_CONTAINS: return andFunction( - field.exists(), - field.arrayContains(Constant._fromProto(value)) + fieldValue.exists(), + fieldValue.arrayContains(Constant._fromProto(value)) ); case Operator.IN: { const values = value?.arrayValue?.values?.map((val: any) => Constant._fromProto(val) ); - return andFunction(field.exists(), field.eqAny(...values!)); + return andFunction(fieldValue.exists(), fieldValue.eqAny(...values!)); } case Operator.ARRAY_CONTAINS_ANY: { const values = value?.arrayValue?.values?.map((val: any) => Constant._fromProto(val) ); - return andFunction(field.exists(), field.arrayContainsAny(values!)); + return andFunction( + fieldValue.exists(), + fieldValue.arrayContainsAny(values!) + ); } case Operator.NOT_IN: { const values = value?.arrayValue?.values?.map((val: any) => Constant._fromProto(val) ); - return andFunction(field.exists(), field.notEqAny(...values!)); + return andFunction( + fieldValue.exists(), + fieldValue.notEqAny(...values!) + ); } default: fail('Unexpected operator'); @@ -179,7 +186,7 @@ export function toPipeline(query: Query, db: Firestore): Pipeline { // orders const orders = queryNormalizedOrderBy(query); const existsConditions = orders.map(order => - Field.of(order.field.canonicalString()).exists() + field(order.field.canonicalString()).exists() ); if (existsConditions.length > 1) { pipeline = pipeline.where( @@ -195,42 +202,45 @@ export function toPipeline(query: Query, db: Firestore): Pipeline { const orderings = orders.map(order => order.dir === Direction.ASCENDING - ? Field.of(order.field.canonicalString()).ascending() - : Field.of(order.field.canonicalString()).descending() + ? field(order.field.canonicalString()).ascending() + : field(order.field.canonicalString()).descending() ); - if (query.limitType === LimitType.Last) { - pipeline = pipeline.sort(...reverseOrderings(orderings)); - // cursors - if (query.startAt !== null) { - pipeline = pipeline.where( - whereConditionsFromCursor(query.startAt, orderings, 'before') - ); - } + if (orderings.length > 0) { + if (query.limitType === LimitType.Last) { + const actualOrderings = reverseOrderings(orderings); + pipeline = pipeline.sort(actualOrderings[0], ...actualOrderings.slice(1)); + // cursors + if (query.startAt !== null) { + pipeline = pipeline.where( + whereConditionsFromCursor(query.startAt, orderings, 'before') + ); + } - if (query.endAt !== null) { - pipeline = pipeline.where( - whereConditionsFromCursor(query.endAt, orderings, 'after') - ); - } + if (query.endAt !== null) { + pipeline = pipeline.where( + whereConditionsFromCursor(query.endAt, orderings, 'after') + ); + } - pipeline = pipeline._limit(query.limit!, true); - pipeline = pipeline.sort(...orderings); - } else { - pipeline = pipeline.sort(...orderings); - if (query.startAt !== null) { - pipeline = pipeline.where( - whereConditionsFromCursor(query.startAt, orderings, 'after') - ); - } - if (query.endAt !== null) { - pipeline = pipeline.where( - whereConditionsFromCursor(query.endAt, orderings, 'before') - ); - } + pipeline = pipeline._limit(query.limit!, true); + pipeline = pipeline.sort(orderings[0], ...orderings.slice(1)); + } else { + pipeline = pipeline.sort(orderings[0], ...orderings.slice(1)); + if (query.startAt !== null) { + pipeline = pipeline.where( + whereConditionsFromCursor(query.startAt, orderings, 'after') + ); + } + if (query.endAt !== null) { + pipeline = pipeline.where( + whereConditionsFromCursor(query.endAt, orderings, 'before') + ); + } - if (query.limit !== null) { - pipeline = pipeline.limit(query.limit); + if (query.limit !== null) { + pipeline = pipeline.limit(query.limit); + } } } @@ -253,7 +263,7 @@ function whereConditionsFromCursor( const conditions: BooleanExpr[] = cursorSubset.map((cursor, index) => { if (index < cursorSubset.length - 1) { return eq(orderings[index].expr as Field, cursor); - } else if (!!bound.inclusive && i === orderings.length) { + } else if (bound.inclusive && i === orderings.length) { return filterInclusiveFunc(orderings[index].expr as Field, cursor); } else { return filterFunc(orderings[index].expr as Field, cursor); diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index f289ace38f5..ee283b9d511 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -100,7 +100,7 @@ function vectorToExpr(value: VectorValue | number[] | Expr): Expr { * Converts a value to an Expr, Returning either a Constant, MapFunction, * ArrayFunction, or the input itself (if it's already an expression). * If the input is a string, it is assumed to be a field name, and a - * Field.of(value) is returned. + * field(value) is returned. * * @private * @internal @@ -108,7 +108,7 @@ function vectorToExpr(value: VectorValue | number[] | Expr): Expr { */ function fieldOfOrExpr(value: any): Expr { if (isString(value)) { - return Field.of(value); + return field(value); } else { return valueToDefaultExpr(value); } @@ -151,7 +151,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Add the value of the 'quantity' field and the 'reserve' field. - * Field.of("quantity").add(Field.of("reserve")); + * field("quantity").add(field("reserve")); * ``` * * @param second The expression or literal to add to this expression. @@ -171,7 +171,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Subtract the 'discount' field from the 'price' field - * Field.of("price").subtract(Field.of("discount")); + * field("price").subtract(field("discount")); * ``` * * @param other The expression to subtract from this expression. @@ -184,7 +184,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Subtract 20 from the value of the 'total' field - * Field.of("total").subtract(20); + * field("total").subtract(20); * ``` * * @param other The constant value to subtract. @@ -200,7 +200,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Multiply the 'quantity' field by the 'price' field - * Field.of("quantity").multiply(Field.of("price")); + * field("quantity").multiply(field("price")); * ``` * * @param second The second expression or literal to multiply by. @@ -220,7 +220,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Divide the 'total' field by the 'count' field - * Field.of("total").divide(Field.of("count")); + * field("total").divide(field("count")); * ``` * * @param other The expression to divide by. @@ -233,7 +233,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Divide the 'value' field by 10 - * Field.of("value").divide(10); + * field("value").divide(10); * ``` * * @param other The constant value to divide by. @@ -249,7 +249,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the remainder of dividing the 'value' field by the 'divisor' field - * Field.of("value").mod(Field.of("divisor")); + * field("value").mod(field("divisor")); * ``` * * @param other The expression to divide by. @@ -262,7 +262,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the remainder of dividing the 'value' field by 10 - * Field.of("value").mod(10); + * field("value").mod(10); * ``` * * @param other The constant value to divide by. @@ -278,7 +278,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'age' field is equal to 21 - * Field.of("age").eq(21); + * field("age").eq(21); * ``` * * @param other The expression to compare for equality. @@ -291,7 +291,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'city' field is equal to "London" - * Field.of("city").eq("London"); + * field("city").eq("London"); * ``` * * @param other The constant value to compare for equality. @@ -307,7 +307,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'status' field is not equal to "completed" - * Field.of("status").neq("completed"); + * field("status").neq("completed"); * ``` * * @param other The expression to compare for inequality. @@ -320,7 +320,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'country' field is not equal to "USA" - * Field.of("country").neq("USA"); + * field("country").neq("USA"); * ``` * * @param other The constant value to compare for inequality. @@ -336,7 +336,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'age' field is less than 'limit' - * Field.of("age").lt(Field.of('limit')); + * field("age").lt(field('limit')); * ``` * * @param other The expression to compare for less than. @@ -349,7 +349,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'price' field is less than 50 - * Field.of("price").lt(50); + * field("price").lt(50); * ``` * * @param other The constant value to compare for less than. @@ -366,7 +366,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'quantity' field is less than or equal to 20 - * Field.of("quantity").lte(Constant.of(20)); + * field("quantity").lte(Constant.of(20)); * ``` * * @param other The expression to compare for less than or equal to. @@ -379,7 +379,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'score' field is less than or equal to 70 - * Field.of("score").lte(70); + * field("score").lte(70); * ``` * * @param other The constant value to compare for less than or equal to. @@ -395,7 +395,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'age' field is greater than the 'limit' field - * Field.of("age").gt(Field.of("limit")); + * field("age").gt(field("limit")); * ``` * * @param other The expression to compare for greater than. @@ -408,7 +408,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'price' field is greater than 100 - * Field.of("price").gt(100); + * field("price").gt(100); * ``` * * @param other The constant value to compare for greater than. @@ -425,7 +425,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'quantity' field is greater than or equal to field 'requirement' plus 1 - * Field.of("quantity").gte(Field.of('requirement').add(1)); + * field("quantity").gte(field('requirement').add(1)); * ``` * * @param other The expression to compare for greater than or equal to. @@ -439,7 +439,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'score' field is greater than or equal to 80 - * Field.of("score").gte(80); + * field("score").gte(80); * ``` * * @param other The constant value to compare for greater than or equal to. @@ -455,7 +455,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Combine the 'items' array with another array field. - * Field.of("items").arrayConcat(Field.of("otherItems")); + * field("items").arrayConcat(field("otherItems")); * ``` * @param secondArray Second array expression or array literal to concatenate. * @param otherArrays Optional additional array expressions or array literals to concatenate. @@ -475,7 +475,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'sizes' array contains the value from the 'selectedSize' field - * Field.of("sizes").arrayContains(Field.of("selectedSize")); + * field("sizes").arrayContains(field("selectedSize")); * ``` * * @param element The element to search for in the array. @@ -488,7 +488,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'colors' array contains "red" - * Field.of("colors").arrayContains("red"); + * field("colors").arrayContains("red"); * ``` * * @param element The element to search for in the array. @@ -507,7 +507,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'tags' array contains both "news" and "sports" - * Field.of("tags").arrayContainsAll(Field.of("tag1"), Field.of("tag2")); + * field("tags").arrayContainsAll(field("tag1"), field("tag2")); * ``` * * @param values The elements to check for in the array. @@ -520,7 +520,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'tags' array contains both of the values from field 'tag1' and "tag2" - * Field.of("tags").arrayContainsAll(Field.of("tag1"), Field.of("tag2")); + * field("tags").arrayContainsAll(field("tag1"), field("tag2")); * ``` * * @param values The elements to check for in the array. @@ -540,7 +540,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'categories' array contains either values from field "cate1" or "cate2" - * Field.of("categories").arrayContainsAny(Field.of("cate1"), Field.of("cate2")); + * field("categories").arrayContainsAny(field("cate1"), field("cate2")); * ``` * * @param values The elements to check for in the array. @@ -554,7 +554,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * ```typescript * // Check if the 'groups' array contains either the value from the 'userGroup' field * // or the value "guest" - * Field.of("groups").arrayContainsAny(Field.of("userGroup"), "guest"); + * field("groups").arrayContainsAny(field("userGroup"), "guest"); * ``` * * @param values The elements to check for in the array. @@ -574,7 +574,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Get the number of items in the 'cart' array - * Field.of("cart").arrayLength(); + * field("cart").arrayLength(); * ``` * * @return A new `Expr` representing the length of the array. @@ -589,7 +589,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'category' field is either "Electronics" or value of field 'primaryType' - * Field.of("category").eqAny("Electronics", Field.of("primaryType")); + * field("category").eqAny("Electronics", field("primaryType")); * ``` * * @param others The values or expressions to check against. @@ -603,7 +603,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'category' field is either "Electronics" or value of field 'primaryType' - * Field.of("category").eqAny("Electronics", Field.of("primaryType")); + * field("category").eqAny("Electronics", field("primaryType")); * ``` * * @param others The values or expressions to check against. @@ -621,7 +621,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * Field.of("status").notEqAny("pending", Field.of("rejectedStatus")); + * field("status").notEqAny("pending", field("rejectedStatus")); * ``` * * @param others The values or expressions to check against. @@ -635,7 +635,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * Field.of("status").notEqAny("pending", Field.of("rejectedStatus")); + * field("status").notEqAny("pending", field("rejectedStatus")); * ``` * * @param others The values or expressions to check against. @@ -652,7 +652,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the result of a calculation is NaN - * Field.of("value").divide(0).isNaN(); + * field("value").divide(0).isNaN(); * ``` * * @return A new `Expr` representing the 'isNaN' check. @@ -666,7 +666,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the result of a calculation is NaN - * Field.of("value").isNull(); + * field("value").isNull(); * ``` * * @return A new `Expr` representing the 'isNull' check. @@ -680,7 +680,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the document has a field named "phoneNumber" - * Field.of("phoneNumber").exists(); + * field("phoneNumber").exists(); * ``` * * @return A new `Expr` representing the 'exists' check. @@ -694,7 +694,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Get the character length of the 'name' field in its UTF-8 form. - * Field.of("name").charLength(); + * field("name").charLength(); * ``` * * @return A new `Expr` representing the length of the string. @@ -708,7 +708,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'title' field contains the word "guide" (case-sensitive) - * Field.of("title").like("%guide%"); + * field("title").like("%guide%"); * ``` * * @param pattern The pattern to search for. You can use "%" as a wildcard character. @@ -721,7 +721,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'title' field contains the word "guide" (case-sensitive) - * Field.of("title").like("%guide%"); + * field("title").like("%guide%"); * ``` * * @param pattern The pattern to search for. You can use "%" as a wildcard character. @@ -738,7 +738,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'description' field contains "example" (case-insensitive) - * Field.of("description").regexContains("(?i)example"); + * field("description").regexContains("(?i)example"); * ``` * * @param pattern The regular expression to use for the search. @@ -752,7 +752,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'description' field contains the regular expression stored in field 'regex' - * Field.of("description").regexContains(Field.of("regex")); + * field("description").regexContains(field("regex")); * ``` * * @param pattern The regular expression to use for the search. @@ -771,7 +771,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'email' field matches a valid email pattern - * Field.of("email").regexMatch("[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"); + * field("email").regexMatch("[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"); * ``` * * @param pattern The regular expression to use for the match. @@ -784,7 +784,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'email' field matches a regular expression stored in field 'regex' - * Field.of("email").regexMatch(Field.of("regex")); + * field("email").regexMatch(field("regex")); * ``` * * @param pattern The regular expression to use for the match. @@ -803,7 +803,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'description' field contains "example". - * Field.of("description").strContains("example"); + * field("description").strContains("example"); * ``` * * @param substring The substring to search for. @@ -816,7 +816,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'description' field contains the value of the 'keyword' field. - * Field.of("description").strContains(Field.of("keyword")); + * field("description").strContains(field("keyword")); * ``` * * @param expr The expression representing the substring to search for. @@ -835,7 +835,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'name' field starts with "Mr." - * Field.of("name").startsWith("Mr."); + * field("name").startsWith("Mr."); * ``` * * @param prefix The prefix to check for. @@ -849,7 +849,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'fullName' field starts with the value of the 'firstName' field - * Field.of("fullName").startsWith(Field.of("firstName")); + * field("fullName").startsWith(field("firstName")); * ``` * * @param prefix The prefix expression to check for. @@ -868,7 +868,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'filename' field ends with ".txt" - * Field.of("filename").endsWith(".txt"); + * field("filename").endsWith(".txt"); * ``` * * @param suffix The postfix to check for. @@ -882,7 +882,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'url' field ends with the value of the 'extension' field - * Field.of("url").endsWith(Field.of("extension")); + * field("url").endsWith(field("extension")); * ``` * * @param suffix The postfix expression to check for. @@ -901,7 +901,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Convert the 'name' field to lowercase - * Field.of("name").toLower(); + * field("name").toLower(); * ``` * * @return A new `Expr` representing the lowercase string. @@ -915,7 +915,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Convert the 'title' field to uppercase - * Field.of("title").toUpper(); + * field("title").toUpper(); * ``` * * @return A new `Expr` representing the uppercase string. @@ -929,7 +929,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Trim whitespace from the 'userInput' field - * Field.of("userInput").trim(); + * field("userInput").trim(); * ``` * * @return A new `Expr` representing the trimmed string. @@ -943,7 +943,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Combine the 'firstName', " ", and 'lastName' fields into a single string - * Field.of("firstName").strConcat(Constant.of(" "), Field.of("lastName")); + * field("firstName").strConcat(Constant.of(" "), field("lastName")); * ``` * * @param secondString The additional expression or string literal to concatenate. @@ -964,7 +964,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Reverse the value of the 'myString' field. - * Field.of("myString").reverse(); + * field("myString").reverse(); * ``` * * @return A new {@code Expr} representing the reversed string. @@ -978,7 +978,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Replace the first occurrence of "hello" with "hi" in the 'message' field - * Field.of("message").replaceFirst("hello", "hi"); + * field("message").replaceFirst("hello", "hi"); * ``` * * @param find The substring to search for. @@ -993,7 +993,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Replace the first occurrence of the value in 'findField' with the value in 'replaceField' in the 'message' field - * Field.of("message").replaceFirst(Field.of("findField"), Field.of("replaceField")); + * field("message").replaceFirst(field("findField"), field("replaceField")); * ``` * * @param find The expression representing the substring to search for. @@ -1014,7 +1014,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Replace all occurrences of "hello" with "hi" in the 'message' field - * Field.of("message").replaceAll("hello", "hi"); + * field("message").replaceAll("hello", "hi"); * ``` * * @param find The substring to search for. @@ -1029,7 +1029,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Replace all occurrences of the value in 'findField' with the value in 'replaceField' in the 'message' field - * Field.of("message").replaceAll(Field.of("findField"), Field.of("replaceField")); + * field("message").replaceAll(field("findField"), field("replaceField")); * ``` * * @param find The expression representing the substring to search for. @@ -1050,7 +1050,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the length of the 'myString' field in bytes. - * Field.of("myString").byteLength(); + * field("myString").byteLength(); * ``` * * @return A new {@code Expr} representing the length of the string in bytes. @@ -1064,7 +1064,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Get the 'city' value from the 'address' map field - * Field.of("address").mapGet("city"); + * field("address").mapGet("city"); * ``` * * @param subfield The key to access in the map. @@ -1080,7 +1080,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Count the total number of products - * Field.of("productId").count().as("totalProducts"); + * field("productId").count().as("totalProducts"); * ``` * * @return A new `AggregateFunction` representing the 'count' aggregation. @@ -1094,7 +1094,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the total revenue from a set of orders - * Field.of("orderAmount").sum().as("totalRevenue"); + * field("orderAmount").sum().as("totalRevenue"); * ``` * * @return A new `AggregateFunction` representing the 'sum' aggregation. @@ -1109,7 +1109,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the average age of users - * Field.of("age").avg().as("averageAge"); + * field("age").avg().as("averageAge"); * ``` * * @return A new `AggregateFunction` representing the 'avg' aggregation. @@ -1123,7 +1123,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Find the lowest price of all products - * Field.of("price").minimum().as("lowestPrice"); + * field("price").minimum().as("lowestPrice"); * ``` * * @return A new `AggregateFunction` representing the 'min' aggregation. @@ -1137,7 +1137,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Find the highest score in a leaderboard - * Field.of("score").maximum().as("highestScore"); + * field("score").maximum().as("highestScore"); * ``` * * @return A new `AggregateFunction` representing the 'max' aggregation. @@ -1151,7 +1151,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Returns the larger value between the 'timestamp' field and the current timestamp. - * Field.of("timestamp").logicalMaximum(Function.currentTimestamp()); + * field("timestamp").logicalMaximum(Function.currentTimestamp()); * ``` * * @param second The second expression or literal to compare with. @@ -1174,7 +1174,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Returns the smaller value between the 'timestamp' field and the current timestamp. - * Field.of("timestamp").logicalMinimum(Function.currentTimestamp()); + * field("timestamp").logicalMinimum(Function.currentTimestamp()); * ``` * * @param second The second expression or literal to compare with. @@ -1197,7 +1197,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Get the vector length (dimension) of the field 'embedding'. - * Field.of("embedding").vectorLength(); + * field("embedding").vectorLength(); * ``` * * @return A new {@code Expr} representing the length of the vector. @@ -1211,7 +1211,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the cosine distance between the 'userVector' field and the 'itemVector' field - * Field.of("userVector").cosineDistance(Field.of("itemVector")); + * field("userVector").cosineDistance(field("itemVector")); * ``` * * @param other The other vector (represented as an Expr) to compare against. @@ -1223,7 +1223,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the Cosine distance between the 'location' field and a target location - * Field.of("location").cosineDistance(new VectorValue([37.7749, -122.4194])); + * field("location").cosineDistance(new VectorValue([37.7749, -122.4194])); * ``` * * @param other The other vector (as a VectorValue) to compare against. @@ -1235,7 +1235,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the Cosine distance between the 'location' field and a target location - * Field.of("location").cosineDistance([37.7749, -122.4194]); + * field("location").cosineDistance([37.7749, -122.4194]); * ``` * * @param other The other vector (as an array of numbers) to compare against. @@ -1251,7 +1251,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the dot product between a feature vector and a target vector - * Field.of("features").dotProduct([0.5, 0.8, 0.2]); + * field("features").dotProduct([0.5, 0.8, 0.2]); * ``` * * @param other The other vector (as an array of numbers) to calculate with. @@ -1264,7 +1264,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the dot product between a feature vector and a target vector - * Field.of("features").dotProduct(new VectorValue([0.5, 0.8, 0.2])); + * field("features").dotProduct(new VectorValue([0.5, 0.8, 0.2])); * ``` * * @param other The other vector (as an array of numbers) to calculate with. @@ -1277,7 +1277,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the dot product between a feature vector and a target vector - * Field.of("features").dotProduct([0.5, 0.8, 0.2]); + * field("features").dotProduct([0.5, 0.8, 0.2]); * ``` * * @param other The other vector (as an array of numbers) to calculate with. @@ -1293,7 +1293,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the Euclidean distance between the 'location' field and a target location - * Field.of("location").euclideanDistance([37.7749, -122.4194]); + * field("location").euclideanDistance([37.7749, -122.4194]); * ``` * * @param other The other vector (as an array of numbers) to calculate with. @@ -1306,7 +1306,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the Euclidean distance between the 'location' field and a target location - * Field.of("location").euclideanDistance(new VectorValue([37.7749, -122.4194])); + * field("location").euclideanDistance(new VectorValue([37.7749, -122.4194])); * ``` * * @param other The other vector (as a VectorValue) to compare against. @@ -1319,7 +1319,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the Euclidean distance between the 'location' field and a target location - * Field.of("location").euclideanDistance([37.7749, -122.4194]); + * field("location").euclideanDistance([37.7749, -122.4194]); * ``` * * @param other The other vector (as an array of numbers) to compare against. @@ -1336,7 +1336,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the Manhattan distance between the 'location' field and a target location - * Field.of("location").manhattanDistance(new VectorValue([37.7749, -122.4194])); + * field("location").manhattanDistance(new VectorValue([37.7749, -122.4194])); * ``` * * @param other The other vector (as a VectorValue) to compare against. @@ -1351,7 +1351,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the Manhattan distance between the 'location' field and a target location - * Field.of("location").manhattanDistance([37.7749, -122.4194]); + * field("location").manhattanDistance([37.7749, -122.4194]); * ``` * * @param other The other vector (as an array of doubles) to compare against. @@ -1366,7 +1366,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' - * Field.of("pointA").manhattanDistance(Field.of("pointB")); + * field("pointA").manhattanDistance(field("pointB")); * ``` * * @param other The other vector (represented as an Expr) to compare against. @@ -1383,7 +1383,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Interpret the 'microseconds' field as microseconds since epoch. - * Field.of("microseconds").unixMicrosToTimestamp(); + * field("microseconds").unixMicrosToTimestamp(); * ``` * * @return A new {@code Expr} representing the timestamp. @@ -1397,7 +1397,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Convert the 'timestamp' field to microseconds since epoch. - * Field.of("timestamp").timestampToUnixMicros(); + * field("timestamp").timestampToUnixMicros(); * ``` * * @return A new {@code Expr} representing the number of microseconds since epoch. @@ -1412,7 +1412,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Interpret the 'milliseconds' field as milliseconds since epoch. - * Field.of("milliseconds").unixMillisToTimestamp(); + * field("milliseconds").unixMillisToTimestamp(); * ``` * * @return A new {@code Expr} representing the timestamp. @@ -1426,7 +1426,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Convert the 'timestamp' field to milliseconds since epoch. - * Field.of("timestamp").timestampToUnixMillis(); + * field("timestamp").timestampToUnixMillis(); * ``` * * @return A new {@code Expr} representing the number of milliseconds since epoch. @@ -1441,7 +1441,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Interpret the 'seconds' field as seconds since epoch. - * Field.of("seconds").unixSecondsToTimestamp(); + * field("seconds").unixSecondsToTimestamp(); * ``` * * @return A new {@code Expr} representing the timestamp. @@ -1455,7 +1455,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Convert the 'timestamp' field to seconds since epoch. - * Field.of("timestamp").timestampToUnixSeconds(); + * field("timestamp").timestampToUnixSeconds(); * ``` * * @return A new {@code Expr} representing the number of seconds since epoch. @@ -1469,7 +1469,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Add some duration determined by field 'unit' and 'amount' to the 'timestamp' field. - * Field.of("timestamp").timestampAdd(Field.of("unit"), Field.of("amount")); + * field("timestamp").timestampAdd(field("unit"), field("amount")); * ``` * * @param unit The expression evaluates to unit of time, must be one of 'microsecond', 'millisecond', 'second', 'minute', 'hour', 'day'. @@ -1483,7 +1483,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Add 1 day to the 'timestamp' field. - * Field.of("timestamp").timestampAdd("day", 1); + * field("timestamp").timestampAdd("day", 1); * ``` * * @param unit The unit of time to add (e.g., "day", "hour"). @@ -1517,7 +1517,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Subtract some duration determined by field 'unit' and 'amount' from the 'timestamp' field. - * Field.of("timestamp").timestampSub(Field.of("unit"), Field.of("amount")); + * field("timestamp").timestampSub(field("unit"), field("amount")); * ``` * * @param unit The expression evaluates to unit of time, must be one of 'microsecond', 'millisecond', 'second', 'minute', 'hour', 'day'. @@ -1531,7 +1531,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Subtract 1 day from the 'timestamp' field. - * Field.of("timestamp").timestampSub("day", 1); + * field("timestamp").timestampSub("day", 1); * ``` * * @param unit The unit of time to subtract (e.g., "day", "hour"). @@ -1567,7 +1567,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the bitwise AND of 'field1' and 0xFF. - * Field.of("field1").bitAnd(0xFF); + * field("field1").bitAnd(0xFF); * ``` * * @param otherBits A constant representing bits. @@ -1581,7 +1581,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the bitwise AND of 'field1' and 'field2'. - * Field.of("field1").bitAnd(Field.of("field2")); + * field("field1").bitAnd(field("field2")); * ``` * * @param bitsExpression An expression that returns bits when evaluated. @@ -1602,7 +1602,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the bitwise OR of 'field1' and 0xFF. - * Field.of("field1").bitOr(0xFF); + * field("field1").bitOr(0xFF); * ``` * * @param otherBits A constant representing bits. @@ -1616,7 +1616,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the bitwise OR of 'field1' and 'field2'. - * Field.of("field1").bitOr(Field.of("field2")); + * field("field1").bitOr(field("field2")); * ``` * * @param bitsExpression An expression that returns bits when evaluated. @@ -1637,7 +1637,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the bitwise XOR of 'field1' and 0xFF. - * Field.of("field1").bitXor(0xFF); + * field("field1").bitXor(0xFF); * ``` * * @param otherBits A constant representing bits. @@ -1651,7 +1651,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the bitwise XOR of 'field1' and 'field2'. - * Field.of("field1").bitXor(Field.of("field2")); + * field("field1").bitXor(field("field2")); * ``` * * @param bitsExpression An expression that returns bits when evaluated. @@ -1672,7 +1672,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the bitwise NOT of 'field1'. - * Field.of("field1").bitNot(); + * field("field1").bitNot(); * ``` * * @return A new {@code Expr} representing the bitwise NOT operation. @@ -1688,7 +1688,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the bitwise left shift of 'field1' by 2 bits. - * Field.of("field1").bitLeftShift(2); + * field("field1").bitLeftShift(2); * ``` * * @param y The operand constant representing the number of bits to shift. @@ -1702,7 +1702,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the bitwise left shift of 'field1' by 'field2' bits. - * Field.of("field1").bitLeftShift(Field.of("field2")); + * field("field1").bitLeftShift(field("field2")); * ``` * * @param numberExpr The operand expression representing the number of bits to shift. @@ -1723,7 +1723,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the bitwise right shift of 'field1' by 2 bits. - * Field.of("field1").bitRightShift(2); + * field("field1").bitRightShift(2); * ``` * * @param right The operand constant representing the number of bits to shift. @@ -1737,7 +1737,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Calculate the bitwise right shift of 'field1' by 'field2' bits. - * Field.of("field1").bitRightShift(Field.of("field2")); + * field("field1").bitRightShift(field("field2")); * ``` * * @param numberExpr The operand expression representing the number of bits to shift. @@ -1758,7 +1758,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Get the document ID from a path. - * Field.of("__path__").documentId(); + * field("__path__").documentId(); * ``` * * @return A new {@code Expr} representing the documentId operation. @@ -1809,7 +1809,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Return the value in the 'tags' field array at index `1`. - * Field.of('tags').arrayOffset(1); + * field('tags').arrayOffset(1); * ``` * * @param offset The index of the element to return. @@ -1826,7 +1826,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * ```typescript * // Return the value in the tags field array at index specified by field * // 'favoriteTag'. - * Field.of('tags').arrayOffset(Field.of('favoriteTag')); + * field('tags').arrayOffset(field('favoriteTag')); * ``` * * @param offsetExpr An Expr evaluating to the index of the element to return. @@ -1844,7 +1844,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the result of a calculation is an error - * Field.of("title").arrayContains(1).isError(); + * field("title").arrayContains(1).isError(); * ``` * * @return A new {@code BooleanExpr} representing the 'isError' check. @@ -1862,7 +1862,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * ```typescript * // Returns the first item in the title field arrays, or returns * // the entire title field if the array is empty or the field is another type. - * Field.of("title").arrayOffset(0).ifError(Field.of("title")); + * field("title").arrayOffset(0).ifError(field("title")); * ``` * * @param catchExpr The catch expression that will be evaluated and @@ -1880,7 +1880,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * ```typescript * // Returns the first item in the title field arrays, or returns * // "Default Title" - * Field.of("title").arrayOffset(0).ifError("Default Title"); + * field("title").arrayOffset(0).ifError("Default Title"); * ``` * * @param catchValue The value that will be returned if this expression @@ -1900,7 +1900,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the field `value` is absent. - * Field.of("value").isAbsent(); + * field("value").isAbsent(); * ``` * * @return A new {@code BooleanExpr} representing the 'isAbsent' check. @@ -1916,7 +1916,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the value of the 'name' field is not null - * Field.of("name").isNotNull(); + * field("name").isNotNull(); * ``` * * @return A new {@code BooleanExpr} representing the 'isNotNull' check. @@ -1932,7 +1932,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the result of a calculation is NOT NaN - * Field.of("value").divide(0).isNotNan(); + * field("value").divide(0).isNotNan(); * ``` * * @return A new {@code Expr} representing the 'isNaN' check. @@ -1984,7 +1984,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * ``` * // Merges the map in the settings field with, a map literal, and a map in * // that is conditionally returned by another expression - * Field.of('settings').mapMerge({ enabled: true }, cond(Field.of('isAdmin'), { admin: true}, {}) + * field('settings').mapMerge({ enabled: true }, cond(field('isAdmin'), { admin: true}, {}) * ``` * * @param secondMap A required second map to merge. Represented as a literal or @@ -2013,7 +2013,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * ```typescript * // Sort documents by the 'name' field in ascending order * pipeline().collection("users") - * .sort(Field.of("name").ascending()); + * .sort(field("name").ascending()); * ``` * * @return A new `Ordering` for ascending sorting. @@ -2028,7 +2028,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * ```typescript * // Sort documents by the 'createdAt' field in descending order * firestore.pipeline().collection("users") - * .sort(Field.of("createdAt").descending()); + * .sort(field("createdAt").descending()); * ``` * * @return A new `Ordering` for descending sorting. @@ -2046,7 +2046,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * ```typescript * // Calculate the total price and assign it the alias "totalPrice" and add it to the output. * firestore.pipeline().collection("items") - * .addFields(Field.of("price").multiply(Field.of("quantity")).as("totalPrice")); + * .addFields(field("price").multiply(field("quantity")).as("totalPrice")); * ``` * * @param name The alias to assign to this expression. @@ -2086,7 +2086,7 @@ export class AggregateFunction implements ProtoValueSerializable, UserData { * ```typescript * // Calculate the average price of all items and assign it the alias "averagePrice". * firestore.pipeline().collection("items") - * .aggregate(Field.of("price").avg().as("averagePrice")); + * .aggregate(field("price").avg().as("averagePrice")); * ``` * * @param name The alias to assign to this AggregateFunction. @@ -2211,51 +2211,24 @@ class ListOfExprs extends Expr { * * ```typescript * // Create a Field instance for the 'name' field - * const nameField = Field.of("name"); + * const nameField = field("name"); * * // Create a Field instance for a nested field 'address.city' - * const cityField = Field.of("address.city"); + * const cityField = field("address.city"); * ``` */ export class Field extends Expr implements Selectable { readonly exprType: ExprType = 'Field'; selectable = true as const; - private constructor(private fieldPath: InternalFieldPath) { - super(); - } - /** - * Creates a {@code Field} instance representing the field at the given path. - * - * The path can be a simple field name (e.g., "name") or a dot-separated path to a nested field - * (e.g., "address.city"). - * - * ```typescript - * // Create a Field instance for the 'title' field - * const titleField = Field.of("title"); - * - * // Create a Field instance for a nested field 'author.firstName' - * const authorFirstNameField = Field.of("author.firstName"); - * ``` - * - * @param name The path to the field. - * @return A new {@code Field} instance representing the specified field. + * @internal + * @private + * @hideconstructor + * @param fieldPath */ - static of(name: string): Field; - static of(path: FieldPath): Field; - static of(nameOrPath: string | FieldPath): Field { - if (typeof nameOrPath === 'string') { - if (DOCUMENT_KEY_NAME === nameOrPath) { - return new Field(documentId()._internalPath); - } - return new Field(fieldPathFromArgument('of', nameOrPath)); - } else { - if (documentId().isEqual(nameOrPath)) { - return new Field(documentId()._internalPath); - } - return new Field(nameOrPath._internalPath); - } + constructor(private fieldPath: InternalFieldPath) { + super(); } fieldName(): string { @@ -2287,6 +2260,39 @@ export class Field extends Expr implements Selectable { _readUserData(dataReader: UserDataReader): void {} } +/** + * Creates a {@code Field} instance representing the field at the given path. + * + * The path can be a simple field name (e.g., "name") or a dot-separated path to a nested field + * (e.g., "address.city"). + * + * ```typescript + * // Create a Field instance for the 'title' field + * const titleField = field("title"); + * + * // Create a Field instance for a nested field 'author.firstName' + * const authorFirstNameField = field("author.firstName"); + * ``` + * + * @param name The path to the field. + * @return A new {@code Field} instance representing the specified field. + */ +export function field(name: string): Field; +export function field(path: FieldPath): Field; +export function field(nameOrPath: string | FieldPath): Field { + if (typeof nameOrPath === 'string') { + if (DOCUMENT_KEY_NAME === nameOrPath) { + return new Field(documentId()._internalPath); + } + return new Field(fieldPathFromArgument('of', nameOrPath)); + } else { + if (documentId().isEqual(nameOrPath)) { + return new Field(documentId()._internalPath); + } + return new Field(nameOrPath._internalPath); + } +} + /** * @beta * @@ -2570,7 +2576,7 @@ export class BooleanExpr extends FunctionExpr { * * ```typescript * // Find the count of documents with a score greater than 90 - * Field.of("score").gt(90).countIf().as("highestScore"); + * field("score").gt(90).countIf().as("highestScore"); * ``` * * @return A new `AggregateFunction` representing the 'countIf' aggregation. @@ -2584,7 +2590,7 @@ export class BooleanExpr extends FunctionExpr { * * ```typescript * // Find documents where the 'tags' field does not contain 'completed' - * Field.of("tags").arrayContains("completed").not(); + * field("tags").arrayContains("completed").not(); * ``` * * @return A new {@code Expr} representing the negated filter condition. @@ -2601,7 +2607,7 @@ export class BooleanExpr extends FunctionExpr { * * ```typescript * // Count the number of documents where 'is_active' field equals true - * countif(Field.of("is_active").eq(true)).as("numActiveDocuments"); + * countif(field("is_active").eq(true)).as("numActiveDocuments"); * ``` * * @param booleanExpr - The boolean expression to evaluate on each input. @@ -2644,7 +2650,7 @@ export function bitAnd(field: string, otherBits: number | Bytes): FunctionExpr; * * ```typescript * // Calculate the bitwise AND of 'field1' and 'field2'. - * bitAnd("field1", Field.of("field2")); + * bitAnd("field1", field("field2")); * ``` * * @param field The left operand field name. @@ -2659,7 +2665,7 @@ export function bitAnd(field: string, bitsExpression: Expr): FunctionExpr; * * ```typescript * // Calculate the bitwise AND of 'field1' and 0xFF. - * bitAnd(Field.of("field1"), 0xFF); + * bitAnd(field("field1"), 0xFF); * ``` * * @param bitsExpression An expression returning bits. @@ -2677,7 +2683,7 @@ export function bitAnd( * * ```typescript * // Calculate the bitwise AND of 'field1' and 'field2'. - * bitAnd(Field.of("field1"), Field.of("field2")); + * bitAnd(field("field1"), field("field2")); * ``` * * @param bitsExpression An expression that returns bits when evaluated. @@ -2719,7 +2725,7 @@ export function bitOr(field: string, otherBits: number | Bytes): FunctionExpr; * * ```typescript * // Calculate the bitwise OR of 'field1' and 'field2'. - * bitOr("field1", Field.of("field2")); + * bitOr("field1", field("field2")); * ``` * * @param field The left operand field name. @@ -2734,7 +2740,7 @@ export function bitOr(field: string, bitsExpression: Expr): FunctionExpr; * * ```typescript * // Calculate the bitwise OR of 'field1' and 0xFF. - * bitOr(Field.of("field1"), 0xFF); + * bitOr(field("field1"), 0xFF); * ``` * * @param bitsExpression An expression returning bits. @@ -2752,7 +2758,7 @@ export function bitOr( * * ```typescript * // Calculate the bitwise OR of 'field1' and 'field2'. - * bitOr(Field.of("field1"), Field.of("field2")); + * bitOr(field("field1"), field("field2")); * ``` * * @param bitsExpression An expression that returns bits when evaluated. @@ -2794,7 +2800,7 @@ export function bitXor(field: string, otherBits: number | Bytes): FunctionExpr; * * ```typescript * // Calculate the bitwise XOR of 'field1' and 'field2'. - * bitXor("field1", Field.of("field2")); + * bitXor("field1", field("field2")); * ``` * * @param field The left operand field name. @@ -2809,7 +2815,7 @@ export function bitXor(field: string, bitsExpression: Expr): FunctionExpr; * * ```typescript * // Calculate the bitwise XOR of 'field1' and 0xFF. - * bitXor(Field.of("field1"), 0xFF); + * bitXor(field("field1"), 0xFF); * ``` * * @param bitsExpression An expression returning bits. @@ -2827,7 +2833,7 @@ export function bitXor( * * ```typescript * // Calculate the bitwise XOR of 'field1' and 'field2'. - * bitXor(Field.of("field1"), Field.of("field2")); + * bitXor(field("field1"), field("field2")); * ``` * * @param bitsExpression An expression that returns bits when evaluated. @@ -2868,7 +2874,7 @@ export function bitNot(field: string): FunctionExpr; * * ```typescript * // Calculate the bitwise NOT of 'field1'. - * bitNot(Field.of("field1")); + * bitNot(field("field1")); * ``` * * @param bitsValueExpression An expression that returns bits when evaluated. @@ -2901,7 +2907,7 @@ export function bitLeftShift(field: string, y: number): FunctionExpr; * * ```typescript * // Calculate the bitwise left shift of 'field1' by 'field2' bits. - * bitLeftShift("field1", Field.of("field2")); + * bitLeftShift("field1", field("field2")); * ``` * * @param field The left operand field name. @@ -2916,7 +2922,7 @@ export function bitLeftShift(field: string, numberExpr: Expr): FunctionExpr; * * ```typescript * // Calculate the bitwise left shift of 'field1' by 2 bits. - * bitLeftShift(Field.of("field1"), 2); + * bitLeftShift(field("field1"), 2); * ``` * * @param xValue An expression returning bits. @@ -2931,7 +2937,7 @@ export function bitLeftShift(xValue: Expr, y: number): FunctionExpr; * * ```typescript * // Calculate the bitwise left shift of 'field1' by 'field2' bits. - * bitLeftShift(Field.of("field1"), Field.of("field2")); + * bitLeftShift(field("field1"), field("field2")); * ``` * * @param xValue An expression returning bits. @@ -2968,7 +2974,7 @@ export function bitRightShift(field: string, y: number): FunctionExpr; * * ```typescript * // Calculate the bitwise right shift of 'field1' by 'field2' bits. - * bitRightShift("field1", Field.of("field2")); + * bitRightShift("field1", field("field2")); * ``` * * @param field The left operand field name. @@ -2983,7 +2989,7 @@ export function bitRightShift(field: string, numberExpr: Expr): FunctionExpr; * * ```typescript * // Calculate the bitwise right shift of 'field1' by 2 bits. - * bitRightShift(Field.of("field1"), 2); + * bitRightShift(field("field1"), 2); * ``` * * @param xValue An expression returning bits. @@ -2998,7 +3004,7 @@ export function bitRightShift(xValue: Expr, y: number): FunctionExpr; * * ```typescript * // Calculate the bitwise right shift of 'field1' by 'field2' bits. - * bitRightShift(Field.of("field1"), Field.of("field2")); + * bitRightShift(field("field1"), field("field2")); * ``` * * @param xValue An expression returning bits. @@ -3039,7 +3045,7 @@ export function arrayOffset(arrayField: string, offset: number): FunctionExpr; * ```typescript * // Return the value in the tags field array at index specified by field * // 'favoriteTag'. - * arrayOffset('tags', Field.of('favoriteTag')); + * arrayOffset('tags', field('favoriteTag')); * ``` * * @param arrayField The name of the array field. @@ -3056,7 +3062,7 @@ export function arrayOffset(arrayField: string, offsetExpr: Expr): FunctionExpr; * * ```typescript * // Return the value in the tags field array at index 1. - * arrayOffset(Field.of('tags'), 1); + * arrayOffset(field('tags'), 1); * ``` * * @param arrayExpression An Expr evaluating to an array. @@ -3077,7 +3083,7 @@ export function arrayOffset( * ```typescript * // Return the value in the tags field array at index specified by field * // 'favoriteTag'. - * arrayOffset(Field.of('tags'), Field.of('favoriteTag')); + * arrayOffset(field('tags'), field('favoriteTag')); * ``` * * @param arrayExpression An Expr evaluating to an array. @@ -3112,7 +3118,7 @@ export function currentContext(): FunctionExpr { * * ```typescript * // Check if the result of a calculation is an error - * isError(Field.of("title").arrayContains(1)); + * isError(field("title").arrayContains(1)); * ``` * * @param value The expression to check. @@ -3131,7 +3137,7 @@ export function isError(value: Expr): BooleanExpr { * ```typescript * // Returns the first item in the title field arrays, or returns * // the entire title field if the array is empty or the field is another type. - * ifError(Field.of("title").arrayOffset(0), Field.of("title")); + * ifError(field("title").arrayOffset(0), field("title")); * ``` * * @param tryExpr The try expression. @@ -3150,7 +3156,7 @@ export function ifError(tryExpr: Expr, catchExpr: Expr): FunctionExpr; * ```typescript * // Returns the first item in the title field arrays, or returns * // "Default Title" - * ifError(Field.of("title").arrayOffset(0), "Default Title"); + * ifError(field("title").arrayOffset(0), "Default Title"); * ``` * * @param tryExpr The try expression. @@ -3171,7 +3177,7 @@ export function ifError(tryExpr: Expr, catchValue: any): FunctionExpr { * * ```typescript * // Check if the field `value` is absent. - * isAbsent(Field.of("value")); + * isAbsent(field("value")); * ``` * * @param value The expression to check. @@ -3205,7 +3211,7 @@ export function isAbsent(value: Expr | string): BooleanExpr { * * ```typescript * // Check if the result of a calculation is NaN - * isNaN(Field.of("value").divide(0)); + * isNaN(field("value").divide(0)); * ``` * * @param value The expression to check. @@ -3238,7 +3244,7 @@ export function isNull(value: Expr | string): BooleanExpr { * * ```typescript * // Check if the value of the 'name' field is not null - * isNotNull(Field.of("name")); + * isNotNull(field("name")); * ``` * * @param value The expression to check. @@ -3271,7 +3277,7 @@ export function isNotNull(value: Expr | string): BooleanExpr { * * ```typescript * // Check if the result of a calculation is NOT NaN - * isNotNaN(Field.of("value").divide(0)); + * isNotNaN(field("value").divide(0)); * ``` * * @param value The expression to check. @@ -3369,7 +3375,7 @@ export function mapRemove( * ``` * // Merges the map in the settings field with, a map literal, and a map in * // that is conditionally returned by another expression - * mapMerge('settings', { enabled: true }, cond(Field.of('isAdmin'), { admin: true}, {}) + * mapMerge('settings', { enabled: true }, cond(field('isAdmin'), { admin: true}, {}) * ``` * * @param mapField Name of a field containing a map value that will be merged. @@ -3392,7 +3398,7 @@ export function mapMerge( * ``` * // Merges the map in the settings field with, a map literal, and a map in * // that is conditionally returned by another expression - * mapMerge(Field.of('settings'), { enabled: true }, cond(Field.of('isAdmin'), { admin: true}, {}) + * mapMerge(field('settings'), { enabled: true }, cond(field('isAdmin'), { admin: true}, {}) * ``` * * @param firstMap An expression or literal map map value that will be merged. @@ -3440,7 +3446,7 @@ export function documentIdFunction( * * ```typescript * // Get the document ID from a path. - * documentId(Field.of("__path__")); + * documentId(field("__path__")); * ``` * * @return A new {@code Expr} representing the documentId operation. @@ -3534,7 +3540,7 @@ export function substr( * * ```typescript * // Add the value of the 'quantity' field and the 'reserve' field. - * add(Field.of("quantity"), Field.of("reserve")); + * add(field("quantity"), field("reserve")); * ``` * * @param first The first expression to add. @@ -3555,7 +3561,7 @@ export function add( * * ```typescript * // Add the value of the 'quantity' field and the 'reserve' field. - * add("quantity", Field.of("reserve")); + * add("quantity", field("reserve")); * ``` * * @param fieldName The name of the field containing the value to add. @@ -3587,7 +3593,7 @@ export function add( * * ```typescript * // Subtract the 'discount' field from the 'price' field - * subtract(Field.of("price"), Field.of("discount")); + * subtract(field("price"), field("discount")); * ``` * * @param left The expression to subtract from. @@ -3603,7 +3609,7 @@ export function subtract(left: Expr, right: Expr): FunctionExpr; * * ```typescript * // Subtract the constant value 2 from the 'value' field - * subtract(Field.of("value"), 2); + * subtract(field("value"), 2); * ``` * * @param left The expression to subtract from. @@ -3619,7 +3625,7 @@ export function subtract(left: Expr, right: any): FunctionExpr; * * ```typescript * // Subtract the 'discount' field from the 'price' field - * subtract("price", Field.of("discount")); + * subtract("price", field("discount")); * ``` * * @param left The field name to subtract from. @@ -3644,7 +3650,7 @@ export function subtract(left: string, right: Expr): FunctionExpr; */ export function subtract(left: string, right: any): FunctionExpr; export function subtract(left: Expr | string, right: Expr | any): FunctionExpr { - const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; + const normalizedLeft = typeof left === 'string' ? field(left) : left; const normalizedRight = valueToDefaultExpr(right); return normalizedLeft.subtract(normalizedRight); } @@ -3656,7 +3662,7 @@ export function subtract(left: Expr | string, right: Expr | any): FunctionExpr { * * ```typescript * // Multiply the 'quantity' field by the 'price' field - * multiply(Field.of("quantity"), Field.of("price")); + * multiply(field("quantity"), field("price")); * ``` * * @param first The first expression to multiply. @@ -3677,7 +3683,7 @@ export function multiply( * * ```typescript * // Multiply the 'quantity' field by the 'price' field - * multiply("quantity", Field.of("price")); + * multiply("quantity", field("price")); * ``` * * @param fieldName The name of the field containing the value to add. @@ -3709,7 +3715,7 @@ export function multiply( * * ```typescript * // Divide the 'total' field by the 'count' field - * divide(Field.of("total"), Field.of("count")); + * divide(field("total"), field("count")); * ``` * * @param left The expression to be divided. @@ -3725,7 +3731,7 @@ export function divide(left: Expr, right: Expr): FunctionExpr; * * ```typescript * // Divide the 'value' field by 10 - * divide(Field.of("value"), 10); + * divide(field("value"), 10); * ``` * * @param left The expression to be divided. @@ -3741,7 +3747,7 @@ export function divide(left: Expr, right: any): FunctionExpr; * * ```typescript * // Divide the 'total' field by the 'count' field - * divide("total", Field.of("count")); + * divide("total", field("count")); * ``` * * @param left The field name to be divided. @@ -3766,7 +3772,7 @@ export function divide(left: string, right: Expr): FunctionExpr; */ export function divide(left: string, right: any): FunctionExpr; export function divide(left: Expr | string, right: Expr | any): FunctionExpr { - const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; + const normalizedLeft = typeof left === 'string' ? field(left) : left; const normalizedRight = valueToDefaultExpr(right); return normalizedLeft.divide(normalizedRight); } @@ -3778,7 +3784,7 @@ export function divide(left: Expr | string, right: Expr | any): FunctionExpr { * * ```typescript * // Calculate the remainder of dividing 'field1' by 'field2'. - * mod(Field.of("field1"), Field.of("field2")); + * mod(field("field1"), field("field2")); * ``` * * @param left The dividend expression. @@ -3794,7 +3800,7 @@ export function mod(left: Expr, right: Expr): FunctionExpr; * * ```typescript * // Calculate the remainder of dividing 'field1' by 5. - * mod(Field.of("field1"), 5); + * mod(field("field1"), 5); * ``` * * @param left The dividend expression. @@ -3810,7 +3816,7 @@ export function mod(left: Expr, right: any): FunctionExpr; * * ```typescript * // Calculate the remainder of dividing 'field1' by 'field2'. - * mod("field1", Field.of("field2")); + * mod("field1", field("field2")); * ``` * * @param left The dividend field name. @@ -3835,7 +3841,7 @@ export function mod(left: string, right: Expr): FunctionExpr; */ export function mod(left: string, right: any): FunctionExpr; export function mod(left: Expr | string, right: Expr | any): FunctionExpr { - const normalizedLeft = typeof left === 'string' ? Field.of(left) : left; + const normalizedLeft = typeof left === 'string' ? field(left) : left; const normalizedRight = valueToDefaultExpr(right); return normalizedLeft.mod(normalizedRight); } @@ -3888,7 +3894,7 @@ export function array(elements: any[]): FunctionExpr { * * ```typescript * // Check if the 'age' field is equal to an expression - * eq(Field.of("age"), Field.of("minAge").add(10)); + * eq(field("age"), field("minAge").add(10)); * ``` * * @param left The first expression to compare. @@ -3904,7 +3910,7 @@ export function eq(left: Expr, right: Expr): BooleanExpr; * * ```typescript * // Check if the 'age' field is equal to 21 - * eq(Field.of("age"), 21); + * eq(field("age"), 21); * ``` * * @param left The expression to compare. @@ -3920,7 +3926,7 @@ export function eq(left: Expr, right: any): BooleanExpr; * * ```typescript * // Check if the 'age' field is equal to the 'limit' field - * eq("age", Field.of("limit")); + * eq("age", field("limit")); * ``` * * @param left The field name to compare. @@ -3945,7 +3951,7 @@ export function eq(left: string, right: Expr): BooleanExpr; */ export function eq(left: string, right: any): BooleanExpr; export function eq(left: Expr | string, right: any): BooleanExpr { - const leftExpr = left instanceof Expr ? left : Field.of(left); + const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.eq(rightExpr); } @@ -3957,7 +3963,7 @@ export function eq(left: Expr | string, right: any): BooleanExpr { * * ```typescript * // Check if the 'status' field is not equal to field 'finalState' - * neq(Field.of("status"), Field.of("finalState")); + * neq(field("status"), field("finalState")); * ``` * * @param left The first expression to compare. @@ -3973,7 +3979,7 @@ export function neq(left: Expr, right: Expr): BooleanExpr; * * ```typescript * // Check if the 'status' field is not equal to "completed" - * neq(Field.of("status"), "completed"); + * neq(field("status"), "completed"); * ``` * * @param left The expression to compare. @@ -3989,7 +3995,7 @@ export function neq(left: Expr, right: any): BooleanExpr; * * ```typescript * // Check if the 'status' field is not equal to the value of 'expectedStatus' - * neq("status", Field.of("expectedStatus")); + * neq("status", field("expectedStatus")); * ``` * * @param left The field name to compare. @@ -4014,7 +4020,7 @@ export function neq(left: string, right: Expr): BooleanExpr; */ export function neq(left: string, right: any): BooleanExpr; export function neq(left: Expr | string, right: any): BooleanExpr { - const leftExpr = left instanceof Expr ? left : Field.of(left); + const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.neq(rightExpr); } @@ -4026,7 +4032,7 @@ export function neq(left: Expr | string, right: any): BooleanExpr { * * ```typescript * // Check if the 'age' field is less than 30 - * lt(Field.of("age"), Field.of("limit")); + * lt(field("age"), field("limit")); * ``` * * @param left The first expression to compare. @@ -4042,7 +4048,7 @@ export function lt(left: Expr, right: Expr): BooleanExpr; * * ```typescript * // Check if the 'age' field is less than 30 - * lt(Field.of("age"), 30); + * lt(field("age"), 30); * ``` * * @param left The expression to compare. @@ -4058,7 +4064,7 @@ export function lt(left: Expr, right: any): BooleanExpr; * * ```typescript * // Check if the 'age' field is less than the 'limit' field - * lt("age", Field.of("limit")); + * lt("age", field("limit")); * ``` * * @param left The field name to compare. @@ -4083,7 +4089,7 @@ export function lt(left: string, right: Expr): BooleanExpr; */ export function lt(left: string, right: any): BooleanExpr; export function lt(left: Expr | string, right: any): BooleanExpr { - const leftExpr = left instanceof Expr ? left : Field.of(left); + const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.lt(rightExpr); } @@ -4096,7 +4102,7 @@ export function lt(left: Expr | string, right: any): BooleanExpr { * * ```typescript * // Check if the 'quantity' field is less than or equal to 20 - * lte(Field.of("quantity"), Field.of("limit")); + * lte(field("quantity"), field("limit")); * ``` * * @param left The first expression to compare. @@ -4112,7 +4118,7 @@ export function lte(left: Expr, right: Expr): BooleanExpr; * * ```typescript * // Check if the 'quantity' field is less than or equal to 20 - * lte(Field.of("quantity"), 20); + * lte(field("quantity"), 20); * ``` * * @param left The expression to compare. @@ -4126,7 +4132,7 @@ export function lte(left: Expr, right: any): BooleanExpr; * * ```typescript * // Check if the 'quantity' field is less than or equal to the 'limit' field - * lte("quantity", Field.of("limit")); + * lte("quantity", field("limit")); * ``` * * @param left The field name to compare. @@ -4151,7 +4157,7 @@ export function lte(left: string, right: Expr): BooleanExpr; */ export function lte(left: string, right: any): BooleanExpr; export function lte(left: Expr | string, right: any): BooleanExpr { - const leftExpr = left instanceof Expr ? left : Field.of(left); + const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.lte(rightExpr); } @@ -4164,7 +4170,7 @@ export function lte(left: Expr | string, right: any): BooleanExpr { * * ```typescript * // Check if the 'age' field is greater than 18 - * gt(Field.of("age"), Constant(9).add(9)); + * gt(field("age"), Constant(9).add(9)); * ``` * * @param left The first expression to compare. @@ -4180,7 +4186,7 @@ export function gt(left: Expr, right: Expr): BooleanExpr; * * ```typescript * // Check if the 'age' field is greater than 18 - * gt(Field.of("age"), 18); + * gt(field("age"), 18); * ``` * * @param left The expression to compare. @@ -4196,7 +4202,7 @@ export function gt(left: Expr, right: any): BooleanExpr; * * ```typescript * // Check if the value of field 'age' is greater than the value of field 'limit' - * gt("age", Field.of("limit")); + * gt("age", field("limit")); * ``` * * @param left The field name to compare. @@ -4221,7 +4227,7 @@ export function gt(left: string, right: Expr): BooleanExpr; */ export function gt(left: string, right: any): BooleanExpr; export function gt(left: Expr | string, right: any): BooleanExpr { - const leftExpr = left instanceof Expr ? left : Field.of(left); + const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.gt(rightExpr); } @@ -4234,7 +4240,7 @@ export function gt(left: Expr | string, right: any): BooleanExpr { * * ```typescript * // Check if the 'quantity' field is greater than or equal to the field "threshold" - * gte(Field.of("quantity"), Field.of("threshold")); + * gte(field("quantity"), field("threshold")); * ``` * * @param left The first expression to compare. @@ -4251,7 +4257,7 @@ export function gte(left: Expr, right: Expr): BooleanExpr; * * ```typescript * // Check if the 'quantity' field is greater than or equal to 10 - * gte(Field.of("quantity"), 10); + * gte(field("quantity"), 10); * ``` * * @param left The expression to compare. @@ -4267,7 +4273,7 @@ export function gte(left: Expr, right: any): BooleanExpr; * * ```typescript * // Check if the value of field 'age' is greater than or equal to the value of field 'limit' - * gte("age", Field.of("limit")); + * gte("age", field("limit")); * ``` * * @param left The field name to compare. @@ -4293,7 +4299,7 @@ export function gte(left: string, right: Expr): BooleanExpr; */ export function gte(left: string, right: any): BooleanExpr; export function gte(left: Expr | string, right: any): BooleanExpr { - const leftExpr = left instanceof Expr ? left : Field.of(left); + const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.gte(rightExpr); } @@ -4305,7 +4311,7 @@ export function gte(left: Expr | string, right: any): BooleanExpr { * * ```typescript * // Combine the 'items' array with two new item arrays - * arrayConcat(Field.of("items"), [Field.of("newItems"), Field.of("otherItems")]); + * arrayConcat(field("items"), [field("newItems"), field("otherItems")]); * ``` * * @param firstArray The first array expression to concatenate to. @@ -4326,7 +4332,7 @@ export function arrayConcat( * * ```typescript * // Combine the 'items' array with two new item arrays - * arrayConcat("items", [Field.of("newItems"), Field.of("otherItems")]); + * arrayConcat("items", [field("newItems"), field("otherItems")]); * ``` * * @param firstArrayField The first array to concatenate to. @@ -4359,7 +4365,7 @@ export function arrayConcat( * * ```typescript * // Check if the 'colors' array contains the value of field 'selectedColor' - * arrayContains(Field.of("colors"), Field.of("selectedColor")); + * arrayContains(field("colors"), field("selectedColor")); * ``` * * @param array The array expression to check. @@ -4375,7 +4381,7 @@ export function arrayContains(array: Expr, element: Expr): FunctionExpr; * * ```typescript * // Check if the 'colors' array contains "red" - * arrayContains(Field.of("colors"), "red"); + * arrayContains(field("colors"), "red"); * ``` * * @param array The array expression to check. @@ -4391,7 +4397,7 @@ export function arrayContains(array: Expr, element: any): FunctionExpr; * * ```typescript * // Check if the 'colors' array contains the value of field 'selectedColor' - * arrayContains("colors", Field.of("selectedColor")); + * arrayContains("colors", field("selectedColor")); * ``` * * @param array The field name to check. @@ -4429,7 +4435,7 @@ export function arrayContains(array: Expr | string, element: any): BooleanExpr { * * ```typescript * // Check if the 'categories' array contains either values from field "cate1" or "Science" - * arrayContainsAny(Field.of("categories"), [Field.of("cate1"), "Science"]); + * arrayContainsAny(field("categories"), [field("cate1"), "Science"]); * ``` * * @param array The array expression to check. @@ -4446,7 +4452,7 @@ export function arrayContainsAny(array: Expr, values: Expr[]): BooleanExpr; * * ```typescript * // Check if the 'categories' array contains either values from field "cate1" or "Science" - * arrayContainsAny(Field.of("categories"), [Field.of("cate1"), "Science"]); + * arrayContainsAny(field("categories"), [field("cate1"), "Science"]); * ``` * * @param array The array expression to check. @@ -4464,7 +4470,7 @@ export function arrayContainsAny(array: Expr, values: any[]): BooleanExpr; * ```typescript * // Check if the 'groups' array contains either the value from the 'userGroup' field * // or the value "guest" - * arrayContainsAny("categories", [Field.of("cate1"), "Science"]); + * arrayContainsAny("categories", [field("cate1"), "Science"]); * ``` * * @param array The field name to check. @@ -4482,7 +4488,7 @@ export function arrayContainsAny(array: string, values: Expr[]): BooleanExpr; * ```typescript * // Check if the 'groups' array contains either the value from the 'userGroup' field * // or the value "guest" - * arrayContainsAny("categories", [Field.of("cate1"), "Science"]); + * arrayContainsAny("categories", [field("cate1"), "Science"]); * ``` * * @param array The field name to check. @@ -4506,7 +4512,7 @@ export function arrayContainsAny( * * ```typescript * // Check if the "tags" array contains all of the values: "SciFi", "Adventure", and the value from field "tag1" - * arrayContainsAll(Field.of("tags"), [Field.of("tag1"), Constant.of("SciFi"), Constant.of("Adventure")]); + * arrayContainsAll(field("tags"), [field("tag1"), Constant.of("SciFi"), Constant.of("Adventure")]); * ``` * * @param array The array expression to check. @@ -4522,7 +4528,7 @@ export function arrayContainsAll(array: Expr, values: Expr[]): BooleanExpr; * * ```typescript * // Check if the "tags" array contains all of the values: "SciFi", "Adventure", and the value from field "tag1" - * arrayContainsAll(Field.of("tags"), [Field.of("tag1"), "SciFi", "Adventure"]); + * arrayContainsAll(field("tags"), [field("tag1"), "SciFi", "Adventure"]); * ``` * * @param array The array expression to check. @@ -4539,7 +4545,7 @@ export function arrayContainsAll(array: Expr, values: any[]): BooleanExpr; * * ```typescript * // Check if the 'tags' array contains both of the values from field 'tag1' and "tag2" - * arrayContainsAll("tags", [Field.of("tag1"), "SciFi", "Adventure"]); + * arrayContainsAll("tags", [field("tag1"), "SciFi", "Adventure"]); * ``` * * @param array The field name to check. @@ -4556,7 +4562,7 @@ export function arrayContainsAll(array: string, values: Expr[]): BooleanExpr; * * ```typescript * // Check if the 'tags' array contains both of the values from field 'tag1' and "tag2" - * arrayContainsAll("tags", [Field.of("tag1"), "SciFi", "Adventure"]); + * arrayContainsAll("tags", [field("tag1"), "SciFi", "Adventure"]); * ``` * * @param array The field name to check. @@ -4580,7 +4586,7 @@ export function arrayContainsAll( * * ```typescript * // Get the number of items in the 'cart' array - * arrayLength(Field.of("cart")); + * arrayLength(field("cart")); * ``` * * @param array The array expression to calculate the length of. @@ -4598,7 +4604,7 @@ export function arrayLength(array: Expr): FunctionExpr { * * ```typescript * // Check if the 'category' field is either "Electronics" or value of field 'primaryType' - * eqAny(Field.of("category"), [Constant.of("Electronics"), Field.of("primaryType")]); + * eqAny(field("category"), [Constant.of("Electronics"), field("primaryType")]); * ``` * * @param element The expression to compare. @@ -4615,7 +4621,7 @@ export function eqAny(element: Expr, others: Expr[]): BooleanExpr; * * ```typescript * // Check if the 'category' field is either "Electronics" or value of field 'primaryType' - * eqAny(Field.of("category"), ["Electronics", Field.of("primaryType")]); + * eqAny(field("category"), ["Electronics", field("primaryType")]); * ``` * * @param element The expression to compare. @@ -4632,7 +4638,7 @@ export function eqAny(element: Expr, others: any[]): BooleanExpr; * * ```typescript * // Check if the 'category' field is either "Electronics" or value of field 'primaryType' - * eqAny("category", [Constant.of("Electronics"), Field.of("primaryType")]); + * eqAny("category", [Constant.of("Electronics"), field("primaryType")]); * ``` * * @param element The field to compare. @@ -4649,7 +4655,7 @@ export function eqAny(element: string, others: Expr[]): BooleanExpr; * * ```typescript * // Check if the 'category' field is either "Electronics" or value of field 'primaryType' - * eqAny("category", ["Electronics", Field.of("primaryType")]); + * eqAny("category", ["Electronics", field("primaryType")]); * ``` * * @param element The field to compare. @@ -4671,7 +4677,7 @@ export function eqAny(element: Expr | string, others: any[]): BooleanExpr { * * ```typescript * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * notEqAny(Field.of("status"), [Constant.of("pending"), Field.of("rejectedStatus")]); + * notEqAny(field("status"), [Constant.of("pending"), field("rejectedStatus")]); * ``` * * @param element The expression to compare. @@ -4688,7 +4694,7 @@ export function notEqAny(element: Expr, others: Expr[]): BooleanExpr; * * ```typescript * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * notEqAny(Field.of("status"), ["pending", Field.of("rejectedStatus")]); + * notEqAny(field("status"), ["pending", field("rejectedStatus")]); * ``` * * @param element The expression to compare. @@ -4705,7 +4711,7 @@ export function notEqAny(element: Expr, others: any[]): BooleanExpr; * * ```typescript * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * notEqAny("status", [Constant.of("pending"), Field.of("rejectedStatus")]); + * notEqAny("status", [Constant.of("pending"), field("rejectedStatus")]); * ``` * * @param element The field name to compare. @@ -4722,7 +4728,7 @@ export function notEqAny(element: string, others: Expr[]): BooleanExpr; * * ```typescript * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * notEqAny("status", ["pending", Field.of("rejectedStatus")]); + * notEqAny("status", ["pending", field("rejectedStatus")]); * ``` * * @param element The field name to compare. @@ -4813,7 +4819,7 @@ export function not(filter: BooleanExpr): BooleanExpr { * * ```typescript * // Returns the larger value between the 'field1' field and the 'field2' field. - * logicalMaximum(Field.of("field1"), Field.of("field2")); + * logicalMaximum(field("field1"), field("field2")); * ``` * * @param first The first operand expression. @@ -4834,7 +4840,7 @@ export function logicalMaximum( * * ```typescript * // Returns the larger value between the 'field1' field and the 'field2' field. - * logicalMaximum("field1", Field.of('field2')); + * logicalMaximum("field1", field('field2')); * ``` * * @param fieldName The first operand field name. @@ -4866,7 +4872,7 @@ export function logicalMaximum( * * ```typescript * // Returns the smaller value between the 'field1' field and the 'field2' field. - * logicalMinimum(Field.of("field1"), Field.of("field2")); + * logicalMinimum(field("field1"), field("field2")); * ``` * * @param first The first operand expression. @@ -4887,7 +4893,7 @@ export function logicalMinimum( * * ```typescript * // Returns the smaller value between the 'field1' field and the 'field2' field. - * logicalMinimum("field1", Field.of("field2")); + * logicalMinimum("field1", field("field2")); * ``` * * @param fieldName The first operand field name. @@ -4919,7 +4925,7 @@ export function logicalMinimum( * * ```typescript * // Check if the document has a field named "phoneNumber" - * exists(Field.of("phoneNumber")); + * exists(field("phoneNumber")); * ``` * * @param value An expression evaluates to the name of the field to check. @@ -4952,7 +4958,7 @@ export function exists(valueOrField: Expr | string): BooleanExpr { * * ```typescript * // Check if the result of a calculation is NaN - * isNaN(Field.of("value").divide(0)); + * isNaN(field("value").divide(0)); * ``` * * @param value The expression to check. @@ -4985,7 +4991,7 @@ export function isNan(value: Expr | string): BooleanExpr { * * ```typescript * // Reverse the value of the 'myString' field. - * reverse(Field.of("myString")); + * reverse(field("myString")); * ``` * * @param expr The expression representing the string to reverse. @@ -5018,7 +5024,7 @@ export function reverse(expr: Expr | string): FunctionExpr { * * ```typescript * // Replace the first occurrence of "hello" with "hi" in the 'message' field. - * replaceFirst(Field.of("message"), "hello", "hi"); + * replaceFirst(field("message"), "hello", "hi"); * ``` * * @param value The expression representing the string to perform the replacement on. @@ -5040,7 +5046,7 @@ export function replaceFirst( * * ```typescript * // Replace the first occurrence of the value in 'findField' with the value in 'replaceField' in the 'message' field. - * replaceFirst(Field.of("message"), Field.of("findField"), Field.of("replaceField")); + * replaceFirst(field("message"), field("findField"), field("replaceField")); * ``` * * @param value The expression representing the string to perform the replacement on. @@ -5092,7 +5098,7 @@ export function replaceFirst( * * ```typescript * // Replace all occurrences of "hello" with "hi" in the 'message' field. - * replaceAll(Field.of("message"), "hello", "hi"); + * replaceAll(field("message"), "hello", "hi"); * ``` * * @param value The expression representing the string to perform the replacement on. @@ -5114,7 +5120,7 @@ export function replaceAll( * * ```typescript * // Replace all occurrences of the value in 'findField' with the value in 'replaceField' in the 'message' field. - * replaceAll(Field.of("message"), Field.of("findField"), Field.of("replaceField")); + * replaceAll(field("message"), field("findField"), field("replaceField")); * ``` * * @param value The expression representing the string to perform the replacement on. @@ -5166,7 +5172,7 @@ export function replaceAll( * * ```typescript * // Calculate the length of the 'myString' field in bytes. - * byteLength(Field.of("myString")); + * byteLength(field("myString")); * ``` * * @param expr The expression representing the string. @@ -5215,7 +5221,7 @@ export function charLength(field: string): FunctionExpr; * * ```typescript * // Get the character length of the 'name' field in UTF-8. - * strLength(Field.of("name")); + * strLength(field("name")); * ``` * * @param expr The expression representing the string to calculate the length of. @@ -5252,7 +5258,7 @@ export function like(left: string, pattern: string): BooleanExpr; * * ```typescript * // Check if the 'title' field contains the string "guide" - * like("title", Field.of("pattern")); + * like("title", field("pattern")); * ``` * * @param left The name of the field containing the string. @@ -5268,7 +5274,7 @@ export function like(left: string, pattern: Expr): BooleanExpr; * * ```typescript * // Check if the 'title' field contains the string "guide" - * like(Field.of("title"), "%guide%"); + * like(field("title"), "%guide%"); * ``` * * @param left The expression representing the string to perform the comparison on. @@ -5284,7 +5290,7 @@ export function like(left: Expr, pattern: string): BooleanExpr; * * ```typescript * // Check if the 'title' field contains the string "guide" - * like(Field.of("title"), Field.of("pattern")); + * like(field("title"), field("pattern")); * ``` * * @param left The expression representing the string to perform the comparison on. @@ -5326,7 +5332,7 @@ export function regexContains(left: string, pattern: string): BooleanExpr; * * ```typescript * // Check if the 'description' field contains "example" (case-insensitive) - * regexContains("description", Field.of("pattern")); + * regexContains("description", field("pattern")); * ``` * * @param left The name of the field containing the string. @@ -5343,7 +5349,7 @@ export function regexContains(left: string, pattern: Expr): BooleanExpr; * * ```typescript * // Check if the 'description' field contains "example" (case-insensitive) - * regexContains(Field.of("description"), "(?i)example"); + * regexContains(field("description"), "(?i)example"); * ``` * * @param left The expression representing the string to perform the comparison on. @@ -5360,7 +5366,7 @@ export function regexContains(left: Expr, pattern: string): BooleanExpr; * * ```typescript * // Check if the 'description' field contains "example" (case-insensitive) - * regexContains(Field.of("description"), Field.of("pattern")); + * regexContains(field("description"), field("pattern")); * ``` * * @param left The expression representing the string to perform the comparison on. @@ -5400,7 +5406,7 @@ export function regexMatch(left: string, pattern: string): BooleanExpr; * * ```typescript * // Check if the 'email' field matches a valid email pattern - * regexMatch("email", Field.of("pattern")); + * regexMatch("email", field("pattern")); * ``` * * @param left The name of the field containing the string. @@ -5417,7 +5423,7 @@ export function regexMatch(left: string, pattern: Expr): BooleanExpr; * * ```typescript * // Check if the 'email' field matches a valid email pattern - * regexMatch(Field.of("email"), "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"); + * regexMatch(field("email"), "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"); * ``` * * @param left The expression representing the string to match against. @@ -5434,7 +5440,7 @@ export function regexMatch(left: Expr, pattern: string): BooleanExpr; * * ```typescript * // Check if the 'email' field matches a valid email pattern - * regexMatch(Field.of("email"), Field.of("pattern")); + * regexMatch(field("email"), field("pattern")); * ``` * * @param left The expression representing the string to match against. @@ -5474,7 +5480,7 @@ export function strContains(left: string, substring: string): BooleanExpr; * * ```typescript * // Check if the 'description' field contains the value of the 'keyword' field. - * strContains("description", Field.of("keyword")); + * strContains("description", field("keyword")); * ``` * * @param left The name of the field containing the string. @@ -5490,7 +5496,7 @@ export function strContains(left: string, substring: Expr): BooleanExpr; * * ```typescript * // Check if the 'description' field contains "example". - * strContains(Field.of("description"), "example"); + * strContains(field("description"), "example"); * ``` * * @param left The expression representing the string to perform the comparison on. @@ -5506,7 +5512,7 @@ export function strContains(left: Expr, substring: string): BooleanExpr; * * ```typescript * // Check if the 'description' field contains the value of the 'keyword' field. - * strContains(Field.of("description"), Field.of("keyword")); + * strContains(field("description"), field("keyword")); * ``` * * @param left The expression representing the string to perform the comparison on. @@ -5546,7 +5552,7 @@ export function startsWith(expr: string, prefix: string): BooleanExpr; * * ```typescript * // Check if the 'fullName' field starts with the value of the 'firstName' field - * startsWith("fullName", Field.of("firstName")); + * startsWith("fullName", field("firstName")); * ``` * * @param expr The field name to check. @@ -5562,7 +5568,7 @@ export function startsWith(expr: string, prefix: Expr): BooleanExpr; * * ```typescript * // Check if the result of concatenating 'firstName' and 'lastName' fields starts with "Mr." - * startsWith(Field.of("fullName"), "Mr."); + * startsWith(field("fullName"), "Mr."); * ``` * * @param expr The expression to check. @@ -5578,7 +5584,7 @@ export function startsWith(expr: Expr, prefix: string): BooleanExpr; * * ```typescript * // Check if the result of concatenating 'firstName' and 'lastName' fields starts with "Mr." - * startsWith(Field.of("fullName"), Field.of("prefix")); + * startsWith(field("fullName"), field("prefix")); * ``` * * @param expr The expression to check. @@ -5616,7 +5622,7 @@ export function endsWith(expr: string, suffix: string): BooleanExpr; * * ```typescript * // Check if the 'url' field ends with the value of the 'extension' field - * endsWith("url", Field.of("extension")); + * endsWith("url", field("extension")); * ``` * * @param expr The field name to check. @@ -5632,7 +5638,7 @@ export function endsWith(expr: string, suffix: Expr): BooleanExpr; * * ```typescript * // Check if the result of concatenating 'firstName' and 'lastName' fields ends with "Jr." - * endsWith(Field.of("fullName"), "Jr."); + * endsWith(field("fullName"), "Jr."); * ``` * * @param expr The expression to check. @@ -5648,7 +5654,7 @@ export function endsWith(expr: Expr, suffix: string): BooleanExpr; * * ```typescript * // Check if the result of concatenating 'firstName' and 'lastName' fields ends with "Jr." - * endsWith(Field.of("fullName"), Constant.of("Jr.")); + * endsWith(field("fullName"), Constant.of("Jr.")); * ``` * * @param expr The expression to check. @@ -5685,7 +5691,7 @@ export function toLower(expr: string): FunctionExpr; * * ```typescript * // Convert the 'name' field to lowercase - * toLower(Field.of("name")); + * toLower(field("name")); * ``` * * @param expr The expression representing the string to convert to lowercase. @@ -5718,7 +5724,7 @@ export function toUpper(expr: string): FunctionExpr; * * ```typescript * // Convert the 'title' field to uppercase - * toUppercase(Field.of("title")); + * toUppercase(field("title")); * ``` * * @param expr The expression representing the string to convert to uppercase. @@ -5751,7 +5757,7 @@ export function trim(expr: string): FunctionExpr; * * ```typescript * // Trim whitespace from the 'userInput' field - * trim(Field.of("userInput")); + * trim(field("userInput")); * ``` * * @param expr The expression representing the string to trim. @@ -5769,7 +5775,7 @@ export function trim(expr: Expr | string): FunctionExpr { * * ```typescript * // Combine the 'firstName', " ", and 'lastName' fields into a single string - * strConcat("firstName", " ", Field.of("lastName")); + * strConcat("firstName", " ", field("lastName")); * ``` * * @param fieldName The field name containing the initial string value. @@ -5789,7 +5795,7 @@ export function strConcat( * * ```typescript * // Combine the 'firstName', " ", and 'lastName' fields into a single string - * strConcat(Field.of("firstName"), " ", Field.of("lastName")); + * strConcat(field("firstName"), " ", field("lastName")); * ``` * * @param firstString The initial string expression to concatenate to. @@ -5836,7 +5842,7 @@ export function mapGet(mapField: string, subField: string): FunctionExpr; * * ```typescript * // Get the 'city' value from the 'address' map field - * mapGet(Field.of("address"), "city"); + * mapGet(field("address"), "city"); * ``` * * @param mapExpr The expression representing the map. @@ -5875,7 +5881,7 @@ export function countAll(): AggregateFunction { * * ```typescript * // Count the number of items where the price is greater than 10 - * count(Field.of("price").gt(10)).as("expensiveItemCount"); + * count(field("price").gt(10)).as("expensiveItemCount"); * ``` * * @param value The expression to count. @@ -5908,7 +5914,7 @@ export function countFunction(value: Expr | string): AggregateFunction { * * ```typescript * // Calculate the total revenue from a set of orders - * sum(Field.of("orderAmount")).as("totalRevenue"); + * sum(field("orderAmount")).as("totalRevenue"); * ``` * * @param value The expression to sum up. @@ -5943,7 +5949,7 @@ export function sumFunction(value: Expr | string): AggregateFunction { * * ```typescript * // Calculate the average age of users - * avg(Field.of("age")).as("averageAge"); + * avg(field("age")).as("averageAge"); * ``` * * @param value The expression representing the values to average. @@ -5978,7 +5984,7 @@ export function avgFunction(value: Expr | string): AggregateFunction { * * ```typescript * // Find the lowest price of all products - * minimum(Field.of("price")).as("lowestPrice"); + * minimum(field("price")).as("lowestPrice"); * ``` * * @param value The expression to find the minimum value of. @@ -6012,7 +6018,7 @@ export function minimum(value: Expr | string): AggregateFunction { * * ```typescript * // Find the highest score in a leaderboard - * maximum(Field.of("score")).as("highestScore"); + * maximum(field("score")).as("highestScore"); * ``` * * @param value The expression to find the maximum value of. @@ -6077,7 +6083,7 @@ export function cosineDistance(expr: string, other: VectorValue): FunctionExpr; * * ```typescript * // Calculate the cosine distance between the 'userVector' field and the 'itemVector' field - * cosineDistance("userVector", Field.of("itemVector")); + * cosineDistance("userVector", field("itemVector")); * ``` * * @param expr The name of the field containing the first vector. @@ -6093,7 +6099,7 @@ export function cosineDistance(expr: string, other: Expr): FunctionExpr; * * ```typescript * // Calculate the cosine distance between the 'location' field and a target location - * cosineDistance(Field.of("location"), [37.7749, -122.4194]); + * cosineDistance(field("location"), [37.7749, -122.4194]); * ``` * * @param expr The first vector (represented as an Expr) to compare against. @@ -6109,7 +6115,7 @@ export function cosineDistance(expr: Expr, other: number[]): FunctionExpr; * * ```typescript * // Calculate the cosine distance between the 'location' field and a target location - * cosineDistance(Field.of("location"), new VectorValue([37.7749, -122.4194])); + * cosineDistance(field("location"), new VectorValue([37.7749, -122.4194])); * ``` * * @param expr The first vector (represented as an Expr) to compare against. @@ -6125,7 +6131,7 @@ export function cosineDistance(expr: Expr, other: VectorValue): FunctionExpr; * * ```typescript * // Calculate the cosine distance between the 'userVector' field and the 'itemVector' field - * cosineDistance(Field.of("userVector"), Field.of("itemVector")); + * cosineDistance(field("userVector"), field("itemVector")); * ``` * * @param expr The first vector (represented as an Expr) to compare against. @@ -6181,7 +6187,7 @@ export function dotProduct(expr: string, other: VectorValue): FunctionExpr; * * ```typescript * // Calculate the dot product distance between two document vectors: 'docVector1' and 'docVector2' - * dotProduct("docVector1", Field.of("docVector2")); + * dotProduct("docVector1", field("docVector2")); * ``` * * @param expr The name of the field containing the first vector. @@ -6197,7 +6203,7 @@ export function dotProduct(expr: string, other: Expr): FunctionExpr; * * ```typescript * // Calculate the dot product between a feature vector and a target vector - * dotProduct(Field.of("features"), [0.5, 0.8, 0.2]); + * dotProduct(field("features"), [0.5, 0.8, 0.2]); * ``` * * @param expr The first vector (represented as an Expr) to calculate with. @@ -6213,7 +6219,7 @@ export function dotProduct(expr: Expr, other: number[]): FunctionExpr; * * ```typescript * // Calculate the dot product between a feature vector and a target vector - * dotProduct(Field.of("features"), new VectorValue([0.5, 0.8, 0.2])); + * dotProduct(field("features"), new VectorValue([0.5, 0.8, 0.2])); * ``` * * @param expr The first vector (represented as an Expr) to calculate with. @@ -6229,7 +6235,7 @@ export function dotProduct(expr: Expr, other: VectorValue): FunctionExpr; * * ```typescript * // Calculate the dot product between two document vectors: 'docVector1' and 'docVector2' - * dotProduct(Field.of("docVector1"), Field.of("docVector2")); + * dotProduct(field("docVector1"), field("docVector2")); * ``` * * @param expr The first vector (represented as an Expr) to calculate with. @@ -6288,7 +6294,7 @@ export function euclideanDistance( * * ```typescript * // Calculate the Euclidean distance between two vector fields: 'pointA' and 'pointB' - * euclideanDistance("pointA", Field.of("pointB")); + * euclideanDistance("pointA", field("pointB")); * ``` * * @param expr The name of the field containing the first vector. @@ -6305,7 +6311,7 @@ export function euclideanDistance(expr: string, other: Expr): FunctionExpr; * ```typescript * // Calculate the Euclidean distance between the 'location' field and a target location * - * euclideanDistance(Field.of("location"), [37.7749, -122.4194]); + * euclideanDistance(field("location"), [37.7749, -122.4194]); * ``` * * @param expr The first vector (represented as an Expr) to compare against. @@ -6321,7 +6327,7 @@ export function euclideanDistance(expr: Expr, other: number[]): FunctionExpr; * * ```typescript * // Calculate the Euclidean distance between the 'location' field and a target location - * euclideanDistance(Field.of("location"), new VectorValue([37.7749, -122.4194])); + * euclideanDistance(field("location"), new VectorValue([37.7749, -122.4194])); * ``` * * @param expr The first vector (represented as an Expr) to compare against. @@ -6337,7 +6343,7 @@ export function euclideanDistance(expr: Expr, other: VectorValue): FunctionExpr; * * ```typescript * // Calculate the Euclidean distance between two vector fields: 'pointA' and 'pointB' - * euclideanDistance(Field.of("pointA"), Field.of("pointB")); + * euclideanDistance(field("pointA"), field("pointB")); * ``` * * @param expr The first vector (represented as an Expr) to compare against. @@ -6396,7 +6402,7 @@ export function manhattanDistance( * * ```typescript * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' - * manhattanDistance("pointA", Field.of("pointB")); + * manhattanDistance("pointA", field("pointB")); * ``` * * @param expr The name of the field containing the first vector. @@ -6413,7 +6419,7 @@ export function manhattanDistance(expr: string, other: Expr): FunctionExpr; * ```typescript * // Calculate the Manhattan distance between the 'location' field and a target location * - * manhattanDistance(Field.of("location"), [37.7749, -122.4194]); + * manhattanDistance(field("location"), [37.7749, -122.4194]); * ``` * * @param expr The first vector (represented as an Expr) to compare against. @@ -6429,7 +6435,7 @@ export function manhattanDistance(expr: Expr, other: number[]): FunctionExpr; * * ```typescript * // Calculate the Manhattan distance between the 'location' field and a target location - * manhattanDistance(Field.of("location"), new VectorValue([37.7749, -122.4194])); + * manhattanDistance(field("location"), new VectorValue([37.7749, -122.4194])); * ``` * * @param expr The first vector (represented as an Expr) to compare against. @@ -6445,7 +6451,7 @@ export function manhattanDistance(expr: Expr, other: VectorValue): FunctionExpr; * * ```typescript * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' - * manhattanDistance(Field.of("pointA"), Field.of("pointB")); + * manhattanDistance(field("pointA"), field("pointB")); * ``` * * @param expr The first vector (represented as an Expr) to compare against. @@ -6469,7 +6475,7 @@ export function manhattanDistance( * * ```typescript * // Get the vector length (dimension) of the field 'embedding'. - * vectorLength(Field.of("embedding")); + * vectorLength(field("embedding")); * ``` * * @param expr The expression representing the Firestore Vector. @@ -6503,7 +6509,7 @@ export function vectorLength(expr: Expr | string): FunctionExpr { * * ```typescript * // Interpret the 'microseconds' field as microseconds since epoch. - * unixMicrosToTimestamp(Field.of("microseconds")); + * unixMicrosToTimestamp(field("microseconds")); * ``` * * @param expr The expression representing the number of microseconds since epoch. @@ -6537,7 +6543,7 @@ export function unixMicrosToTimestamp(expr: Expr | string): FunctionExpr { * * ```typescript * // Convert the 'timestamp' field to microseconds since epoch. - * timestampToUnixMicros(Field.of("timestamp")); + * timestampToUnixMicros(field("timestamp")); * ``` * * @param expr The expression representing the timestamp. @@ -6571,7 +6577,7 @@ export function timestampToUnixMicros(expr: Expr | string): FunctionExpr { * * ```typescript * // Interpret the 'milliseconds' field as milliseconds since epoch. - * unixMillisToTimestamp(Field.of("milliseconds")); + * unixMillisToTimestamp(field("milliseconds")); * ``` * * @param expr The expression representing the number of milliseconds since epoch. @@ -6606,7 +6612,7 @@ export function unixMillisToTimestamp(expr: Expr | string): FunctionExpr { * * ```typescript * // Convert the 'timestamp' field to milliseconds since epoch. - * timestampToUnixMillis(Field.of("timestamp")); + * timestampToUnixMillis(field("timestamp")); * ``` * * @param expr The expression representing the timestamp. @@ -6641,7 +6647,7 @@ export function timestampToUnixMillis(expr: Expr | string): FunctionExpr { * * ```typescript * // Interpret the 'seconds' field as seconds since epoch. - * unixSecondsToTimestamp(Field.of("seconds")); + * unixSecondsToTimestamp(field("seconds")); * ``` * * @param expr The expression representing the number of seconds since epoch. @@ -6676,7 +6682,7 @@ export function unixSecondsToTimestamp(expr: Expr | string): FunctionExpr { * * ```typescript * // Convert the 'timestamp' field to seconds since epoch. - * timestampToUnixSeconds(Field.of("timestamp")); + * timestampToUnixSeconds(field("timestamp")); * ``` * * @param expr The expression representing the timestamp. @@ -6710,7 +6716,7 @@ export function timestampToUnixSeconds(expr: Expr | string): FunctionExpr { * * ```typescript * // Add some duration determined by field 'unit' and 'amount' to the 'timestamp' field. - * timestampAdd(Field.of("timestamp"), Field.of("unit"), Field.of("amount")); + * timestampAdd(field("timestamp"), field("unit"), field("amount")); * ``` * * @param timestamp The expression representing the timestamp. @@ -6731,7 +6737,7 @@ export function timestampAdd( * * ```typescript * // Add 1 day to the 'timestamp' field. - * timestampAdd(Field.of("timestamp"), "day", 1); + * timestampAdd(field("timestamp"), "day", 1); * ``` * * @param timestamp The expression representing the timestamp. @@ -6790,7 +6796,7 @@ export function timestampAdd( * * ```typescript * // Subtract some duration determined by field 'unit' and 'amount' from the 'timestamp' field. - * timestampSub(Field.of("timestamp"), Field.of("unit"), Field.of("amount")); + * timestampSub(field("timestamp"), field("unit"), field("amount")); * ``` * * @param timestamp The expression representing the timestamp. @@ -6811,7 +6817,7 @@ export function timestampSub( * * ```typescript * // Subtract 1 day from the 'timestamp' field. - * timestampSub(Field.of("timestamp"), "day", 1); + * timestampSub(field("timestamp"), "day", 1); * ``` * * @param timestamp The expression representing the timestamp. @@ -6869,8 +6875,8 @@ export function timestampSub( * Creates functions that work on the backend but do not exist in the SDK yet. * * ```typescript - * // This is the same of the 'sum(Field.of("price"))', if it was not yet implemented in the SDK. - * genericFunction("sum", [Field.of("price")]); + * // This is the same of the 'sum(field("price"))', if it was not yet implemented in the SDK. + * genericFunction("sum", [field("price")]); * ``` * * @param functionName The name of the server function. @@ -6891,7 +6897,7 @@ export function genericFunction( * * ```typescript * // This is the same of the 'eq("price", 10)', if it was not yet implemented in the SDK. - * genericFunction("eq", [Field.of("price"), Constant.of(10)]); + * genericFunction("eq", [field("price"), Constant.of(10)]); * ``` * * @param functionName The name of the server boolean expression. @@ -6912,7 +6918,7 @@ export function genericBooleanExpr( * * ```typescript * // This is the same of the 'eq("price", 10)', if it was not yet implemented in the SDK. - * genericFunction("eq", [Field.of("price"), Constant.of(10)]); + * genericFunction("eq", [field("price"), Constant.of(10)]); * ``` * * @param functionName The name of the server boolean expression. @@ -6982,7 +6988,7 @@ export function orFunction( * ```typescript * // Sort documents by the 'name' field in ascending order * firestore.pipeline().collection("users") - * .sort(ascending(Field.of("name"))); + * .sort(ascending(field("name"))); * ``` * * @param expr The expression to create an ascending ordering for. @@ -7000,7 +7006,7 @@ export function ascending(expr: Expr): Ordering { * ```typescript * // Sort documents by the 'createdAt' field in descending order * firestore.pipeline().collection("users") - * .sort(descending(Field.of("createdAt"))); + * .sort(descending(field("createdAt"))); * ``` * * @param expr The expression to create a descending ordering for. diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index 3bdbcb00d53..9cb7f2207b5 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -36,7 +36,8 @@ import { Field, BooleanExpr, Ordering, - Selectable + Selectable, + field } from './expressions'; import { AddFields, @@ -97,18 +98,18 @@ function isReadableUserData(value: any): value is ReadableUserData { * // Example 1: Select specific fields and rename 'rating' to 'bookRating' * const results1 = await execute(db.pipeline() * .collection("books") - * .select("title", "author", Field.of("rating").as("bookRating"))); + * .select("title", "author", field("rating").as("bookRating"))); * * // Example 2: Filter documents where 'genre' is "Science Fiction" and 'published' is after 1950 * const results2 = await execute(db.pipeline() * .collection("books") - * .where(and(Field.of("genre").eq("Science Fiction"), Field.of("published").gt(1950)))); + * .where(and(field("genre").eq("Science Fiction"), field("published").gt(1950)))); * * // Example 3: Calculate the average rating of books published after 1980 * const results3 = await execute(db.pipeline() * .collection("books") - * .where(Field.of("published").gt(1980)) - * .aggregate(avg(Field.of("rating")).as("averageRating"))); + * .where(field("published").gt(1980)) + * .aggregate(avg(field("rating")).as("averageRating"))); * ``` */ @@ -157,8 +158,8 @@ export class Pipeline implements ProtoSerializable { * ```typescript * firestore.pipeline().collection("books") * .addFields( - * Field.of("rating").as("bookRating"), // Rename 'rating' to 'bookRating' - * add(5, Field.of("quantity")).as("totalCost") // Calculate 'totalCost' + * field("rating").as("bookRating"), // Rename 'rating' to 'bookRating' + * add(5, field("quantity")).as("totalCost") // Calculate 'totalCost' * ); * ``` * @@ -186,21 +187,21 @@ export class Pipeline implements ProtoSerializable { * firestore.pipeline().collection('books') * // removes field 'rating' and 'cost' from the previous stage outputs. * .removeFields( - * Field.of('rating'), + * field('rating'), * 'cost' * ); * ``` * - * @param field The first field to remove. + * @param fieldValue The first field to remove. * @param additionalFields Optional additional fields to remove. * @return A new Pipeline object with this stage appended to the stage list. */ removeFields( - field: Field | string, + fieldValue: Field | string, ...additionalFields: Array ): Pipeline { - const fieldExpressions = [field, ...additionalFields].map(f => - typeof f === 'string' ? Field.of(f) : (f as Field) + const fieldExpressions = [fieldValue, ...additionalFields].map(f => + typeof f === 'string' ? field(f) : (f as Field) ); this.readUserData('removeFields', fieldExpressions); return this._addStage(new RemoveFields(fieldExpressions)); @@ -228,8 +229,8 @@ export class Pipeline implements ProtoSerializable { * firestore.pipeline().collection("books") * .select( * "firstName", - * Field.of("lastName"), - * Field.of("address").toUppercase().as("upperAddress"), + * field("lastName"), + * field("address").toUppercase().as("upperAddress"), * ); * ``` * @@ -273,8 +274,8 @@ export class Pipeline implements ProtoSerializable { * firestore.pipeline().collection("books") * .where( * and( - * gt(Field.of("rating"), 4.0), // Filter for ratings greater than 4.0 - * Field.of("genre").eq("Science Fiction") // Equivalent to gt("genre", "Science Fiction") + * gt(field("rating"), 4.0), // Filter for ratings greater than 4.0 + * field("genre").eq("Science Fiction") // Equivalent to gt("genre", "Science Fiction") * ) * ); * ``` @@ -299,7 +300,7 @@ export class Pipeline implements ProtoSerializable { * ```typescript * // Retrieve the second page of 20 results * firestore.pipeline().collection("books") - * .sort(Field.of("published").descending()) + * .sort(field("published").descending()) * .offset(20) // Skip the first 20 results * .limit(20); // Take the next 20 results * ``` @@ -329,7 +330,7 @@ export class Pipeline implements ProtoSerializable { * ```typescript * // Limit the results to the top 10 highest-rated books * firestore.pipeline().collection("books") - * .sort(Field.of("rating").descending()) + * .sort(field("rating").descending()) * .limit(10); * ``` * @@ -374,7 +375,7 @@ export class Pipeline implements ProtoSerializable { * ```typescript * // Get a list of unique author names in uppercase and genre combinations. * firestore.pipeline().collection("books") - * .distinct(toUppercase(Field.of("author")).as("authorName"), Field.of("genre"), "publishedAt") + * .distinct(toUppercase(field("author")).as("authorName"), field("genre"), "publishedAt") * .select("authorName"); * ``` * @@ -411,7 +412,7 @@ export class Pipeline implements ProtoSerializable { * // Calculate the average rating and the total number of books * firestore.pipeline().collection("books") * .aggregate( - * Field.of("rating").avg().as("averageRating"), + * field("rating").avg().as("averageRating"), * countAll().as("totalBooks") * ); * ``` @@ -449,7 +450,7 @@ export class Pipeline implements ProtoSerializable { * // Calculate the average rating for each genre. * firestore.pipeline().collection("books") * .aggregate({ - * accumulators: [avg(Field.of("rating")).as("avg_rating")] + * accumulators: [avg(field("rating")).as("avg_rating")] * groups: ["genre"] * }); * ``` @@ -542,8 +543,8 @@ export class Pipeline implements ProtoSerializable { * // with the same rating * firestore.pipeline().collection("books") * .sort( - * Ordering.of(Field.of("rating")).descending(), - * Ordering.of(Field.of("title")) // Ascending order is the default + * Ordering.of(field("rating")).descending(), + * Ordering.of(field("title")) // Ascending order is the default * ); * ``` * @@ -597,7 +598,7 @@ export class Pipeline implements ProtoSerializable { * // } * * // Emit parents as document. - * firestore.pipeline().collection('people').replaceWith(Field.of('parents')); + * firestore.pipeline().collection('people').replaceWith(field('parents')); * * // Output * // { @@ -609,8 +610,9 @@ export class Pipeline implements ProtoSerializable { * @param field The {@link Field} field containing the nested map. * @return A new {@code Pipeline} object with this stage appended to the stage list. */ - replaceWith(field: Field | string): Pipeline { - const fieldExpr = typeof field === 'string' ? Field.of(field) : field; + replaceWith(fieldValue: Field | string): Pipeline { + const fieldExpr = + typeof fieldValue === 'string' ? field(fieldValue) : fieldValue; return this._addStage(new Replace(fieldExpr, 'full_replace')); } @@ -714,7 +716,7 @@ export class Pipeline implements ProtoSerializable { * * // Emit a book document for each tag of the book. * firestore.pipeline().collection("books") - * .unnest(Field.of("tags").as('tag'), 'tagIndex'); + * .unnest(field("tags").as('tag'), 'tagIndex'); * * // Output: * // { "title": "The Hitchhiker's Guide to the Galaxy", "tag": "comedy", "tagIndex": 0, ... } @@ -729,7 +731,7 @@ export class Pipeline implements ProtoSerializable { unnest(selectable: Selectable, indexField?: string): Pipeline { this.readUserData('unnest', selectable.expr); - const alias = Field.of(selectable.alias); + const alias = field(selectable.alias); this.readUserData('unnest', alias); return this._addStage(new Unnest(selectable.expr, alias, indexField)); @@ -747,7 +749,7 @@ export class Pipeline implements ProtoSerializable { * ```typescript * // Assume we don't have a built-in "where" stage * firestore.pipeline().collection("books") - * .genericStage("where", [Field.of("published").lt(1900)]) // Custom "where" stage + * .genericStage("where", [field("published").lt(1900)]) // Custom "where" stage * .select("title", "author"); * ``` * @@ -809,7 +811,7 @@ export class Pipeline implements ProtoSerializable { const result = new Map(); for (const selectable of selectables) { if (typeof selectable === 'string') { - result.set(selectable as string, Field.of(selectable)); + result.set(selectable as string, field(selectable)); } else if (selectable instanceof Field) { result.set((selectable as Field).fieldName(), selectable); } else if (selectable instanceof ExprWithAlias) { diff --git a/packages/firestore/src/lite-api/pipeline_impl.ts b/packages/firestore/src/lite-api/pipeline_impl.ts index d80c3cd96eb..047f5636de9 100644 --- a/packages/firestore/src/lite-api/pipeline_impl.ts +++ b/packages/firestore/src/lite-api/pipeline_impl.ts @@ -63,7 +63,7 @@ declare module './reference' { * * ```typescript * const futureResults = await execute(firestore.pipeline().collection("books") - * .where(gt(Field.of("rating"), 4.5)) + * .where(gt(field("rating"), 4.5)) * .select("title", "author", "rating")); * ``` * diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index 99c7f156140..c5e1cbdbfa5 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -35,7 +35,8 @@ import { Expr, Field, BooleanExpr, - Ordering + Ordering, + field } from './expressions'; import { Pipeline } from './pipeline'; import { DocumentReference } from './reference'; @@ -297,9 +298,7 @@ export class FindNearest implements Stage { if (this._distanceField) { // eslint-disable-next-line camelcase - options.distance_field = Field.of(this._distanceField)._toProto( - serializer - ); + options.distance_field = field(this._distanceField)._toProto(serializer); } return { diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index e9e62985c1a..ec9701b8dfa 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -52,7 +52,6 @@ import { endsWith, eq, euclideanDistance, - Field, Firestore, gt, like, @@ -96,7 +95,8 @@ import { manhattanDistance, documentId, logicalMinimum, - xor + xor, + field } from '../util/firebase_export'; import { apiDescribe, withTestCollection } from '../util/helpers'; @@ -337,7 +337,7 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) .select( 'title', @@ -352,19 +352,19 @@ apiDescribe.only('Pipelines', persistence => { array([ 1, 2, - Field.of('genre'), + field('genre'), multiply('rating', 10), - [Field.of('title')], + [field('title')], { - published: Field.of('published') + published: field('published') } ]).as('metadataArray'), map({ - genre: Field.of('genre'), + genre: field('genre'), rating: multiply('rating', 10), - nestedArray: [Field.of('title')], + nestedArray: [field('title')], nestedMap: { - published: Field.of('published') + published: field('published') } }).as('metadata') ) @@ -373,19 +373,19 @@ apiDescribe.only('Pipelines', persistence => { eq('metadataArray', [ 1, 2, - Field.of('genre'), + field('genre'), multiply('rating', 10), - [Field.of('title')], + [field('title')], { - published: Field.of('published') + published: field('published') } ]), eq('metadata', { - genre: Field.of('genre'), + genre: field('genre'), rating: multiply('rating', 10), - nestedArray: [Field.of('title')], + nestedArray: [field('title')], nestedMap: { - published: Field.of('published') + published: field('published') } }) ) @@ -539,7 +539,7 @@ apiDescribe.only('Pipelines', persistence => { .where(eq('awards.hugo', true)) .select( 'title', - Field.of('nestedField.level.1'), + field('nestedField.level.1'), mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') ); @@ -565,7 +565,7 @@ apiDescribe.only('Pipelines', persistence => { .aggregate( countAll().as('count'), avgFunction('rating').as('avgRating'), - Field.of('rating').maximum().as('maxRating') + field('rating').maximum().as('maxRating') ) ); expectResults(snapshot, { count: 2, avgRating: 4.4, maxRating: 4.6 }); @@ -589,13 +589,13 @@ apiDescribe.only('Pipelines', persistence => { const snapshot = await execute( randomCol .pipeline() - .where(lt(Field.of('published'), 1984)) + .where(lt(field('published'), 1984)) .aggregate({ accumulators: [avgFunction('rating').as('avgRating')], groups: ['genre'] }) .where(gt('avgRating', 4.3)) - .sort(Field.of('avgRating').descending()) + .sort(field('avgRating').descending()) ); expectResults( snapshot, @@ -611,8 +611,8 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .aggregate( countAll().as('count'), - Field.of('rating').maximum().as('maxRating'), - Field.of('published').minimum().as('minPublished') + field('rating').maximum().as('maxRating'), + field('published').minimum().as('minPublished') ) ); expectResults(snapshot, { @@ -626,7 +626,7 @@ apiDescribe.only('Pipelines', persistence => { let snapshot = await execute( randomCol .pipeline() - .aggregate(countIf(Field.of('rating').gt(4.3)).as('count')) + .aggregate(countIf(field('rating').gt(4.3)).as('count')) ); const expectedResults = { count: 3 @@ -636,7 +636,7 @@ apiDescribe.only('Pipelines', persistence => { snapshot = await execute( randomCol .pipeline() - .aggregate(Field.of('rating').gt(4.3).countIf().as('count')) + .aggregate(field('rating').gt(4.3).countIf().as('count')) ); expectResults(snapshot, expectedResults); }); @@ -648,7 +648,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .distinct('genre', 'author') - .sort(Field.of('genre').ascending(), Field.of('author').ascending()) + .sort(field('genre').ascending(), field('author').ascending()) ); expectResults( snapshot, @@ -673,7 +673,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .select('title', 'author') - .sort(Field.of('author').ascending()) + .sort(field('author').ascending()) ); expectResults( snapshot, @@ -705,7 +705,7 @@ apiDescribe.only('Pipelines', persistence => { .collection(randomCol.path) .select('title', 'author') .addFields(Constant.of('bar').as('foo')) - .sort(Field.of('author').ascending()) + .sort(field('author').ascending()) ); expectResults( snapshot, @@ -758,9 +758,9 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .select('title', 'author') - .sort(Field.of('author').ascending()) - .removeFields(Field.of('author')) - .sort(Field.of('author').ascending()) + .sort(field('author').ascending()) + .removeFields(field('author')) + .sort(field('author').ascending()) ); expectResults( snapshot, @@ -858,7 +858,7 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) - .sort(Field.of('author').ascending()) + .sort(field('author').ascending()) .offset(5) .limit(3) .select('title', 'author') @@ -880,13 +880,13 @@ apiDescribe.only('Pipelines', persistence => { .collection(randomCol.path) .genericStage('select', [ { - title: Field.of('title'), + title: field('title'), metadata: { - 'author': Field.of('author') + 'author': field('author') } } ]) - .sort(Field.of('author').ascending()) + .sort(field('author').ascending()) .limit(1) ); expectResults(snapshot, { @@ -902,12 +902,12 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) - .sort(Field.of('author').ascending()) + .sort(field('author').ascending()) .limit(1) .select('title', 'author') .genericStage('add_fields', [ { - display: Field.of('title').strConcat(' - ', Field.of('author')) + display: field('title').strConcat(' - ', field('author')) } ]) ); @@ -924,7 +924,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .select('title', 'author') - .genericStage('where', [Field.of('author').eq('Douglas Adams')]) + .genericStage('where', [field('author').eq('Douglas Adams')]) ); expectResults(snapshot, { title: "The Hitchhiker's Guide to the Galaxy", @@ -941,7 +941,7 @@ apiDescribe.only('Pipelines', persistence => { .genericStage('sort', [ { direction: 'ascending', - expression: Field.of('author') + expression: field('author') } ]) .genericStage('offset', [3]) @@ -960,7 +960,7 @@ apiDescribe.only('Pipelines', persistence => { .collection(randomCol.path) .select('title', 'author', 'rating') .genericStage('aggregate', [ - { averageRating: Field.of('rating').avg() }, + { averageRating: field('rating').avg() }, {} ]) ); @@ -975,8 +975,8 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .select('title', 'author', 'rating') - .genericStage('distinct', [{ rating: Field.of('rating') }]) - .sort(Field.of('rating').descending()) + .genericStage('distinct', [{ rating: field('rating') }]) + .sort(field('rating').descending()) ); expectResults( snapshot, @@ -1055,7 +1055,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .union(randomCol.pipeline()) - .sort(Field.of(documentId()).ascending()) + .sort(field(documentId()).ascending()) ); expectResults( snapshot, @@ -1089,7 +1089,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) - .unnest(Field.of('tags').as('tag')) + .unnest(field('tags').as('tag')) ); expectResults( snapshot, @@ -1206,11 +1206,11 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .select( 'title', - logicalMaximum(Constant.of(1960), Field.of('published'), 1961).as( + logicalMaximum(Constant.of(1960), field('published'), 1961).as( 'published-safe' ) ) - .sort(Field.of('title').ascending()) + .sort(field('title').ascending()) .limit(3) ); expectResults( @@ -1227,11 +1227,11 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .select( 'title', - logicalMinimum(Constant.of(1960), Field.of('published'), 1961).as( + logicalMinimum(Constant.of(1960), field('published'), 1961).as( 'published-safe' ) ) - .sort(Field.of('title').ascending()) + .sort(field('title').ascending()) .limit(3) ); expectResults( @@ -1249,12 +1249,12 @@ apiDescribe.only('Pipelines', persistence => { .select( 'title', cond( - lt(Field.of('published'), 1960), + lt(field('published'), 1960), Constant.of(1960), - Field.of('published') + field('published') ).as('published-safe') ) - .sort(Field.of('title').ascending()) + .sort(field('title').ascending()) .limit(3) ); expectResults( @@ -1324,7 +1324,7 @@ apiDescribe.only('Pipelines', persistence => { const snapshot = await execute( randomCol .pipeline() - .where(Field.of('tags').arrayContainsAll('adventure', 'magic')) + .where(field('tags').arrayContainsAll('adventure', 'magic')) .select('title') ); expectResults(snapshot, { title: 'The Lord of the Rings' }); @@ -1334,7 +1334,7 @@ apiDescribe.only('Pipelines', persistence => { const snapshot = await execute( randomCol .pipeline() - .select(Field.of('tags').arrayLength().as('tagsCount')) + .select(field('tags').arrayLength().as('tagsCount')) .where(eq('tagsCount', 3)) ); expect(snapshot.results.length).to.equal(10); @@ -1345,9 +1345,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .select( - Field.of('author') - .strConcat(' - ', Field.of('title')) - .as('bookInfo') + field('author').strConcat(' - ', field('title')).as('bookInfo') ) .limit(1) ); @@ -1362,7 +1360,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .where(startsWith('title', 'The')) .select('title') - .sort(Field.of('title').ascending()) + .sort(field('title').ascending()) ); expectResults( snapshot, @@ -1379,7 +1377,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .where(endsWith('title', 'y')) .select('title') - .sort(Field.of('title').descending()) + .sort(field('title').descending()) ); expectResults( snapshot, @@ -1392,12 +1390,9 @@ apiDescribe.only('Pipelines', persistence => { const snapshot = await execute( randomCol .pipeline() - .select( - Field.of('title').charLength().as('titleLength'), - Field.of('title') - ) + .select(field('title').charLength().as('titleLength'), field('title')) .where(gt('titleLength', 20)) - .sort(Field.of('title').ascending()) + .sort(field('title').ascending()) ); expectResults( @@ -1450,10 +1445,10 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .select( - add(Field.of('rating'), 1).as('ratingPlusOne'), - subtract(Field.of('published'), 1900).as('yearsSince1900'), - Field.of('rating').multiply(10).as('ratingTimesTen'), - Field.of('rating').divide(2).as('ratingDividedByTwo'), + add(field('rating'), 1).as('ratingPlusOne'), + subtract(field('published'), 1900).as('yearsSince1900'), + field('rating').multiply(10).as('ratingTimesTen'), + field('rating').divide(2).as('ratingDividedByTwo'), multiply('rating', 10, 2).as('ratingTimes20'), add('rating', 1, 2).as('ratingPlus3') ) @@ -1476,12 +1471,12 @@ apiDescribe.only('Pipelines', persistence => { .where( andFunction( gt('rating', 4.2), - lte(Field.of('rating'), 4.5), + lte(field('rating'), 4.5), neq('genre', 'Science Fiction') ) ) .select('rating', 'title') - .sort(Field.of('title').ascending()) + .sort(field('title').ascending()) ); expectResults( snapshot, @@ -1505,7 +1500,7 @@ apiDescribe.only('Pipelines', persistence => { ) ) .select('title') - .sort(Field.of('title').ascending()) + .sort(field('title').ascending()) ); expectResults( snapshot, @@ -1519,7 +1514,7 @@ apiDescribe.only('Pipelines', persistence => { let snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) .select( isNull('rating').as('ratingIsNull'), @@ -1546,18 +1541,18 @@ apiDescribe.only('Pipelines', persistence => { snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) .select( - Field.of('rating').isNull().as('ratingIsNull'), - Field.of('rating').isNan().as('ratingIsNaN'), + field('rating').isNull().as('ratingIsNull'), + field('rating').isNan().as('ratingIsNaN'), arrayOffset('title', 0).isError().as('isError'), arrayOffset('title', 0) .ifError(Constant.of('was error')) .as('ifError'), - Field.of('foo').isAbsent().as('isAbsent'), - Field.of('title').isNotNull().as('titleIsNotNull'), - Field.of('cost').isNotNan().as('costIsNotNan') + field('foo').isAbsent().as('isAbsent'), + field('title').isNotNull().as('titleIsNotNull'), + field('cost').isNotNan().as('costIsNotNan') ) ); expectResults(snapshot, { @@ -1575,11 +1570,11 @@ apiDescribe.only('Pipelines', persistence => { const snapshot = await execute( randomCol .pipeline() - .sort(Field.of('published').descending()) + .sort(field('published').descending()) .select( - Field.of('awards').mapGet('hugo').as('hugoAward'), - Field.of('awards').mapGet('others').as('others'), - Field.of('title') + field('awards').mapGet('hugo').as('hugoAward'), + field('awards').mapGet('others').as('others'), + field('title') ) .where(eq('hugoAward', true)) ); @@ -1676,7 +1671,7 @@ apiDescribe.only('Pipelines', persistence => { .where(eq('awards.hugo', true)) .select( 'title', - Field.of('nestedField.level.1'), + field('nestedField.level.1'), mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') ) ); @@ -1699,7 +1694,7 @@ apiDescribe.only('Pipelines', persistence => { .sort(descending('rating')) .limit(1) .select( - genericFunction('add', [Field.of('rating'), Constant.of(1)]).as( + genericFunction('add', [field('rating'), Constant.of(1)]).as( 'rating' ) ) @@ -1715,9 +1710,9 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .where( genericBooleanExpr('and', [ - Field.of('rating').gt(0), - Field.of('title').charLength().lt(5), - Field.of('tags').arrayContains('propaganda') + field('rating').gt(0), + field('title').charLength().lt(5), + field('tags').arrayContains('propaganda') ]) ) .select('title') @@ -1733,7 +1728,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .where( genericBooleanExpr('array_contains_any', [ - Field.of('tags'), + field('tags'), ['politics'] ]) ) @@ -1750,7 +1745,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .aggregate( genericAggregateFunction('count_if', [ - Field.of('rating').gte(4.5) + field('rating').gte(4.5) ]).as('countOfBest') ) ); @@ -1764,7 +1759,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .sort( - genericFunction('char_length', [Field.of('title')]).ascending(), + genericFunction('char_length', [field('title')]).ascending(), descending('__name__') ) .limit(3) @@ -1943,9 +1938,9 @@ apiDescribe.only('Pipelines', persistence => { let snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) - .select(documentIdFunction(Field.of('__path__')).as('docId')) + .select(documentIdFunction(field('__path__')).as('docId')) ); expectResults(snapshot, { docId: 'book4' @@ -1953,9 +1948,9 @@ apiDescribe.only('Pipelines', persistence => { snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) - .select(Field.of('__path__').documentId().as('docId')) + .select(field('__path__').documentId().as('docId')) ); expectResults(snapshot, { docId: 'book4' @@ -1966,7 +1961,7 @@ apiDescribe.only('Pipelines', persistence => { let snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) .select(substr('title', 9, 2).as('of')) ); @@ -1976,9 +1971,9 @@ apiDescribe.only('Pipelines', persistence => { snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) - .select(Field.of('title').substr(9, 2).as('of')) + .select(field('title').substr(9, 2).as('of')) ); expectResults(snapshot, { of: 'of' @@ -1989,7 +1984,7 @@ apiDescribe.only('Pipelines', persistence => { let snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) .select(substr('title', 9).as('of')) ); @@ -1999,9 +1994,9 @@ apiDescribe.only('Pipelines', persistence => { snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) - .select(Field.of('title').substr(9).as('of')) + .select(field('title').substr(9).as('of')) ); expectResults(snapshot, { of: 'of the Rings' @@ -2013,8 +2008,8 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .select( - Field.of('tags') - .arrayConcat(['newTag1', 'newTag2'], Field.of('tags'), [null]) + field('tags') + .arrayConcat(['newTag1', 'newTag2'], field('tags'), [null]) .as('modifiedTags') ) .limit(1) @@ -2038,7 +2033,7 @@ apiDescribe.only('Pipelines', persistence => { const snapshot = await execute( randomCol .pipeline() - .select(Field.of('title').toLower().as('lowercaseTitle')) + .select(field('title').toLower().as('lowercaseTitle')) .limit(1) ); expectResults(snapshot, { @@ -2050,7 +2045,7 @@ apiDescribe.only('Pipelines', persistence => { const snapshot = await execute( randomCol .pipeline() - .select(Field.of('author').toUpper().as('uppercaseAuthor')) + .select(field('author').toUpper().as('uppercaseAuthor')) .limit(1) ); expectResults(snapshot, { uppercaseAuthor: 'DOUGLAS ADAMS' }); @@ -2066,8 +2061,8 @@ apiDescribe.only('Pipelines', persistence => { ) ) .select( - Field.of('spacedTitle').trim().as('trimmedTitle'), - Field.of('spacedTitle') + field('spacedTitle').trim().as('trimmedTitle'), + field('spacedTitle') ) .limit(1) ); @@ -2094,7 +2089,7 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) .select(array([1, 2, 3, 4]).as('metadata')) ); @@ -2109,10 +2104,10 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) .select( - array([1, 2, Field.of('genre'), multiply('rating', 10)]).as( + array([1, 2, field('genre'), multiply('rating', 10)]).as( 'metadata' ) ) @@ -2127,7 +2122,7 @@ apiDescribe.only('Pipelines', persistence => { let snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(3) .select(arrayOffset('tags', 0).as('firstTag')) ); @@ -2147,9 +2142,9 @@ apiDescribe.only('Pipelines', persistence => { snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(3) - .select(Field.of('tags').arrayOffset(0).as('firstTag')) + .select(field('tags').arrayOffset(0).as('firstTag')) ); expectResults(snapshot, ...expectedResults); }); @@ -2160,7 +2155,7 @@ apiDescribe.only('Pipelines', persistence => { const snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) .select(currentContext().as('currentContext')) ); @@ -2174,7 +2169,7 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) .select( map({ @@ -2196,12 +2191,12 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) .select( map({ - genre: Field.of('genre'), - rating: Field.of('rating').multiply(10) + genre: field('genre'), + rating: field('rating').multiply(10) }).as('metadata') ) ); @@ -2219,7 +2214,7 @@ apiDescribe.only('Pipelines', persistence => { let snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) .select(mapRemove('awards', 'hugo').as('awards')) ); @@ -2229,9 +2224,9 @@ apiDescribe.only('Pipelines', persistence => { snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) - .select(Field.of('awards').mapRemove('hugo').as('awards')) + .select(field('awards').mapRemove('hugo').as('awards')) ); expectResults(snapshot, { awards: { nebula: false } @@ -2242,7 +2237,7 @@ apiDescribe.only('Pipelines', persistence => { let snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) .select(mapMerge('awards', { fakeAward: true }).as('awards')) ); @@ -2252,9 +2247,9 @@ apiDescribe.only('Pipelines', persistence => { snapshot = await execute( randomCol .pipeline() - .sort(Field.of('rating').descending()) + .sort(field('rating').descending()) .limit(1) - .select(Field.of('awards').mapMerge({ fakeAward: true }).as('awards')) + .select(field('awards').mapMerge({ fakeAward: true }).as('awards')) ); expectResults(snapshot, { awards: { nebula: false, hugo: false, fakeAward: true } @@ -2311,10 +2306,7 @@ apiDescribe.only('Pipelines', persistence => { const pipeline = randomCol .pipeline() .select('title', 'rating', '__name__') - .sort( - Field.of('rating').descending(), - Field.of('__name__').ascending() - ); + .sort(field('rating').descending(), field('__name__').ascending()); let snapshot = await execute(pipeline.limit(pageSize)); expectResults( @@ -2330,10 +2322,10 @@ apiDescribe.only('Pipelines', persistence => { .where( orFunction( andFunction( - Field.of('rating').eq(lastDoc.get('rating')), - Field.of('__path__').gt(lastDoc.ref?.id) + field('rating').eq(lastDoc.get('rating')), + field('__path__').gt(lastDoc.ref?.id) ), - Field.of('rating').lt(lastDoc.get('rating')) + field('rating').lt(lastDoc.get('rating')) ) ) .limit(pageSize) @@ -2354,8 +2346,8 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .select('title', 'rating', secondFilterField) .sort( - Field.of('rating').descending(), - Field.of(secondFilterField).ascending() + field('rating').descending(), + field(secondFilterField).ascending() ); const pageSize = 2; diff --git a/packages/firestore/test/integration/api/query_to_pipeline.test.ts b/packages/firestore/test/integration/api/query_to_pipeline.test.ts index 5a54e20c805..90e27e6ed88 100644 --- a/packages/firestore/test/integration/api/query_to_pipeline.test.ts +++ b/packages/firestore/test/integration/api/query_to_pipeline.test.ts @@ -55,7 +55,7 @@ setLogLevel('debug'); // This is the Query integration tests from the lite API (no cache support) // with some additional test cases added for more complete coverage. -apiDescribe.only('Query to Pipeline', persistence => { +apiDescribe('Query to Pipeline', persistence => { addEqualityMatcher(); function verifyResults( From d31cf63e54a442c251b17152f922cddc7f77a851 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 28 Feb 2025 15:12:27 -0700 Subject: [PATCH 45/75] Add missing export PipelineSnaphsot --- packages/firestore/lite/pipelines/pipelines.ts | 2 +- packages/firestore/src/api_pipelines.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index a3b6358d4d4..c1c98fd0cdd 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -50,7 +50,7 @@ export type { export { PipelineSource } from '../../src/lite-api/pipeline-source'; -export { PipelineResult } from '../../src/lite-api/pipeline-result'; +export { PipelineResult, PipelineSnapshot } from '../../src/lite-api/pipeline-result'; export { Pipeline } from '../../src/lite-api/pipeline'; diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index ec189c09b1c..196bddf7272 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -17,7 +17,7 @@ export { PipelineSource } from './lite-api/pipeline-source'; -export { PipelineResult } from './lite-api/pipeline-result'; +export { PipelineResult, PipelineSnapshot } from './lite-api/pipeline-result'; export { Pipeline } from './api/pipeline'; From 58d15c2425bba0b8d6c538a822462f56e5468383 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 28 Feb 2025 15:31:04 -0700 Subject: [PATCH 46/75] Replace Constant.of() with constant() --- .../firestore/lite/pipelines/pipelines.ts | 6 +- packages/firestore/src/api_pipelines.ts | 1 + .../firestore/src/lite-api/expressions.ts | 322 +++++++++--------- packages/firestore/src/lite-api/pipeline.ts | 6 +- .../test/integration/api/pipeline.test.ts | 89 ++--- 5 files changed, 218 insertions(+), 206 deletions(-) diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index c1c98fd0cdd..b1b8a67dd9e 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -50,7 +50,10 @@ export type { export { PipelineSource } from '../../src/lite-api/pipeline-source'; -export { PipelineResult, PipelineSnapshot } from '../../src/lite-api/pipeline-result'; +export { + PipelineResult, + PipelineSnapshot +} from '../../src/lite-api/pipeline-result'; export { Pipeline } from '../../src/lite-api/pipeline'; @@ -77,6 +80,7 @@ export { export { field, + constant, add, subtract, multiply, diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index 196bddf7272..996f6c74024 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -44,6 +44,7 @@ export { export { field, + constant, add, subtract, multiply, diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index ee283b9d511..96916052fbb 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -77,7 +77,7 @@ function valueToDefaultExpr(value: any): Expr { } else if (value instanceof Array) { return array(value); } else { - return Constant.of(value); + return constant(value); } } /** @@ -92,7 +92,7 @@ function vectorToExpr(value: VectorValue | number[] | Expr): Expr { if (value instanceof Expr) { return value; } else { - return Constant.vector(value); + return constantVector(value); } } @@ -366,7 +366,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'quantity' field is less than or equal to 20 - * field("quantity").lte(Constant.of(20)); + * field("quantity").lte(constant(20)); * ``` * * @param other The expression to compare for less than or equal to. @@ -943,7 +943,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Combine the 'firstName', " ", and 'lastName' fields into a single string - * field("firstName").strConcat(Constant.of(" "), field("lastName")); + * field("firstName").strConcat(constant(" "), field("lastName")); * ``` * * @param secondString The additional expression or string literal to concatenate. @@ -1071,7 +1071,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @return A new `Expr` representing the value associated with the given key in the map. */ mapGet(subfield: string): FunctionExpr { - return new FunctionExpr('map_get', [this, Constant.of(subfield)]); + return new FunctionExpr('map_get', [this, constant(subfield)]); } /** @@ -1962,7 +1962,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ``` * // Removes the key 'baz' from the input map. - * map({foo: 'bar', baz: true}).mapRemove(Constant.of('baz')); + * map({foo: 'bar', baz: true}).mapRemove(constant('baz')); * ``` * * @param keyExpr An expression that produces the name of the key to remove from the input map. @@ -2302,10 +2302,10 @@ export function field(nameOrPath: string | FieldPath): Field { * * ```typescript * // Create a Constant instance for the number 10 - * const ten = Constant.of(10); + * const ten = constant(10); * * // Create a Constant instance for the string "hello" - * const hello = Constant.of("hello"); + * const hello = constant("hello"); * ``` */ export class Constant extends Expr { @@ -2313,147 +2313,14 @@ export class Constant extends Expr { private _protoValue?: ProtoValue; - private constructor(private value: any) { - super(); - } - - /** - * Creates a `Constant` instance for a number value. - * - * @param value The number value. - * @return A new `Constant` instance. - */ - static of(value: number): Constant; - - /** - * Creates a `Constant` instance for a string value. - * - * @param value The string value. - * @return A new `Constant` instance. - */ - static of(value: string): Constant; - - /** - * Creates a `Constant` instance for a boolean value. - * - * @param value The boolean value. - * @return A new `Constant` instance. - */ - static of(value: boolean): Constant; - - /** - * Creates a `Constant` instance for a null value. - * - * @param value The null value. - * @return A new `Constant` instance. - */ - static of(value: null): Constant; - - /** - * Creates a `Constant` instance for an undefined value. - * @private - * @internal - * - * @param value The undefined value. - * @return A new `Constant` instance. - */ - static of(value: undefined): Constant; - - /** - * Creates a `Constant` instance for a GeoPoint value. - * - * @param value The GeoPoint value. - * @return A new `Constant` instance. - */ - static of(value: GeoPoint): Constant; - - /** - * Creates a `Constant` instance for a Timestamp value. - * - * @param value The Timestamp value. - * @return A new `Constant` instance. - */ - static of(value: Timestamp): Constant; - - /** - * Creates a `Constant` instance for a Date value. - * - * @param value The Date value. - * @return A new `Constant` instance. - */ - static of(value: Date): Constant; - - /** - * Creates a `Constant` instance for a Bytes value. - * - * @param value The Bytes value. - * @return A new `Constant` instance. - */ - static of(value: Bytes): Constant; - - /** - * Creates a `Constant` instance for a DocumentReference value. - * - * @param value The DocumentReference value. - * @return A new `Constant` instance. - */ - static of(value: DocumentReference): Constant; - /** - * Creates a `Constant` instance for a Firestore proto value. - * For internal use only. * @private * @internal - * @param value The Firestore proto value. - * @return A new `Constant` instance. - */ - static of(value: ProtoValue): Constant; - - /** - * Creates a `Constant` instance for an array value. - * - * @param value The array value. - * @return A new `Constant` instance. - */ - static of(value: any[]): Constant; - - /** - * Creates a `Constant` instance for a map value. - * - * @param value The map value. - * @return A new `Constant` instance. - */ - static of(value: Record): Constant; - - /** - * Creates a `Constant` instance for a VectorValue value. - * - * @param value The VectorValue value. - * @return A new `Constant` instance. - */ - static of(value: VectorValue): Constant; - - static of(value: any): Constant { - return new Constant(value); - } - - /** - * Creates a `Constant` instance for a VectorValue value. - * - * ```typescript - * // Create a Constant instance for a vector value - * const vectorConstant = Constant.ofVector([1, 2, 3]); - * ``` - * - * @param value The VectorValue value. - * @return A new `Constant` instance. + * @hideconstructor + * @param value The value of the constant. */ - static vector(value: number[] | VectorValue): Constant { - if (value instanceof VectorValue) { - return new Constant(value); - } else { - return new Constant(new VectorValue(value as number[])); - } + constructor(private value: any) { + super(); } /** @@ -2499,6 +2366,145 @@ export class Constant extends Expr { } } +/** + * Creates a `Constant` instance for a number value. + * + * @param value The number value. + * @return A new `Constant` instance. + */ +export function constant(value: number): Constant; + +/** + * Creates a `Constant` instance for a string value. + * + * @param value The string value. + * @return A new `Constant` instance. + */ +export function constant(value: string): Constant; + +/** + * Creates a `Constant` instance for a boolean value. + * + * @param value The boolean value. + * @return A new `Constant` instance. + */ +export function constant(value: boolean): Constant; + +/** + * Creates a `Constant` instance for a null value. + * + * @param value The null value. + * @return A new `Constant` instance. + */ +export function constant(value: null): Constant; + +/** + * Creates a `Constant` instance for an undefined value. + * @private + * @internal + * + * @param value The undefined value. + * @return A new `Constant` instance. + */ +export function constant(value: undefined): Constant; + +/** + * Creates a `Constant` instance for a GeoPoint value. + * + * @param value The GeoPoint value. + * @return A new `Constant` instance. + */ +export function constant(value: GeoPoint): Constant; + +/** + * Creates a `Constant` instance for a Timestamp value. + * + * @param value The Timestamp value. + * @return A new `Constant` instance. + */ +export function constant(value: Timestamp): Constant; + +/** + * Creates a `Constant` instance for a Date value. + * + * @param value The Date value. + * @return A new `Constant` instance. + */ +export function constant(value: Date): Constant; + +/** + * Creates a `Constant` instance for a Bytes value. + * + * @param value The Bytes value. + * @return A new `Constant` instance. + */ +export function constant(value: Bytes): Constant; + +/** + * Creates a `Constant` instance for a DocumentReference value. + * + * @param value The DocumentReference value. + * @return A new `Constant` instance. + */ +export function constant(value: DocumentReference): Constant; + +/** + * Creates a `Constant` instance for a Firestore proto value. + * For internal use only. + * @private + * @internal + * @param value The Firestore proto value. + * @return A new `Constant` instance. + */ +export function constant(value: ProtoValue): Constant; + +/** + * Creates a `Constant` instance for an array value. + * + * @param value The array value. + * @return A new `Constant` instance. + */ +export function constant(value: any[]): Constant; + +/** + * Creates a `Constant` instance for a map value. + * + * @param value The map value. + * @return A new `Constant` instance. + */ +export function constant(value: Record): Constant; + +/** + * Creates a `Constant` instance for a VectorValue value. + * + * @param value The VectorValue value. + * @return A new `Constant` instance. + */ +export function constant(value: VectorValue): Constant; + +export function constant(value: any): Constant { + return new Constant(value); +} + +/** + * Creates a `Constant` instance for a VectorValue value. + * + * ```typescript + * // Create a Constant instance for a vector value + * const vectorConstant = constantVector([1, 2, 3]); + * ``` + * + * @param value The VectorValue value. + * @return A new `Constant` instance. + */ +export function constantVector(value: number[] | VectorValue): Constant { + if (value instanceof VectorValue) { + return new Constant(value); + } else { + return new Constant(new VectorValue(value as number[])); + } +} + /** * Internal only * @internal @@ -3338,7 +3344,7 @@ export function mapRemove(mapExpr: Expr, key: string): FunctionExpr; * * ``` * // Removes the key 'city' field from the map in the address field of the input document. - * mapRemove('address', Constant.of('city')); + * mapRemove('address', constant('city')); * ``` * * @param mapField The name of a field containing a map value. @@ -3352,7 +3358,7 @@ export function mapRemove(mapField: string, keyExpr: Expr): FunctionExpr; * * ``` * // Removes the key 'baz' from the input map. - * mapRemove(map({foo: 'bar', baz: true}), Constant.of('baz')); + * mapRemove(map({foo: 'bar', baz: true}), constant('baz')); * ``` * * @param mapExpr An expression return a map value. @@ -3851,7 +3857,7 @@ export function map(elements: Record): FunctionExpr { for (const key in elements) { if (Object.prototype.hasOwnProperty.call(elements, key)) { const value = elements[key]; - result.push(Constant.of(key)); + result.push(constant(key)); result.push(valueToDefaultExpr(value)); } } @@ -3862,7 +3868,7 @@ export function map(elements: Record): FunctionExpr { * Internal use only * Converts a plainObject to a mapValue in the proto representation, * rather than a functionValue+map that is the result of the map(...) function. - * This behaves different than Constant.of(plainObject) because it + * This behaves different than constant(plainObject) because it * traverses the input object, converts values in the object to expressions, * and calls _readUserData on each of these expressions. * @private @@ -4512,7 +4518,7 @@ export function arrayContainsAny( * * ```typescript * // Check if the "tags" array contains all of the values: "SciFi", "Adventure", and the value from field "tag1" - * arrayContainsAll(field("tags"), [field("tag1"), Constant.of("SciFi"), Constant.of("Adventure")]); + * arrayContainsAll(field("tags"), [field("tag1"), constant("SciFi"), constant("Adventure")]); * ``` * * @param array The array expression to check. @@ -4604,7 +4610,7 @@ export function arrayLength(array: Expr): FunctionExpr { * * ```typescript * // Check if the 'category' field is either "Electronics" or value of field 'primaryType' - * eqAny(field("category"), [Constant.of("Electronics"), field("primaryType")]); + * eqAny(field("category"), [constant("Electronics"), field("primaryType")]); * ``` * * @param element The expression to compare. @@ -4638,7 +4644,7 @@ export function eqAny(element: Expr, others: any[]): BooleanExpr; * * ```typescript * // Check if the 'category' field is either "Electronics" or value of field 'primaryType' - * eqAny("category", [Constant.of("Electronics"), field("primaryType")]); + * eqAny("category", [constant("Electronics"), field("primaryType")]); * ``` * * @param element The field to compare. @@ -4677,7 +4683,7 @@ export function eqAny(element: Expr | string, others: any[]): BooleanExpr { * * ```typescript * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * notEqAny(field("status"), [Constant.of("pending"), field("rejectedStatus")]); + * notEqAny(field("status"), [constant("pending"), field("rejectedStatus")]); * ``` * * @param element The expression to compare. @@ -4711,7 +4717,7 @@ export function notEqAny(element: Expr, others: any[]): BooleanExpr; * * ```typescript * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * notEqAny("status", [Constant.of("pending"), field("rejectedStatus")]); + * notEqAny("status", [constant("pending"), field("rejectedStatus")]); * ``` * * @param element The field name to compare. @@ -4779,7 +4785,7 @@ export function xor( * ```typescript * // If 'age' is greater than 18, return "Adult"; otherwise, return "Minor". * cond( - * gt("age", 18), Constant.of("Adult"), Constant.of("Minor")); + * gt("age", 18), constant("Adult"), constant("Minor")); * ``` * * @param condition The condition to evaluate. @@ -5654,7 +5660,7 @@ export function endsWith(expr: Expr, suffix: string): BooleanExpr; * * ```typescript * // Check if the result of concatenating 'firstName' and 'lastName' fields ends with "Jr." - * endsWith(field("fullName"), Constant.of("Jr.")); + * endsWith(field("fullName"), constant("Jr.")); * ``` * * @param expr The expression to check. @@ -6897,7 +6903,7 @@ export function genericFunction( * * ```typescript * // This is the same of the 'eq("price", 10)', if it was not yet implemented in the SDK. - * genericFunction("eq", [field("price"), Constant.of(10)]); + * genericFunction("eq", [field("price"), constant(10)]); * ``` * * @param functionName The name of the server boolean expression. @@ -6918,7 +6924,7 @@ export function genericBooleanExpr( * * ```typescript * // This is the same of the 'eq("price", 10)', if it was not yet implemented in the SDK. - * genericFunction("eq", [field("price"), Constant.of(10)]); + * genericFunction("eq", [field("price"), constant(10)]); * ``` * * @param functionName The name of the server boolean expression. diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index 9cb7f2207b5..a655ab153b8 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -30,14 +30,14 @@ import { _mapValue, AggregateFunction, AggregateWithAlias, - Constant, Expr, ExprWithAlias, Field, BooleanExpr, Ordering, Selectable, - field + field, + constant } from './expressions'; import { AddFields, @@ -771,7 +771,7 @@ export class Pipeline implements ProtoSerializable { } else if (isPlainObject(value)) { return _mapValue(value); } else { - return Constant.of(value); + return constant(value); } }); diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index ec9701b8dfa..25940faf171 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -18,6 +18,7 @@ import { expect, use } from 'chai'; import chaiAsPromised from 'chai-as-promised'; +import { constantVector } from '../../../src/lite-api/expressions'; import { PipelineSnapshot } from '../../../src/lite-api/pipeline-result'; import { addEqualityMatcher } from '../../util/equality_matcher'; import { Deferred } from '../../util/promise'; @@ -43,7 +44,6 @@ import { arrayContainsAny, avgFunction, CollectionReference, - Constant, cosineDistance, countAll, doc, @@ -96,7 +96,8 @@ import { documentId, logicalMinimum, xor, - field + field, + constant } from '../util/firebase_export'; import { apiDescribe, withTestCollection } from '../util/helpers'; @@ -427,19 +428,19 @@ apiDescribe.only('Pipelines', persistence => { const refDate = new Date(); const refTimestamp = Timestamp.now(); const constants = [ - Constant.of(1).as('number'), - Constant.of('a string').as('string'), - Constant.of(true).as('boolean'), - Constant.of(null).as('null'), - Constant.of(new GeoPoint(0.1, 0.2)).as('geoPoint'), - Constant.of(refTimestamp).as('timestamp'), - Constant.of(refDate).as('date'), - Constant.of( + constant(1).as('number'), + constant('a string').as('string'), + constant(true).as('boolean'), + constant(null).as('null'), + constant(new GeoPoint(0.1, 0.2)).as('geoPoint'), + constant(refTimestamp).as('timestamp'), + constant(refDate).as('date'), + constant( Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])) ).as('bytes'), - Constant.of(doc(firestore, 'foo', 'bar')).as('documentReference'), - Constant.of(vector([1, 2, 3])).as('vectorValue'), - Constant.of({ + constant(doc(firestore, 'foo', 'bar')).as('documentReference'), + constant(vector([1, 2, 3])).as('vectorValue'), + constant({ 'number': 1, 'string': 'a string', 'boolean': true, @@ -458,7 +459,7 @@ apiDescribe.only('Pipelines', persistence => { }, 'array': [1, 'c string'] }).as('map'), - Constant.of([ + constant([ 1, 'a string', true, @@ -704,7 +705,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .select('title', 'author') - .addFields(Constant.of('bar').as('foo')) + .addFields(constant('bar').as('foo')) .sort(field('author').ascending()) ); expectResults( @@ -1206,7 +1207,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .select( 'title', - logicalMaximum(Constant.of(1960), field('published'), 1961).as( + logicalMaximum(constant(1960), field('published'), 1961).as( 'published-safe' ) ) @@ -1227,7 +1228,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .select( 'title', - logicalMinimum(Constant.of(1960), field('published'), 1961).as( + logicalMinimum(constant(1960), field('published'), 1961).as( 'published-safe' ) ) @@ -1250,7 +1251,7 @@ apiDescribe.only('Pipelines', persistence => { 'title', cond( lt(field('published'), 1960), - Constant.of(1960), + constant(1960), field('published') ).as('published-safe') ) @@ -1520,7 +1521,7 @@ apiDescribe.only('Pipelines', persistence => { isNull('rating').as('ratingIsNull'), isNan('rating').as('ratingIsNaN'), isError(arrayOffset('title', 0)).as('isError'), - ifError(arrayOffset('title', 0), Constant.of('was error')).as( + ifError(arrayOffset('title', 0), constant('was error')).as( 'ifError' ), isAbsent('foo').as('isAbsent'), @@ -1548,7 +1549,7 @@ apiDescribe.only('Pipelines', persistence => { field('rating').isNan().as('ratingIsNaN'), arrayOffset('title', 0).isError().as('isError'), arrayOffset('title', 0) - .ifError(Constant.of('was error')) + .ifError(constant('was error')) .as('ifError'), field('foo').isAbsent().as('isAbsent'), field('title').isNotNull().as('titleIsNotNull'), @@ -1596,16 +1597,16 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .select( - cosineDistance(Constant.vector(sourceVector), targetVector).as( + cosineDistance(constantVector(sourceVector), targetVector).as( 'cosineDistance' ), - dotProduct(Constant.vector(sourceVector), targetVector).as( + dotProduct(constantVector(sourceVector), targetVector).as( 'dotProductDistance' ), - euclideanDistance(Constant.vector(sourceVector), targetVector).as( + euclideanDistance(constantVector(sourceVector), targetVector).as( 'euclideanDistance' ), - manhattanDistance(Constant.vector(sourceVector), targetVector).as( + manhattanDistance(constantVector(sourceVector), targetVector).as( 'manhattanDistance' ) ) @@ -1623,16 +1624,16 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .select( - Constant.vector(sourceVector) + constantVector(sourceVector) .cosineDistance(targetVector) .as('cosineDistance'), - Constant.vector(sourceVector) + constantVector(sourceVector) .dotProduct(targetVector) .as('dotProductDistance'), - Constant.vector(sourceVector) + constantVector(sourceVector) .euclideanDistance(targetVector) .as('euclideanDistance'), - Constant.vector(sourceVector) + constantVector(sourceVector) .manhattanDistance(targetVector) .as('manhattanDistance') ) @@ -1694,7 +1695,7 @@ apiDescribe.only('Pipelines', persistence => { .sort(descending('rating')) .limit(1) .select( - genericFunction('add', [field('rating'), Constant.of(1)]).as( + genericFunction('add', [field('rating'), constant(1)]).as( 'rating' ) ) @@ -1786,7 +1787,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .limit(1) - .select(bitAnd(Constant.of(5), 12).as('result')) + .select(bitAnd(constant(5), 12).as('result')) ); expectResults(snapshot, { result: 4 @@ -1796,7 +1797,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .limit(1) - .select(Constant.of(5).bitAnd(12).as('result')) + .select(constant(5).bitAnd(12).as('result')) ); expectResults(snapshot, { result: 4 @@ -1808,7 +1809,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .limit(1) - .select(bitOr(Constant.of(5), 12).as('result')) + .select(bitOr(constant(5), 12).as('result')) ); expectResults(snapshot, { result: 13 @@ -1817,7 +1818,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .limit(1) - .select(Constant.of(5).bitOr(12).as('result')) + .select(constant(5).bitOr(12).as('result')) ); expectResults(snapshot, { result: 13 @@ -1829,7 +1830,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .limit(1) - .select(bitXor(Constant.of(5), 12).as('result')) + .select(bitXor(constant(5), 12).as('result')) ); expectResults(snapshot, { result: 9 @@ -1838,7 +1839,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .limit(1) - .select(Constant.of(5).bitXor(12).as('result')) + .select(constant(5).bitXor(12).as('result')) ); expectResults(snapshot, { result: 9 @@ -1851,9 +1852,9 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .limit(1) .select( - bitNot( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd))) - ).as('result') + bitNot(constant(Bytes.fromUint8Array(Uint8Array.of(0xfd)))).as( + 'result' + ) ) ); expectResults(snapshot, { @@ -1864,7 +1865,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .limit(1) .select( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0xfd))) + constant(Bytes.fromUint8Array(Uint8Array.of(0xfd))) .bitNot() .as('result') ) @@ -1881,7 +1882,7 @@ apiDescribe.only('Pipelines', persistence => { .limit(1) .select( bitLeftShift( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))), 2 ).as('result') ) @@ -1894,7 +1895,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .limit(1) .select( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))) + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) .bitLeftShift(2) .as('result') ) @@ -1911,7 +1912,7 @@ apiDescribe.only('Pipelines', persistence => { .limit(1) .select( bitRightShift( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))), + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))), 2 ).as('result') ) @@ -1924,7 +1925,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .limit(1) .select( - Constant.of(Bytes.fromUint8Array(Uint8Array.of(0x02))) + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) .bitRightShift(2) .as('result') ) @@ -2056,7 +2057,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .addFields( - Constant.of(" The Hitchhiker's Guide to the Galaxy ").as( + constant(" The Hitchhiker's Guide to the Galaxy ").as( 'spacedTitle' ) ) From 3268c63f7646864c1b1e4f7d86be469cdb7f5a3f Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 28 Feb 2025 15:48:28 -0700 Subject: [PATCH 47/75] Removed constant(...) overloads to create a map or array. Use the array or map function instead. --- packages/firestore/src/lite-api/expressions.ts | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 96916052fbb..18910d4eb40 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -2458,22 +2458,6 @@ export function constant(value: DocumentReference): Constant; */ export function constant(value: ProtoValue): Constant; -/** - * Creates a `Constant` instance for an array value. - * - * @param value The array value. - * @return A new `Constant` instance. - */ -export function constant(value: any[]): Constant; - -/** - * Creates a `Constant` instance for a map value. - * - * @param value The map value. - * @return A new `Constant` instance. - */ -export function constant(value: Record): Constant; - /** * Creates a `Constant` instance for a VectorValue value. * From b909af7d8aa3be40607a517d19cb3684fdc2738a Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 28 Feb 2025 15:49:55 -0700 Subject: [PATCH 48/75] Implemented and documented ascending|descending(fieldName) as a convenient way to create orderings for a specific field --- .../firestore/src/lite-api/expressions.ts | 52 +++++++++++++++---- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 18910d4eb40..d994f269d68 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -6973,36 +6973,68 @@ export function orFunction( /** * @beta * - * Creates an {@link Ordering} that sorts documents in ascending order based on this expression. + * Creates an {@link Ordering} that sorts documents in ascending order based on an expression. * * ```typescript - * // Sort documents by the 'name' field in ascending order + * // Sort documents by the 'name' field in lowercase in ascending order * firestore.pipeline().collection("users") - * .sort(ascending(field("name"))); + * .sort(ascending(field("name").toLower())); * ``` * * @param expr The expression to create an ascending ordering for. * @return A new `Ordering` for ascending sorting. */ -export function ascending(expr: Expr): Ordering { - return new Ordering(expr, 'ascending'); +export function ascending(expr: Expr): Ordering; + +/** + * @beta + * + * Creates an {@link Ordering} that sorts documents in ascending order based on a field. + * + * ```typescript + * // Sort documents by the 'name' field in ascending order + * firestore.pipeline().collection("users") + * .sort(ascending("name")); + * ``` + * + * @param fieldName The field to create an ascending ordering for. + * @return A new `Ordering` for ascending sorting. + */ +export function ascending(fieldName: string): Ordering; +export function ascending(field: Expr | string): Ordering { + return new Ordering(fieldOfOrExpr(field), 'ascending'); } /** * @beta * - * Creates an {@link Ordering} that sorts documents in descending order based on this expression. + * Creates an {@link Ordering} that sorts documents in descending order based on an expression. * * ```typescript - * // Sort documents by the 'createdAt' field in descending order + * // Sort documents by the 'name' field in lowercase in descending order * firestore.pipeline().collection("users") - * .sort(descending(field("createdAt"))); + * .sort(descending(field("name").toLower())); * ``` * * @param expr The expression to create a descending ordering for. * @return A new `Ordering` for descending sorting. */ export function descending(expr: Expr): Ordering; + +/** + * @beta + * + * Creates an {@link Ordering} that sorts documents in descending order based on a field. + * + * ```typescript + * // Sort documents by the 'name' field in descending order + * firestore.pipeline().collection("users") + * .sort(descending("name")); + * ``` + * + * @param fieldName The field to create a descending ordering for. + * @return A new `Ordering` for descending sorting. + */ export function descending(fieldName: string): Ordering; export function descending(field: Expr | string): Ordering { return new Ordering(fieldOfOrExpr(field), 'descending'); @@ -7015,7 +7047,7 @@ export function descending(field: Expr | string): Ordering { * * You create `Ordering` instances using the `ascending` and `descending` helper functions. */ -export class Ordering { +export class Ordering implements ProtoValueSerializable, UserData { constructor( readonly expr: Expr, readonly direction: 'ascending' | 'descending' @@ -7043,4 +7075,6 @@ export class Ordering { _readUserData(dataReader: UserDataReader): void { this.expr._readUserData(dataReader); } + + _protoValueType: "ProtoValue" = "ProtoValue"; } From 36def6e10efc0233de3c796a1b39ec2c613a36db Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 28 Feb 2025 16:01:01 -0700 Subject: [PATCH 49/75] fix tests creating a constant map and array --- packages/firestore/test/integration/api/pipeline.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 25940faf171..f5de2745a14 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -440,7 +440,7 @@ apiDescribe.only('Pipelines', persistence => { ).as('bytes'), constant(doc(firestore, 'foo', 'bar')).as('documentReference'), constant(vector([1, 2, 3])).as('vectorValue'), - constant({ + map({ 'number': 1, 'string': 'a string', 'boolean': true, @@ -459,7 +459,7 @@ apiDescribe.only('Pipelines', persistence => { }, 'array': [1, 'c string'] }).as('map'), - constant([ + array([ 1, 'a string', true, From f1c68a53fbfc5f0d9382dde82ef42a2f23fe241f Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 28 Feb 2025 16:01:50 -0700 Subject: [PATCH 50/75] Remove genericFunction, genericAggregateFunction, and genericBooleanExpr. Replace usage with constructor --- .../firestore/lite/pipelines/pipelines.ts | 1 - packages/firestore/src/api_pipelines.ts | 3 - .../firestore/src/lite-api/expressions.ts | 67 +------------------ .../test/integration/api/pipeline.test.ts | 26 +++---- 4 files changed, 16 insertions(+), 81 deletions(-) diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index b1b8a67dd9e..b8fca507e59 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -137,7 +137,6 @@ export { timestampToUnixSeconds, timestampAdd, timestampSub, - genericFunction, ascending, descending, ExprWithAlias, diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index 996f6c74024..1d5f98c54ab 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -106,9 +106,6 @@ export { timestampToUnixSeconds, timestampAdd, timestampSub, - genericFunction, - genericBooleanExpr, - genericAggregateFunction, ascending, descending, countIf, diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index d994f269d68..7d9e4fd8f04 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -6859,69 +6859,6 @@ export function timestampSub( return normalizedTimestamp.timestampSub(normalizedUnit, normalizedAmount); } -/** - * @beta - * - * Creates functions that work on the backend but do not exist in the SDK yet. - * - * ```typescript - * // This is the same of the 'sum(field("price"))', if it was not yet implemented in the SDK. - * genericFunction("sum", [field("price")]); - * ``` - * - * @param functionName The name of the server function. - * @param params The arguments to pass to the function. - * @return A new {@code FirestoreFunction} representing the function call. - */ -export function genericFunction( - functionName: string, - params: any[] -): FunctionExpr { - return new FunctionExpr(functionName, params.map(valueToDefaultExpr)); -} - -/** - * @beta - * - * Creates a boolean expression that works on the backend but does not exist in the SDK yet. - * - * ```typescript - * // This is the same of the 'eq("price", 10)', if it was not yet implemented in the SDK. - * genericFunction("eq", [field("price"), constant(10)]); - * ``` - * - * @param functionName The name of the server boolean expression. - * @param params The arguments to pass to the boolean expression. - * @return A new {@code BooleanExpr} representing the function call. - */ -export function genericBooleanExpr( - functionName: string, - params: any[] -): BooleanExpr { - return new BooleanExpr(functionName, params.map(valueToDefaultExpr)); -} - -/** - * @beta - * - * Creates a boolean expression that works on the backend but does not exist in the SDK yet. - * - * ```typescript - * // This is the same of the 'eq("price", 10)', if it was not yet implemented in the SDK. - * genericFunction("eq", [field("price"), constant(10)]); - * ``` - * - * @param functionName The name of the server boolean expression. - * @param params The arguments to pass to the boolean expression. - * @return A new {@code BooleanExpr} representing the function call. - */ -export function genericAggregateFunction( - functionName: string, - params: any[] -): AggregateFunction { - return new AggregateFunction(functionName, params.map(valueToDefaultExpr)); -} - /** * @beta * @@ -7001,7 +6938,7 @@ export function ascending(expr: Expr): Ordering; * @return A new `Ordering` for ascending sorting. */ export function ascending(fieldName: string): Ordering; -export function ascending(field: Expr | string): Ordering { +export function ascending(field: Expr | string): Ordering { return new Ordering(fieldOfOrExpr(field), 'ascending'); } @@ -7076,5 +7013,5 @@ export class Ordering implements ProtoValueSerializable, UserData { this.expr._readUserData(dataReader); } - _protoValueType: "ProtoValue" = "ProtoValue"; + _protoValueType: 'ProtoValue' = 'ProtoValue'; } diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index f5de2745a14..e638e9e220c 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -18,7 +18,12 @@ import { expect, use } from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import { constantVector } from '../../../src/lite-api/expressions'; +import { + AggregateFunction, + BooleanExpr, + constantVector, + FunctionExpr +} from '../../../src/lite-api/expressions'; import { PipelineSnapshot } from '../../../src/lite-api/pipeline-result'; import { addEqualityMatcher } from '../../util/equality_matcher'; import { Deferred } from '../../util/promise'; @@ -27,9 +32,6 @@ import { Timestamp, array, descending, - genericFunction, - genericAggregateFunction, - genericBooleanExpr, isNan, map, Bytes, @@ -1695,7 +1697,7 @@ apiDescribe.only('Pipelines', persistence => { .sort(descending('rating')) .limit(1) .select( - genericFunction('add', [field('rating'), constant(1)]).as( + new FunctionExpr('add', [field('rating'), constant(1)]).as( 'rating' ) ) @@ -1710,7 +1712,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .where( - genericBooleanExpr('and', [ + new BooleanExpr('and', [ field('rating').gt(0), field('title').charLength().lt(5), field('tags').arrayContains('propaganda') @@ -1728,9 +1730,9 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .where( - genericBooleanExpr('array_contains_any', [ + new BooleanExpr('array_contains_any', [ field('tags'), - ['politics'] + array(['politics']) ]) ) .select('title') @@ -1745,9 +1747,9 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .aggregate( - genericAggregateFunction('count_if', [ - field('rating').gte(4.5) - ]).as('countOfBest') + new AggregateFunction('count_if', [field('rating').gte(4.5)]).as( + 'countOfBest' + ) ) ); expectResults(snapshot, { @@ -1760,7 +1762,7 @@ apiDescribe.only('Pipelines', persistence => { randomCol .pipeline() .sort( - genericFunction('char_length', [field('title')]).ascending(), + new FunctionExpr('char_length', [field('title')]).ascending(), descending('__name__') ) .limit(3) From 406929fe1f9b50139137417bb8d4dc3e66db01f7 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 3 Mar 2025 12:54:57 -0700 Subject: [PATCH 51/75] Pipeline result timestamp testing --- .../test/integration/api/pipeline.test.ts | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index e638e9e220c..083ca5067dc 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -99,7 +99,8 @@ import { logicalMinimum, xor, field, - constant + constant, + writeBatch } from '../util/firebase_export'; import { apiDescribe, withTestCollection } from '../util/helpers'; @@ -112,16 +113,20 @@ apiDescribe.only('Pipelines', persistence => { let firestore: Firestore; let randomCol: CollectionReference; + let beginDocCreation: number = 0; + let endDocCreation: number = 0; async function testCollectionWithDocs(docs: { [id: string]: DocumentData; }): Promise> { + beginDocCreation = new Date().valueOf(); for (const id in docs) { if (docs.hasOwnProperty(id)) { const ref = doc(randomCol, id); await setDoc(ref, docs[id]); } } + endDocCreation = new Date().valueOf(); return randomCol; } @@ -550,6 +555,56 @@ apiDescribe.only('Pipelines', persistence => { expect(proto).not.to.be.null; }); + it('returns execution time', async () => { + const start = new Date().valueOf(); + const pipeline = firestore.pipeline().collection(randomCol.path); + + const snapshot = await execute(pipeline); + const end = new Date().valueOf(); + + expect(snapshot.executionTime.toDate().valueOf()).to.approximately( + (start + end) / 2, + end - start + ); + }); + + it('returns create and update time for each document', async () => { + const pipeline = firestore.pipeline().collection(randomCol.path); + + let snapshot = await execute(pipeline); + expect(snapshot.results.length).to.equal(10); + snapshot.results.forEach(doc => { + expect(doc.createTime).to.not.be.null; + expect(doc.updateTime).to.not.be.null; + + expect(doc.createTime!.toDate().valueOf()).to.approximately( + (beginDocCreation + endDocCreation) / 2, + endDocCreation - beginDocCreation + ); + expect(doc.updateTime!.toDate().valueOf()).to.approximately( + (beginDocCreation + endDocCreation) / 2, + endDocCreation - beginDocCreation + ); + expect(doc.createTime?.valueOf()).to.equal(doc.updateTime?.valueOf()); + }); + + const wb = writeBatch(firestore); + snapshot.results.forEach(doc => { + wb.update(doc.ref!, { newField: 'value' }); + }); + await wb.commit(); + + snapshot = await execute(pipeline); + expect(snapshot.results.length).to.equal(10); + snapshot.results.forEach(doc => { + expect(doc.createTime).to.not.be.null; + expect(doc.updateTime).to.not.be.null; + expect(doc.createTime!.toDate().valueOf()).to.be.lessThan( + doc.updateTime!.toDate().valueOf() + ); + }); + }); + describe('stages', () => { describe('aggregate stage', () => { it('supports aggregate', async () => { From 9f1abbb1b0fa96d2e735d55c869cc8d16fa58828 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 3 Mar 2025 13:22:06 -0700 Subject: [PATCH 52/75] Testing timestamp edge cases --- .../test/integration/api/pipeline.test.ts | 126 +++++++++++++----- 1 file changed, 90 insertions(+), 36 deletions(-) diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 083ca5067dc..b1f0ce9bf2c 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -555,54 +555,108 @@ apiDescribe.only('Pipelines', persistence => { expect(proto).not.to.be.null; }); - it('returns execution time', async () => { - const start = new Date().valueOf(); - const pipeline = firestore.pipeline().collection(randomCol.path); + describe('timestamps', () => { + it('returns execution time', async () => { + const start = new Date().valueOf(); + const pipeline = firestore.pipeline().collection(randomCol.path); - const snapshot = await execute(pipeline); - const end = new Date().valueOf(); + const snapshot = await execute(pipeline); + const end = new Date().valueOf(); - expect(snapshot.executionTime.toDate().valueOf()).to.approximately( - (start + end) / 2, - end - start - ); - }); + expect(snapshot.executionTime.toDate().valueOf()).to.approximately( + (start + end) / 2, + end - start + ); + }); - it('returns create and update time for each document', async () => { - const pipeline = firestore.pipeline().collection(randomCol.path); + it('returns execution time for an empty query', async () => { + const start = new Date().valueOf(); + const pipeline = firestore.pipeline().collection(randomCol.path).limit(0); - let snapshot = await execute(pipeline); - expect(snapshot.results.length).to.equal(10); - snapshot.results.forEach(doc => { - expect(doc.createTime).to.not.be.null; - expect(doc.updateTime).to.not.be.null; + const snapshot = await execute(pipeline); + const end = new Date().valueOf(); - expect(doc.createTime!.toDate().valueOf()).to.approximately( - (beginDocCreation + endDocCreation) / 2, - endDocCreation - beginDocCreation - ); - expect(doc.updateTime!.toDate().valueOf()).to.approximately( - (beginDocCreation + endDocCreation) / 2, - endDocCreation - beginDocCreation + expect(snapshot.results.length).to.equal(0); + + expect(snapshot.executionTime.toDate().valueOf()).to.approximately( + (start + end) / 2, + end - start ); - expect(doc.createTime?.valueOf()).to.equal(doc.updateTime?.valueOf()); }); - const wb = writeBatch(firestore); - snapshot.results.forEach(doc => { - wb.update(doc.ref!, { newField: 'value' }); + it('returns create and update time for each document', async () => { + const pipeline = firestore.pipeline().collection(randomCol.path); + + let snapshot = await execute(pipeline); + expect(snapshot.results.length).to.equal(10); + snapshot.results.forEach(doc => { + expect(doc.createTime).to.not.be.null; + expect(doc.updateTime).to.not.be.null; + + expect(doc.createTime!.toDate().valueOf()).to.approximately( + (beginDocCreation + endDocCreation) / 2, + endDocCreation - beginDocCreation + ); + expect(doc.updateTime!.toDate().valueOf()).to.approximately( + (beginDocCreation + endDocCreation) / 2, + endDocCreation - beginDocCreation + ); + expect(doc.createTime?.valueOf()).to.equal(doc.updateTime?.valueOf()); + }); + + const wb = writeBatch(firestore); + snapshot.results.forEach(doc => { + wb.update(doc.ref!, { newField: 'value' }); + }); + await wb.commit(); + + snapshot = await execute(pipeline); + expect(snapshot.results.length).to.equal(10); + snapshot.results.forEach(doc => { + expect(doc.createTime).to.not.be.null; + expect(doc.updateTime).to.not.be.null; + expect(doc.createTime!.toDate().valueOf()).to.be.lessThan( + doc.updateTime!.toDate().valueOf() + ); + }); }); - await wb.commit(); - snapshot = await execute(pipeline); - expect(snapshot.results.length).to.equal(10); - snapshot.results.forEach(doc => { - expect(doc.createTime).to.not.be.null; - expect(doc.updateTime).to.not.be.null; - expect(doc.createTime!.toDate().valueOf()).to.be.lessThan( - doc.updateTime!.toDate().valueOf() + it('returns execution time for an aggregate query', async () => { + const start = new Date().valueOf(); + const pipeline = firestore + .pipeline() + .collection(randomCol.path) + .aggregate(avgFunction('rating').as('avgRating')); + + const snapshot = await execute(pipeline); + const end = new Date().valueOf(); + + expect(snapshot.results.length).to.equal(1); + + expect(snapshot.executionTime.toDate().valueOf()).to.approximately( + (start + end) / 2, + end - start ); }); + + it('returns undefined create and update time for each result in an aggregate query', async () => { + const pipeline = firestore + .pipeline() + .collection(randomCol.path) + .aggregate({ + accumulators: [avgFunction('rating').as('avgRating')], + groups: ['genre'] + }); + + const snapshot = await execute(pipeline); + + expect(snapshot.results.length).to.equal(8); + + snapshot.results.forEach(doc => { + expect(doc.updateTime).to.be.undefined; + expect(doc.createTime).to.be.undefined; + }); + }); }); describe('stages', () => { From 57c2a56edc6c8ee9e423f03d80fe2290ca7d1a6a Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 3 Mar 2025 14:07:48 -0700 Subject: [PATCH 53/75] Query to pipeline conversion is performed from the PipelineSource class rather than the Query class --- packages/firestore/src/api/pipeline_impl.ts | 11 +-- packages/firestore/src/core/pipeline-util.ts | 2 +- .../firestore/src/lite-api/pipeline-source.ts | 15 +++- .../firestore/src/lite-api/pipeline_impl.ts | 27 +----- .../integration/api/query_to_pipeline.test.ts | 90 ++++++++++--------- 5 files changed, 63 insertions(+), 82 deletions(-) diff --git a/packages/firestore/src/api/pipeline_impl.ts b/packages/firestore/src/api/pipeline_impl.ts index 8650140a444..3fbfbf5f7a6 100644 --- a/packages/firestore/src/api/pipeline_impl.ts +++ b/packages/firestore/src/api/pipeline_impl.ts @@ -17,7 +17,6 @@ import { Pipeline } from '../api/pipeline'; import { firestoreClientExecutePipeline } from '../core/firestore_client'; -import { toPipeline } from '../core/pipeline-util'; import { Pipeline as LitePipeline } from '../lite-api/pipeline'; import { PipelineResult, PipelineSnapshot } from '../lite-api/pipeline-result'; import { PipelineSource } from '../lite-api/pipeline-source'; @@ -26,7 +25,7 @@ import { newUserDataReader } from '../lite-api/user_data_reader'; import { cast } from '../util/input_validation'; import { ensureFirestoreConfigured, Firestore } from './database'; -import { DocumentReference, Query } from './reference'; +import { DocumentReference } from './reference'; import { ExpUserDataWriter } from './user_data_writer'; declare module './database' { @@ -108,11 +107,3 @@ Firestore.prototype.pipeline = function (): PipelineSource { ); }); }; - -// Augment the Query class with the pipeline() factory method -Query.prototype.pipeline = function (): Pipeline { - const db = cast(this.firestore, Firestore); - - const litePipeline: LitePipeline = toPipeline(this._query, db); - return cast(litePipeline, Pipeline); -}; diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index 933809e0957..c1ca7c71353 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Firestore } from '../api/database'; +import { Firestore } from '../lite-api/database'; import { Constant, Field, diff --git a/packages/firestore/src/lite-api/pipeline-source.ts b/packages/firestore/src/lite-api/pipeline-source.ts index fb596a626bc..421fc759bfb 100644 --- a/packages/firestore/src/lite-api/pipeline-source.ts +++ b/packages/firestore/src/lite-api/pipeline-source.ts @@ -16,9 +16,11 @@ */ import { DatabaseId } from '../core/database_info'; +import { toPipeline } from '../core/pipeline-util'; import { FirestoreError, Code } from '../util/error'; -import { CollectionReference, DocumentReference } from './reference'; +import { Pipeline } from './pipeline'; +import { CollectionReference, DocumentReference, Query } from './reference'; import { CollectionGroupSource, CollectionSource, @@ -105,6 +107,17 @@ export class PipelineSource { return this._createPipeline([DocumentsSource.of(docs)]); } + /** + * Convert the given Query into an equivalent Pipeline. + * + * @param query A Query to be converted into a Pipeline. + * + * @throws {@FirestoreError} Thrown if any of the provided DocumentReferences target a different project or database than the pipeline. + */ + createFrom(query: Query): Pipeline { + return toPipeline(query._query, query.firestore); + } + _validateReference(reference: CollectionReference | DocumentReference): void { const refDbId = reference.firestore._databaseId; if (!refDbId.isEqual(this.databaseId)) { diff --git a/packages/firestore/src/lite-api/pipeline_impl.ts b/packages/firestore/src/lite-api/pipeline_impl.ts index 047f5636de9..6179a35b8b6 100644 --- a/packages/firestore/src/lite-api/pipeline_impl.ts +++ b/packages/firestore/src/lite-api/pipeline_impl.ts @@ -22,7 +22,7 @@ import { Firestore } from './database'; import { Pipeline } from './pipeline'; import { PipelineResult, PipelineSnapshot } from './pipeline-result'; import { PipelineSource } from './pipeline-source'; -import { DocumentReference, Query } from './reference'; +import { DocumentReference } from './reference'; import { LiteUserDataWriter } from './reference_impl'; import { Stage } from './stage'; import { newUserDataReader } from './user_data_reader'; @@ -33,12 +33,6 @@ declare module './database' { } } -declare module './reference' { - interface Query { - pipeline(): Pipeline; - } -} - /** * Executes this pipeline and returns a Promise to represent the asynchronous operation. * @@ -107,22 +101,3 @@ Firestore.prototype.pipeline = function (): PipelineSource { return new Pipeline(this, userDataReader, userDataWriter, stages); }); }; - -Query.prototype.pipeline = function (): Pipeline { - let pipeline; - const query = this; - if (query._query.collectionGroup) { - pipeline = query.firestore - .pipeline() - .collectionGroup(query._query.collectionGroup); - } else { - pipeline = query.firestore - .pipeline() - .collection(query._query.path.canonicalString()); - } - - // TODO(pipeline) convert existing query filters, limits, etc into - // pipeline stages - - return pipeline; -}; diff --git a/packages/firestore/test/integration/api/query_to_pipeline.test.ts b/packages/firestore/test/integration/api/query_to_pipeline.test.ts index 90e27e6ed88..ab29f8634e9 100644 --- a/packages/firestore/test/integration/api/query_to_pipeline.test.ts +++ b/packages/firestore/test/integration/api/query_to_pipeline.test.ts @@ -74,8 +74,8 @@ apiDescribe('Query to Pipeline', persistence => { return withTestCollection( PERSISTENCE_MODE_UNSPECIFIED, { 1: { foo: 1 } }, - async collRef => { - const snapshot = await execute(collRef.pipeline()); + async (collRef, db) => { + const snapshot = await execute(db.pipeline().createFrom(collRef)); verifyResults(snapshot, { foo: 1 }); } ); @@ -88,9 +88,9 @@ apiDescribe('Query to Pipeline', persistence => { 1: { foo: 1 }, 2: { foo: 2 } }, - async collRef => { + async (collRef, db) => { const query1 = query(collRef, where('foo', '==', 1)); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 1 }); } ); @@ -103,9 +103,9 @@ apiDescribe('Query to Pipeline', persistence => { 1: { foo: 1 }, 2: { foo: 2 } }, - async collRef => { + async (collRef, db) => { const query1 = query(collRef, where(new FieldPath('foo'), '==', 1)); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 1 }); } ); @@ -118,9 +118,9 @@ apiDescribe('Query to Pipeline', persistence => { 1: { foo: 1 }, 2: { foo: 2 } }, - async collRef => { + async (collRef, db) => { const query1 = query(collRef, orderBy('foo')); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 1 }, { foo: 2 }); } ); @@ -133,9 +133,9 @@ apiDescribe('Query to Pipeline', persistence => { 1: { foo: 1 }, 2: { foo: 2 } }, - async collRef => { + async (collRef, db) => { const query1 = query(collRef, orderBy('foo', 'asc')); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 1 }, { foo: 2 }); } ); @@ -148,9 +148,9 @@ apiDescribe('Query to Pipeline', persistence => { 1: { foo: 1 }, 2: { foo: 2 } }, - async collRef => { + async (collRef, db) => { const query1 = query(collRef, orderBy('foo', 'desc')); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 2 }, { foo: 1 }); } ); @@ -163,9 +163,9 @@ apiDescribe('Query to Pipeline', persistence => { 1: { foo: 1 }, 2: { foo: 2 } }, - async collRef => { + async (collRef, db) => { const query1 = query(collRef, orderBy('foo'), limit(1)); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 1 }); } ); @@ -179,9 +179,9 @@ apiDescribe('Query to Pipeline', persistence => { 2: { foo: 2 }, 3: { foo: 3 } }, - async collRef => { + async (collRef, db) => { const query1 = query(collRef, orderBy('foo'), limitToLast(2)); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 2 }, { foo: 3 }); } ); @@ -194,9 +194,9 @@ apiDescribe('Query to Pipeline', persistence => { 1: { foo: 1 }, 2: { foo: 2 } }, - async collRef => { + async (collRef, db) => { const query1 = query(collRef, orderBy('foo'), startAt(2)); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 2 }); } ); @@ -219,7 +219,7 @@ apiDescribe('Query to Pipeline', persistence => { 11: { id: 11, foo: 2, bar: 2, baz: 2 }, 12: { id: 12, foo: 2, bar: 2, baz: 2 } }, - async collRef => { + async (collRef, db) => { let docRef = await getDoc(doc(collRef, '2')); let query1 = query( collRef, @@ -228,7 +228,7 @@ apiDescribe('Query to Pipeline', persistence => { orderBy('baz'), startAfter(docRef) ); - let snapshot = await execute(query1.pipeline()); + let snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults( snapshot, { id: 3, foo: 1, bar: 1, baz: 2 }, @@ -251,7 +251,7 @@ apiDescribe('Query to Pipeline', persistence => { orderBy('baz'), startAfter(docRef) ); - snapshot = await execute(query1.pipeline()); + snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults( snapshot, { id: 4, foo: 1, bar: 2, baz: 1 }, @@ -285,7 +285,7 @@ apiDescribe('Query to Pipeline', persistence => { 11: { id: 11, foo: 2, bar: 2, baz: 2 }, 12: { id: 12, foo: 2, bar: 2, baz: 2 } }, - async collRef => { + async (collRef, db) => { let docRef = await getDoc(doc(collRef, '2')); let query1 = query( collRef, @@ -294,7 +294,7 @@ apiDescribe('Query to Pipeline', persistence => { orderBy('baz'), startAt(docRef) ); - let snapshot = await execute(query1.pipeline()); + let snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults( snapshot, { id: 2, foo: 1, bar: 1, baz: 2 }, @@ -318,7 +318,7 @@ apiDescribe('Query to Pipeline', persistence => { orderBy('baz'), startAt(docRef) ); - snapshot = await execute(query1.pipeline()); + snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults( snapshot, { id: 3, foo: 1, bar: 1, baz: 2 }, @@ -343,9 +343,9 @@ apiDescribe('Query to Pipeline', persistence => { 1: { foo: 1 }, 2: { foo: 2 } }, - async collRef => { + async (collRef, db) => { const query1 = query(collRef, orderBy('foo'), startAfter(1)); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 2 }); } ); @@ -358,9 +358,9 @@ apiDescribe('Query to Pipeline', persistence => { 1: { foo: 1 }, 2: { foo: 2 } }, - async collRef => { + async (collRef, db) => { const query1 = query(collRef, orderBy('foo'), endAt(1)); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 1 }); } ); @@ -373,9 +373,9 @@ apiDescribe('Query to Pipeline', persistence => { 1: { foo: 1 }, 2: { foo: 2 } }, - async collRef => { + async (collRef, db) => { const query1 = query(collRef, orderBy('foo'), endBefore(2)); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 1 }); } ); @@ -388,15 +388,15 @@ apiDescribe('Query to Pipeline', persistence => { 1: { foo: 1 }, 2: { foo: 2 } }, - async collRef => { + async (collRef, db) => { let query1 = query(collRef, orderBy('foo'), limit(1)); - const pipeline1 = query1.pipeline(); + const pipeline1 = db.pipeline().createFrom(query1); let snapshot = await execute(pipeline1); verifyResults(snapshot, { foo: 1 }); // Pass the document snapshot from the previous snapshot query1 = query(query1, startAfter(snapshot.results[0].get('foo'))); - snapshot = await execute(query1.pipeline()); + snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 2 }); } ); @@ -409,14 +409,14 @@ apiDescribe('Query to Pipeline', persistence => { 1: { foo: 1 }, 2: { foo: 2 } }, - async collRef => { + async (collRef, db) => { let query1 = query( collRef, orderBy('foo'), orderBy(documentId(), 'asc'), limit(1) ); - const pipeline1 = query1.pipeline(); + const pipeline1 = db.pipeline().createFrom(query1); let snapshot = await execute(pipeline1); verifyResults(snapshot, { foo: 1 }); @@ -428,7 +428,7 @@ apiDescribe('Query to Pipeline', persistence => { snapshot.results[0].ref?.id ) ); - snapshot = await execute(query1.pipeline()); + snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { foo: 2 }); } ); @@ -438,7 +438,7 @@ apiDescribe('Query to Pipeline', persistence => { return withTestCollection( PERSISTENCE_MODE_UNSPECIFIED, {}, - async collRef => { + async (collRef, db) => { const collectionGroupId = `${collRef.id}group`; const fooDoc = doc( @@ -453,7 +453,7 @@ apiDescribe('Query to Pipeline', persistence => { await setDoc(barDoc, { bar: 1 }); const query1 = collectionGroup(collRef.firestore, collectionGroupId); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults(snapshot, { bar: 1 }, { foo: 1 }); } @@ -464,7 +464,7 @@ apiDescribe('Query to Pipeline', persistence => { return withTestCollection( PERSISTENCE_MODE_UNSPECIFIED, {}, - async collRef => { + async (collRef, db) => { const docWithSpecials = doc(collRef, 'so!@#$%^&*()_+special'); const collectionWithSpecials = collection( @@ -475,7 +475,9 @@ apiDescribe('Query to Pipeline', persistence => { await addDoc(collectionWithSpecials, { foo: 2 }); const snapshot = await execute( - query(collectionWithSpecials, orderBy('foo', 'asc')).pipeline() + db + .pipeline() + .createFrom(query(collectionWithSpecials, orderBy('foo', 'asc'))) ); verifyResults(snapshot, { foo: 1 }, { foo: 2 }); @@ -500,12 +502,12 @@ apiDescribe('Query to Pipeline', persistence => { '11': { id: 11, foo: 2, bar: 2, baz: 2 }, '12': { id: 12, foo: 2, bar: 2, baz: 2 } }, - async collRef => { + async (collRef, db) => { const query1 = query( collRef, and(where('id', '>', 2), where('id', '<=', 10)) ); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults( snapshot, { id: 3, foo: 1, bar: 1, baz: 2 }, @@ -538,12 +540,12 @@ apiDescribe('Query to Pipeline', persistence => { '11': { id: 11, foo: 2, bar: 2, baz: 2 }, '12': { id: 12, foo: 2, bar: 2, baz: 2 } }, - async collRef => { + async (collRef, db) => { const query1 = query( collRef, and(where('id', '>=', 2), where('baz', '<', 2)) ); - const snapshot = await execute(query1.pipeline()); + const snapshot = await execute(db.pipeline().createFrom(query1)); verifyResults( snapshot, { id: 4, foo: 1, bar: 2, baz: 1 }, From 0eda1acc6686e1c15f644e8a0bc40f6604a3bdf2 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 5 Mar 2025 11:22:23 -0700 Subject: [PATCH 54/75] Timestamp tests and fix pipeline tests for change in pipeline creation from a classic query --- .../test/integration/api/pipeline.test.ts | 272 ++++++++++++------ 1 file changed, 185 insertions(+), 87 deletions(-) diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index b1f0ce9bf2c..d5ccd6f41cb 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -485,8 +485,9 @@ apiDescribe.only('Pipelines', persistence => { ]; const snapshots = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select(constants[0], ...constants.slice(1)) ); @@ -671,8 +672,9 @@ apiDescribe.only('Pipelines', persistence => { expectResults(snapshot, { count: 10 }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(eq('genre', 'Science Fiction')) .aggregate( countAll().as('count'), @@ -686,8 +688,9 @@ apiDescribe.only('Pipelines', persistence => { it('rejects groups without accumulators', async () => { await expect( execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(lt('published', 1900)) .aggregate({ accumulators: [], @@ -699,8 +702,9 @@ apiDescribe.only('Pipelines', persistence => { it('returns group and accumulate results', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(lt(field('published'), 1984)) .aggregate({ accumulators: [avgFunction('rating').as('avgRating')], @@ -719,8 +723,9 @@ apiDescribe.only('Pipelines', persistence => { it('returns min and max accumulations', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .aggregate( countAll().as('count'), field('rating').maximum().as('maxRating'), @@ -736,8 +741,9 @@ apiDescribe.only('Pipelines', persistence => { it('returns countif accumulation', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .aggregate(countIf(field('rating').gt(4.3)).as('count')) ); const expectedResults = { @@ -746,8 +752,9 @@ apiDescribe.only('Pipelines', persistence => { expectResults(snapshot, expectedResults); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .aggregate(field('rating').gt(4.3).countIf().as('count')) ); expectResults(snapshot, expectedResults); @@ -757,8 +764,9 @@ apiDescribe.only('Pipelines', persistence => { describe('distinct stage', () => { it('returns distinct values as expected', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .distinct('genre', 'author') .sort(field('genre').ascending(), field('author').ascending()) ); @@ -907,8 +915,9 @@ apiDescribe.only('Pipelines', persistence => { describe('where stage', () => { it('where with and', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where( andFunction( gt('rating', 4.5), @@ -921,8 +930,9 @@ apiDescribe.only('Pipelines', persistence => { }); it('where with or', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where( orFunction( eq('genre', 'Romance'), @@ -943,8 +953,9 @@ apiDescribe.only('Pipelines', persistence => { it('where with xor', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where( xor( eq('genre', 'Romance'), @@ -1120,8 +1131,9 @@ apiDescribe.only('Pipelines', persistence => { describe('replace stage', () => { it('run pipleine with replace', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) .replaceWith('awards') ); @@ -1135,13 +1147,18 @@ apiDescribe.only('Pipelines', persistence => { describe('sample stage', () => { it('run pipeline with sample limit of 3', async () => { - const snapshot = await execute(randomCol.pipeline().sample(3)); + const snapshot = await execute( + firestore.pipeline().collection(randomCol.path).sample(3) + ); expect(snapshot.results.length).to.equal(3); }); it('run pipeline with sample limit of {documents: 3}', async () => { const snapshot = await execute( - randomCol.pipeline().sample({ documents: 3 }) + firestore + .pipeline() + .collection(randomCol.path) + .sample({ documents: 3 }) ); expect(snapshot.results.length).to.equal(3); }); @@ -1151,7 +1168,10 @@ apiDescribe.only('Pipelines', persistence => { const numIterations = 20; for (let i = 0; i < numIterations; i++) { const snapshot = await execute( - randomCol.pipeline().sample({ percentage: 0.6 }) + firestore + .pipeline() + .collection(randomCol.path) + .sample({ percentage: 0.6 }) ); avgSize += snapshot.results.length; @@ -1164,9 +1184,10 @@ apiDescribe.only('Pipelines', persistence => { describe('union stage', () => { it('run pipeline with union', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() - .union(randomCol.pipeline()) + .collection(randomCol.path) + .union(firestore.pipeline().collection(randomCol.path)) .sort(field(documentId()).ascending()) ); expectResults( @@ -1198,8 +1219,9 @@ apiDescribe.only('Pipelines', persistence => { describe('unnest stage', () => { it('run pipeline with unnest', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) .unnest(field('tags').as('tag')) ); @@ -1254,8 +1276,9 @@ apiDescribe.only('Pipelines', persistence => { }); it('unnest an expr', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) .unnest(array([1, 2, 3]).as('copy')) ); @@ -1314,8 +1337,9 @@ apiDescribe.only('Pipelines', persistence => { describe('function expressions', () => { it('logical max works', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .select( 'title', logicalMaximum(constant(1960), field('published'), 1961).as( @@ -1335,8 +1359,9 @@ apiDescribe.only('Pipelines', persistence => { it('logical min works', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .select( 'title', logicalMinimum(constant(1960), field('published'), 1961).as( @@ -1356,8 +1381,9 @@ apiDescribe.only('Pipelines', persistence => { it('cond works', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .select( 'title', cond( @@ -1379,8 +1405,9 @@ apiDescribe.only('Pipelines', persistence => { it('eqAny works', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(eqAny('published', [1979, 1999, 1967])) .select('title') ); @@ -1393,8 +1420,9 @@ apiDescribe.only('Pipelines', persistence => { it('notEqAny works', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where( notEqAny( 'published', @@ -1408,8 +1436,9 @@ apiDescribe.only('Pipelines', persistence => { it('arrayContains works', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(arrayContains('tags', 'comedy')) .select('title') ); @@ -1420,8 +1449,9 @@ apiDescribe.only('Pipelines', persistence => { it('arrayContainsAny works', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(arrayContainsAny('tags', ['comedy', 'classic'])) .select('title') ); @@ -1434,8 +1464,9 @@ apiDescribe.only('Pipelines', persistence => { it('arrayContainsAll works', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(field('tags').arrayContainsAll('adventure', 'magic')) .select('title') ); @@ -1444,8 +1475,9 @@ apiDescribe.only('Pipelines', persistence => { it('arrayLength works', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .select(field('tags').arrayLength().as('tagsCount')) .where(eq('tagsCount', 3)) ); @@ -1454,8 +1486,9 @@ apiDescribe.only('Pipelines', persistence => { it('testStrConcat', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .select( field('author').strConcat(' - ', field('title')).as('bookInfo') ) @@ -1468,8 +1501,9 @@ apiDescribe.only('Pipelines', persistence => { it('testStartsWith', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(startsWith('title', 'The')) .select('title') .sort(field('title').ascending()) @@ -1485,8 +1519,9 @@ apiDescribe.only('Pipelines', persistence => { it('testEndsWith', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(endsWith('title', 'y')) .select('title') .sort(field('title').descending()) @@ -1500,8 +1535,9 @@ apiDescribe.only('Pipelines', persistence => { it('testLength', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .select(field('title').charLength().as('titleLength'), field('title')) .where(gt('titleLength', 20)) .sort(field('title').ascending()) @@ -1531,7 +1567,11 @@ apiDescribe.only('Pipelines', persistence => { it('testLike', async () => { const snapshot = await execute( - randomCol.pipeline().where(like('title', '%Guide%')).select('title') + firestore + .pipeline() + .collection(randomCol.path) + .where(like('title', '%Guide%')) + .select('title') ); expectResults(snapshot, { title: "The Hitchhiker's Guide to the Galaxy" @@ -1540,22 +1580,29 @@ apiDescribe.only('Pipelines', persistence => { it('testRegexContains', async () => { const snapshot = await execute( - randomCol.pipeline().where(regexContains('title', '(?i)(the|of)')) + firestore + .pipeline() + .collection(randomCol.path) + .where(regexContains('title', '(?i)(the|of)')) ); expect(snapshot.results.length).to.equal(5); }); it('testRegexMatches', async () => { const snapshot = await execute( - randomCol.pipeline().where(regexMatch('title', '.*(?i)(the|of).*')) + firestore + .pipeline() + .collection(randomCol.path) + .where(regexMatch('title', '.*(?i)(the|of).*')) ); expect(snapshot.results.length).to.equal(5); }); it('testArithmeticOperations', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .select( add(field('rating'), 1).as('ratingPlusOne'), subtract(field('published'), 1900).as('yearsSince1900'), @@ -1578,8 +1625,9 @@ apiDescribe.only('Pipelines', persistence => { it('testComparisonOperators', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where( andFunction( gt('rating', 4.2), @@ -1603,8 +1651,9 @@ apiDescribe.only('Pipelines', persistence => { it('testLogicalOperators', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where( orFunction( andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')), @@ -1624,8 +1673,9 @@ apiDescribe.only('Pipelines', persistence => { it('testChecks', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select( @@ -1651,8 +1701,9 @@ apiDescribe.only('Pipelines', persistence => { }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select( @@ -1680,8 +1731,9 @@ apiDescribe.only('Pipelines', persistence => { it('testMapGet', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('published').descending()) .select( field('awards').mapGet('hugo').as('hugoAward'), @@ -1705,8 +1757,9 @@ apiDescribe.only('Pipelines', persistence => { const sourceVector = [0.1, 0.1]; const targetVector = [0.5, 0.8]; let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .select( cosineDistance(constantVector(sourceVector), targetVector).as( 'cosineDistance' @@ -1732,8 +1785,9 @@ apiDescribe.only('Pipelines', persistence => { }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .select( constantVector(sourceVector) .cosineDistance(targetVector) @@ -1761,8 +1815,9 @@ apiDescribe.only('Pipelines', persistence => { it('testNestedFields', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(eq('awards.hugo', true)) .select('title', 'awards.hugo') ); @@ -1778,8 +1833,9 @@ apiDescribe.only('Pipelines', persistence => { it('test mapGet with field name including . notation', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where(eq('awards.hugo', true)) .select( 'title', @@ -1801,8 +1857,9 @@ apiDescribe.only('Pipelines', persistence => { describe('genericFunction', () => { it('add selectable', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(descending('rating')) .limit(1) .select( @@ -1818,8 +1875,9 @@ apiDescribe.only('Pipelines', persistence => { it('and (variadic) selectable', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where( new BooleanExpr('and', [ field('rating').gt(0), @@ -1836,8 +1894,9 @@ apiDescribe.only('Pipelines', persistence => { it('array contains any', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .where( new BooleanExpr('array_contains_any', [ field('tags'), @@ -1853,8 +1912,9 @@ apiDescribe.only('Pipelines', persistence => { it('countif aggregate', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .aggregate( new AggregateFunction('count_if', [field('rating').gte(4.5)]).as( 'countOfBest' @@ -1868,8 +1928,9 @@ apiDescribe.only('Pipelines', persistence => { it('sort by char_len', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort( new FunctionExpr('char_length', [field('title')]).ascending(), descending('__name__') @@ -1895,8 +1956,9 @@ apiDescribe.only('Pipelines', persistence => { describe.skip('not implemented in backend', () => { it('supports Bit_and', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select(bitAnd(constant(5), 12).as('result')) ); @@ -1905,8 +1967,9 @@ apiDescribe.only('Pipelines', persistence => { }); it('supports Bit_and', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select(constant(5).bitAnd(12).as('result')) ); @@ -1917,8 +1980,9 @@ apiDescribe.only('Pipelines', persistence => { it('supports Bit_or', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select(bitOr(constant(5), 12).as('result')) ); @@ -1926,8 +1990,9 @@ apiDescribe.only('Pipelines', persistence => { result: 13 }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select(constant(5).bitOr(12).as('result')) ); @@ -1938,8 +2003,9 @@ apiDescribe.only('Pipelines', persistence => { it('supports Bit_xor', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select(bitXor(constant(5), 12).as('result')) ); @@ -1947,8 +2013,9 @@ apiDescribe.only('Pipelines', persistence => { result: 9 }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select(constant(5).bitXor(12).as('result')) ); @@ -1959,8 +2026,9 @@ apiDescribe.only('Pipelines', persistence => { it('supports Bit_not', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select( bitNot(constant(Bytes.fromUint8Array(Uint8Array.of(0xfd)))).as( @@ -1972,8 +2040,9 @@ apiDescribe.only('Pipelines', persistence => { result: Bytes.fromUint8Array(Uint8Array.of(0x02)) }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select( constant(Bytes.fromUint8Array(Uint8Array.of(0xfd))) @@ -1988,8 +2057,9 @@ apiDescribe.only('Pipelines', persistence => { it('supports Bit_left_shift', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select( bitLeftShift( @@ -2002,8 +2072,9 @@ apiDescribe.only('Pipelines', persistence => { result: Bytes.fromUint8Array(Uint8Array.of(0x04)) }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select( constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) @@ -2018,8 +2089,9 @@ apiDescribe.only('Pipelines', persistence => { it('supports Bit_right_shift', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select( bitRightShift( @@ -2032,8 +2104,9 @@ apiDescribe.only('Pipelines', persistence => { result: Bytes.fromUint8Array(Uint8Array.of(0x01)) }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .limit(1) .select( constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) @@ -2048,8 +2121,9 @@ apiDescribe.only('Pipelines', persistence => { it('supports Document_id', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select(documentIdFunction(field('__path__')).as('docId')) @@ -2058,8 +2132,9 @@ apiDescribe.only('Pipelines', persistence => { docId: 'book4' }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select(field('__path__').documentId().as('docId')) @@ -2071,8 +2146,9 @@ apiDescribe.only('Pipelines', persistence => { it('supports Substr', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select(substr('title', 9, 2).as('of')) @@ -2081,8 +2157,9 @@ apiDescribe.only('Pipelines', persistence => { of: 'of' }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select(field('title').substr(9, 2).as('of')) @@ -2094,8 +2171,9 @@ apiDescribe.only('Pipelines', persistence => { it('supports Substr without length', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select(substr('title', 9).as('of')) @@ -2104,8 +2182,9 @@ apiDescribe.only('Pipelines', persistence => { of: 'of the Rings' }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select(field('title').substr(9).as('of')) @@ -2117,8 +2196,9 @@ apiDescribe.only('Pipelines', persistence => { it('arrayConcat works', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .select( field('tags') .arrayConcat(['newTag1', 'newTag2'], field('tags'), [null]) @@ -2143,8 +2223,9 @@ apiDescribe.only('Pipelines', persistence => { it('testToLowercase', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .select(field('title').toLower().as('lowercaseTitle')) .limit(1) ); @@ -2155,8 +2236,9 @@ apiDescribe.only('Pipelines', persistence => { it('testToUppercase', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .select(field('author').toUpper().as('uppercaseAuthor')) .limit(1) ); @@ -2165,8 +2247,9 @@ apiDescribe.only('Pipelines', persistence => { it('testTrim', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .addFields( constant(" The Hitchhiker's Guide to the Galaxy ").as( 'spacedTitle' @@ -2187,7 +2270,11 @@ apiDescribe.only('Pipelines', persistence => { it('supports Rand', async () => { const snapshot = await execute( - randomCol.pipeline().limit(10).select(rand().as('result')) + firestore + .pipeline() + .collection(randomCol.path) + .limit(10) + .select(rand().as('result')) ); expect(snapshot.results.length).to.equal(10); snapshot.results.forEach(d => { @@ -2232,8 +2319,9 @@ apiDescribe.only('Pipelines', persistence => { it('supports arrayOffset', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(3) .select(arrayOffset('tags', 0).as('firstTag')) @@ -2252,8 +2340,9 @@ apiDescribe.only('Pipelines', persistence => { expectResults(snapshot, ...expectedResults); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(3) .select(field('tags').arrayOffset(0).as('firstTag')) @@ -2265,8 +2354,9 @@ apiDescribe.only('Pipelines', persistence => { // TODO: current_context tests with are failing because of b/395937453 it.skip('supports currentContext', async () => { const snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select(currentContext().as('currentContext')) @@ -2324,8 +2414,9 @@ apiDescribe.only('Pipelines', persistence => { it('supports mapRemove', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select(mapRemove('awards', 'hugo').as('awards')) @@ -2334,8 +2425,9 @@ apiDescribe.only('Pipelines', persistence => { awards: { nebula: false } }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select(field('awards').mapRemove('hugo').as('awards')) @@ -2347,8 +2439,9 @@ apiDescribe.only('Pipelines', persistence => { it('supports mapMerge', async () => { let snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select(mapMerge('awards', { fakeAward: true }).as('awards')) @@ -2357,8 +2450,9 @@ apiDescribe.only('Pipelines', persistence => { awards: { nebula: false, hugo: false, fakeAward: true } }); snapshot = await execute( - randomCol + firestore .pipeline() + .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) .select(field('awards').mapMerge({ fakeAward: true }).as('awards')) @@ -2375,10 +2469,12 @@ apiDescribe.only('Pipelines', persistence => { * additional books support pagination test scenarios * that would otherwise not be possible with the original * set of books. - * @param collection + * @param collectionReference */ - async function addBooks(collection: CollectionReference): Promise { - await setDoc(doc(randomCol, 'book11'), { + async function addBooks( + collectionReference: CollectionReference + ): Promise { + await setDoc(doc(collectionReference, 'book11'), { title: 'Jonathan Strange & Mr Norrell', author: 'Susanna Clarke', genre: 'Fantasy', @@ -2387,7 +2483,7 @@ apiDescribe.only('Pipelines', persistence => { tags: ['historical fantasy', 'magic', 'alternate history', 'england'], awards: { hugo: false, nebula: false } }); - await setDoc(doc(randomCol, 'book12'), { + await setDoc(doc(collectionReference, 'book12'), { title: 'The Master and Margarita', author: 'Mikhail Bulgakov', genre: 'Satire', @@ -2401,7 +2497,7 @@ apiDescribe.only('Pipelines', persistence => { ], awards: {} }); - await setDoc(doc(randomCol, 'book13'), { + await setDoc(doc(collectionReference, 'book13'), { title: 'A Long Way to a Small, Angry Planet', author: 'Becky Chambers', genre: 'Science Fiction', @@ -2415,8 +2511,9 @@ apiDescribe.only('Pipelines', persistence => { it('supports pagination with filters', async () => { await addBooks(randomCol); const pageSize = 2; - const pipeline = randomCol + const pipeline = firestore .pipeline() + .collection(randomCol.path) .select('title', 'rating', '__name__') .sort(field('rating').descending(), field('__name__').ascending()); @@ -2454,8 +2551,9 @@ apiDescribe.only('Pipelines', persistence => { const secondFilterField = '__path__'; - const pipeline = randomCol + const pipeline = firestore .pipeline() + .collection(randomCol.path) .select('title', 'rating', secondFilterField) .sort( field('rating').descending(), From 38d505229572c056fb18b6579bd105bd801b8f83 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 6 Mar 2025 13:27:01 -0700 Subject: [PATCH 55/75] test fix --- packages/firestore/test/integration/api/pipeline.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index d5ccd6f41cb..2ed82824c2f 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -1467,7 +1467,7 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) - .where(field('tags').arrayContainsAll('adventure', 'magic')) + .where(field('tags').arrayContainsAll(['adventure', 'magic'])) .select('title') ); expectResults(snapshot, { title: 'The Lord of the Rings' }); From c7beb1dd97554d524ed60bdc89f5445abdaa5b04 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 6 Mar 2025 13:27:22 -0700 Subject: [PATCH 56/75] Refactor and rename all functions to match API proposal changes after API review. --- .../firestore/src/lite-api/expressions.ts | 1226 ++++++++--------- 1 file changed, 582 insertions(+), 644 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 7d9e4fd8f04..651a682eb96 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -80,6 +80,7 @@ function valueToDefaultExpr(value: any): Expr { return constant(value); } } + /** * Converts a value to an Expr, Returning either a Constant, MapFunction, * ArrayFunction, or the input itself (if it's already an expression). @@ -252,10 +253,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("value").mod(field("divisor")); * ``` * - * @param other The expression to divide by. + * @param expression The expression to divide by. * @return A new `Expr` representing the modulo operation. */ - mod(other: Expr): FunctionExpr; + mod(expression: Expr): FunctionExpr; /** * Creates an expression that calculates the modulo (remainder) of dividing this expression by a constant value. @@ -265,10 +266,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("value").mod(10); * ``` * - * @param other The constant value to divide by. + * @param value The constant value to divide by. * @return A new `Expr` representing the modulo operation. */ - mod(other: any): FunctionExpr; + mod(value: any): FunctionExpr; mod(other: any): FunctionExpr { return new FunctionExpr('mod', [this, valueToDefaultExpr(other)]); } @@ -281,10 +282,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("age").eq(21); * ``` * - * @param other The expression to compare for equality. + * @param expression The expression to compare for equality. * @return A new `Expr` representing the equality comparison. */ - eq(other: Expr): BooleanExpr; + eq(expression: Expr): BooleanExpr; /** * Creates an expression that checks if this expression is equal to a constant value. @@ -294,10 +295,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("city").eq("London"); * ``` * - * @param other The constant value to compare for equality. + * @param value The constant value to compare for equality. * @return A new `Expr` representing the equality comparison. */ - eq(other: any): BooleanExpr; + eq(value: any): BooleanExpr; eq(other: any): BooleanExpr { return new BooleanExpr('eq', [this, valueToDefaultExpr(other)]); } @@ -310,10 +311,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("status").neq("completed"); * ``` * - * @param other The expression to compare for inequality. + * @param expression The expression to compare for inequality. * @return A new `Expr` representing the inequality comparison. */ - neq(other: Expr): BooleanExpr; + neq(expression: Expr): BooleanExpr; /** * Creates an expression that checks if this expression is not equal to a constant value. @@ -323,10 +324,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("country").neq("USA"); * ``` * - * @param other The constant value to compare for inequality. + * @param value The constant value to compare for inequality. * @return A new `Expr` representing the inequality comparison. */ - neq(other: any): BooleanExpr; + neq(value: any): BooleanExpr; neq(other: any): BooleanExpr { return new BooleanExpr('neq', [this, valueToDefaultExpr(other)]); } @@ -339,10 +340,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("age").lt(field('limit')); * ``` * - * @param other The expression to compare for less than. + * @param experession The expression to compare for less than. * @return A new `Expr` representing the less than comparison. */ - lt(other: Expr): BooleanExpr; + lt(experession: Expr): BooleanExpr; /** * Creates an expression that checks if this expression is less than a constant value. @@ -352,10 +353,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("price").lt(50); * ``` * - * @param other The constant value to compare for less than. + * @param value The constant value to compare for less than. * @return A new `Expr` representing the less than comparison. */ - lt(other: any): BooleanExpr; + lt(value: any): BooleanExpr; lt(other: any): BooleanExpr { return new BooleanExpr('lt', [this, valueToDefaultExpr(other)]); } @@ -369,10 +370,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("quantity").lte(constant(20)); * ``` * - * @param other The expression to compare for less than or equal to. + * @param expression The expression to compare for less than or equal to. * @return A new `Expr` representing the less than or equal to comparison. */ - lte(other: Expr): BooleanExpr; + lte(expression: Expr): BooleanExpr; /** * Creates an expression that checks if this expression is less than or equal to a constant value. @@ -382,10 +383,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("score").lte(70); * ``` * - * @param other The constant value to compare for less than or equal to. + * @param value The constant value to compare for less than or equal to. * @return A new `Expr` representing the less than or equal to comparison. */ - lte(other: any): BooleanExpr; + lte(value: any): BooleanExpr; lte(other: any): BooleanExpr { return new BooleanExpr('lte', [this, valueToDefaultExpr(other)]); } @@ -398,10 +399,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("age").gt(field("limit")); * ``` * - * @param other The expression to compare for greater than. + * @param expression The expression to compare for greater than. * @return A new `Expr` representing the greater than comparison. */ - gt(other: Expr): BooleanExpr; + gt(expression: Expr): BooleanExpr; /** * Creates an expression that checks if this expression is greater than a constant value. @@ -411,10 +412,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("price").gt(100); * ``` * - * @param other The constant value to compare for greater than. + * @param value The constant value to compare for greater than. * @return A new `Expr` representing the greater than comparison. */ - gt(other: any): BooleanExpr; + gt(value: any): BooleanExpr; gt(other: any): BooleanExpr { return new BooleanExpr('gt', [this, valueToDefaultExpr(other)]); } @@ -428,10 +429,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("quantity").gte(field('requirement').add(1)); * ``` * - * @param other The expression to compare for greater than or equal to. + * @param expression The expression to compare for greater than or equal to. * @return A new `Expr` representing the greater than or equal to comparison. */ - gte(other: Expr): BooleanExpr; + gte(expression: Expr): BooleanExpr; /** * Creates an expression that checks if this expression is greater than or equal to a constant @@ -442,10 +443,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("score").gte(80); * ``` * - * @param other The constant value to compare for greater than or equal to. + * @param value The constant value to compare for greater than or equal to. * @return A new `Expr` representing the greater than or equal to comparison. */ - gte(other: any): BooleanExpr; + gte(value: any): BooleanExpr; gte(other: any): BooleanExpr { return new BooleanExpr('gte', [this, valueToDefaultExpr(other)]); } @@ -478,10 +479,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("sizes").arrayContains(field("selectedSize")); * ``` * - * @param element The element to search for in the array. + * @param expression The element to search for in the array. * @return A new `Expr` representing the 'array_contains' comparison. */ - arrayContains(element: Expr): BooleanExpr; + arrayContains(expression: Expr): BooleanExpr; /** * Creates an expression that checks if an array contains a specific value. @@ -491,10 +492,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("colors").arrayContains("red"); * ``` * - * @param element The element to search for in the array. + * @param value The element to search for in the array. * @return A new `Expr` representing the 'array_contains' comparison. */ - arrayContains(element: any): BooleanExpr; + arrayContains(value: any): BooleanExpr; arrayContains(element: any): BooleanExpr { return new BooleanExpr('array_contains', [ this, @@ -506,33 +507,32 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * Creates an expression that checks if an array contains all the specified elements. * * ```typescript - * // Check if the 'tags' array contains both "news" and "sports" - * field("tags").arrayContainsAll(field("tag1"), field("tag2")); + * // Check if the 'tags' array contains both the value in field "tag1" and the literal value "tag2" + * field("tags").arrayContainsAll([field("tag1"), "tag2"]); * ``` * * @param values The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_all' comparison. */ - arrayContainsAll(...values: Expr[]): BooleanExpr; + arrayContainsAll(values: Array): BooleanExpr; /** * Creates an expression that checks if an array contains all the specified elements. * * ```typescript - * // Check if the 'tags' array contains both of the values from field 'tag1' and "tag2" - * field("tags").arrayContainsAll(field("tag1"), field("tag2")); + * // Check if the 'tags' array contains both of the values from field "tag1" and the literal value "tag2" + * field("tags").arrayContainsAll(array([field("tag1"), "tag2"])); * ``` * - * @param values The elements to check for in the array. + * @param arrayExpression The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_all' comparison. */ - arrayContainsAll(...values: any[]): BooleanExpr; - arrayContainsAll(...values: any[]): BooleanExpr { - const exprValues = values.map(value => valueToDefaultExpr(value)); - return new BooleanExpr('array_contains_all', [ - this, - new ListOfExprs(exprValues) - ]); + arrayContainsAll(arrayExpression: Expr): BooleanExpr; + arrayContainsAll(values: any[] | Expr): BooleanExpr { + const normalizedExpr = Array.isArray(values) + ? new ListOfExprs(values.map(valueToDefaultExpr)) + : values; + return new BooleanExpr('array_contains_all', [this, normalizedExpr]); } /** @@ -540,13 +540,13 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'categories' array contains either values from field "cate1" or "cate2" - * field("categories").arrayContainsAny(field("cate1"), field("cate2")); + * field("categories").arrayContainsAny([field("cate1"), field("cate2")]); * ``` * * @param values The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_any' comparison. */ - arrayContainsAny(...values: Expr[]): BooleanExpr; + arrayContainsAny(values: Array): BooleanExpr; /** * Creates an expression that checks if an array contains any of the specified elements. @@ -554,19 +554,18 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * ```typescript * // Check if the 'groups' array contains either the value from the 'userGroup' field * // or the value "guest" - * field("groups").arrayContainsAny(field("userGroup"), "guest"); + * field("groups").arrayContainsAny(array([field("userGroup"), "guest"])); * ``` * - * @param values The elements to check for in the array. + * @param arrayExpression The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_any' comparison. */ - arrayContainsAny(...values: any[]): BooleanExpr; - arrayContainsAny(...values: any[]): BooleanExpr { - const exprValues = values.map(value => valueToDefaultExpr(value)); - return new BooleanExpr('array_contains_any', [ - this, - new ListOfExprs(exprValues) - ]); + arrayContainsAny(arrayExpression: Expr): BooleanExpr; + arrayContainsAny(values: Array | Expr): BooleanExpr { + const normalizedExpr = Array.isArray(values) + ? new ListOfExprs(values.map(valueToDefaultExpr)) + : values; + return new BooleanExpr('array_contains_any', [this, normalizedExpr]); } /** @@ -592,10 +591,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("category").eqAny("Electronics", field("primaryType")); * ``` * - * @param others The values or expressions to check against. + * @param values The values or expressions to check against. * @return A new `Expr` representing the 'IN' comparison. */ - eqAny(...others: Expr[]): BooleanExpr; + eqAny(values: Array): BooleanExpr; /** * Creates an expression that checks if this expression is equal to any of the provided values or @@ -603,16 +602,18 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'category' field is either "Electronics" or value of field 'primaryType' - * field("category").eqAny("Electronics", field("primaryType")); + * field("category").eqAny(array(["Electronics", field("primaryType")])); * ``` * - * @param others The values or expressions to check against. + * @param arrayExpression An expression that evaluates to an array of values to check against. * @return A new `Expr` representing the 'IN' comparison. */ - eqAny(...others: any[]): BooleanExpr; - eqAny(...others: any[]): BooleanExpr { - const exprOthers = others.map(other => valueToDefaultExpr(other)); - return new BooleanExpr('eq_any', [this, new ListOfExprs(exprOthers)]); + eqAny(arrayExpression: Expr): BooleanExpr; + eqAny(others: any[] | Expr): BooleanExpr { + const exprOthers = Array.isArray(others) + ? new ListOfExprs(others.map(valueToDefaultExpr)) + : others; + return new BooleanExpr('eq_any', [this, exprOthers]); } /** @@ -621,30 +622,31 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * field("status").notEqAny("pending", field("rejectedStatus")); + * field("status").notEqAny([]"pending", field("rejectedStatus")]); * ``` * - * @param others The values or expressions to check against. + * @param values The values or expressions to check against. * @return A new `Expr` representing the 'NotEqAny' comparison. */ - notEqAny(...others: Expr[]): BooleanExpr; + notEqAny(values: Array): BooleanExpr; /** - * Creates an expression that checks if this expression is not equal to any of the provided values or - * expressions. + * Creates an expression that checks if this expression is not equal to any of the values in the evaluated expression. * * ```typescript - * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * field("status").notEqAny("pending", field("rejectedStatus")); + * // Check if the 'status' field is not equal to any value in the field 'rejectedStatuses' + * field("status").notEqAny(field('rejectedStatuses')); * ``` * - * @param others The values or expressions to check against. + * @param arrayExpression The values or expressions to check against. * @return A new `Expr` representing the 'NotEqAny' comparison. */ - notEqAny(...others: any[]): BooleanExpr; - notEqAny(...others: any[]): BooleanExpr { - const exprOthers = others.map(other => valueToDefaultExpr(other)); - return new BooleanExpr('not_eq_any', [this, new ListOfExprs(exprOthers)]); + notEqAny(arrayExpression: Expr): BooleanExpr; + notEqAny(others: any[] | Expr): BooleanExpr { + const exprOthers = Array.isArray(others) + ? new ListOfExprs(others.map(valueToDefaultExpr)) + : others; + return new BooleanExpr('not_eq_any', [this, exprOthers]); } /** @@ -1214,10 +1216,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("userVector").cosineDistance(field("itemVector")); * ``` * - * @param other The other vector (represented as an Expr) to compare against. + * @param vectorExpression The other vector (represented as an Expr) to compare against. * @return A new `Expr` representing the cosine distance between the two vectors. */ - cosineDistance(other: Expr): FunctionExpr; + cosineDistance(vectorExpression: Expr): FunctionExpr; /** * Calculates the Cosine distance between two vectors. * @@ -1226,22 +1228,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("location").cosineDistance(new VectorValue([37.7749, -122.4194])); * ``` * - * @param other The other vector (as a VectorValue) to compare against. + * @param vector The other vector (as a VectorValue) to compare against. * @return A new `Expr` representing the Cosine* distance between the two vectors. */ - cosineDistance(other: VectorValue): FunctionExpr; - /** - * Calculates the Cosine distance between two vectors. - * - * ```typescript - * // Calculate the Cosine distance between the 'location' field and a target location - * field("location").cosineDistance([37.7749, -122.4194]); - * ``` - * - * @param other The other vector (as an array of numbers) to compare against. - * @return A new `Expr` representing the Cosine distance between the two vectors. - */ - cosineDistance(other: number[]): FunctionExpr; + cosineDistance(vector: VectorValue | number[]): FunctionExpr; cosineDistance(other: Expr | VectorValue | number[]): FunctionExpr { return new FunctionExpr('cosine_distance', [this, vectorToExpr(other)]); } @@ -1254,10 +1244,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("features").dotProduct([0.5, 0.8, 0.2]); * ``` * - * @param other The other vector (as an array of numbers) to calculate with. + * @param vectorExpression The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the dot product between the two vectors. */ - dotProduct(other: Expr): FunctionExpr; + dotProduct(vectorExpression: Expr): FunctionExpr; /** * Calculates the dot product between two vectors. @@ -1267,23 +1257,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("features").dotProduct(new VectorValue([0.5, 0.8, 0.2])); * ``` * - * @param other The other vector (as an array of numbers) to calculate with. - * @return A new `Expr` representing the dot product between the two vectors. - */ - dotProduct(other: VectorValue): FunctionExpr; - - /** - * Calculates the dot product between two vectors. - * - * ```typescript - * // Calculate the dot product between a feature vector and a target vector - * field("features").dotProduct([0.5, 0.8, 0.2]); - * ``` - * - * @param other The other vector (as an array of numbers) to calculate with. + * @param vector The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the dot product between the two vectors. */ - dotProduct(other: number[]): FunctionExpr; + dotProduct(vector: VectorValue | number[]): FunctionExpr; dotProduct(other: Expr | VectorValue | number[]): FunctionExpr { return new FunctionExpr('dot_product', [this, vectorToExpr(other)]); } @@ -1296,10 +1273,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("location").euclideanDistance([37.7749, -122.4194]); * ``` * - * @param other The other vector (as an array of numbers) to calculate with. + * @param vectorExpression The other vector (as an array of numbers) to calculate with. * @return A new `Expr` representing the Euclidean distance between the two vectors. */ - euclideanDistance(other: Expr): FunctionExpr; + euclideanDistance(vectorExpression: Expr): FunctionExpr; /** * Calculates the Euclidean distance between two vectors. @@ -1309,26 +1286,14 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("location").euclideanDistance(new VectorValue([37.7749, -122.4194])); * ``` * - * @param other The other vector (as a VectorValue) to compare against. - * @return A new `Expr` representing the Euclidean distance between the two vectors. - */ - euclideanDistance(other: VectorValue): FunctionExpr; - - /** - * Calculates the Euclidean distance between two vectors. - * - * ```typescript - * // Calculate the Euclidean distance between the 'location' field and a target location - * field("location").euclideanDistance([37.7749, -122.4194]); - * ``` - * - * @param other The other vector (as an array of numbers) to compare against. + * @param vector The other vector (as a VectorValue) to compare against. * @return A new `Expr` representing the Euclidean distance between the two vectors. */ - euclideanDistance(other: number[]): FunctionExpr; + euclideanDistance(vector: VectorValue | number[]): FunctionExpr; euclideanDistance(other: Expr | VectorValue | number[]): FunctionExpr { return new FunctionExpr('euclidean_distance', [this, vectorToExpr(other)]); } + /** * @beta * @@ -1339,25 +1304,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("location").manhattanDistance(new VectorValue([37.7749, -122.4194])); * ``` * - * @param other The other vector (as a VectorValue) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ - manhattanDistance(other: VectorValue): FunctionExpr; - - /** - * @beta - * - * Calculates the Manhattan distance between the result of this expression and a double array. - * - * ```typescript - * // Calculate the Manhattan distance between the 'location' field and a target location - * field("location").manhattanDistance([37.7749, -122.4194]); - * ``` - * - * @param other The other vector (as an array of doubles) to compare against. + * @param vector The other vector (as a VectorValue) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ - manhattanDistance(other: number[]): FunctionExpr; + manhattanDistance(vector: VectorValue | number[]): FunctionExpr; /** * @beta @@ -1369,10 +1319,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * field("pointA").manhattanDistance(field("pointB")); * ``` * - * @param other The other vector (represented as an Expr) to compare against. + * @param vectorExpression The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ - manhattanDistance(other: Expr): FunctionExpr; + manhattanDistance(vectorExpression: Expr): FunctionExpr; manhattanDistance(other: Expr | number[] | VectorValue): FunctionExpr { return new FunctionExpr('manhattan_distance', [this, vectorToExpr(other)]); } @@ -3602,11 +3552,11 @@ export function subtract(left: Expr, right: Expr): FunctionExpr; * subtract(field("value"), 2); * ``` * - * @param left The expression to subtract from. - * @param right The constant value to subtract. + * @param expression The expression to subtract from. + * @param value The constant value to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: Expr, right: any): FunctionExpr; +export function subtract(expression: Expr, value: any): FunctionExpr; /** * @beta @@ -3618,11 +3568,11 @@ export function subtract(left: Expr, right: any): FunctionExpr; * subtract("price", field("discount")); * ``` * - * @param left The field name to subtract from. - * @param right The expression to subtract. + * @param fieldName The field name to subtract from. + * @param expression The expression to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: string, right: Expr): FunctionExpr; +export function subtract(fieldName: string, expression: Expr): FunctionExpr; /** * @beta @@ -3634,11 +3584,11 @@ export function subtract(left: string, right: Expr): FunctionExpr; * subtract("total", 20); * ``` * - * @param left The field name to subtract from. - * @param right The constant value to subtract. + * @param fieldName The field name to subtract from. + * @param value The constant value to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(left: string, right: any): FunctionExpr; +export function subtract(fieldName: string, value: any): FunctionExpr; export function subtract(left: Expr | string, right: Expr | any): FunctionExpr { const normalizedLeft = typeof left === 'string' ? field(left) : left; const normalizedRight = valueToDefaultExpr(right); @@ -3724,11 +3674,11 @@ export function divide(left: Expr, right: Expr): FunctionExpr; * divide(field("value"), 10); * ``` * - * @param left The expression to be divided. - * @param right The constant value to divide by. + * @param expression The expression to be divided. + * @param value The constant value to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: Expr, right: any): FunctionExpr; +export function divide(expression: Expr, value: any): FunctionExpr; /** * @beta @@ -3740,11 +3690,11 @@ export function divide(left: Expr, right: any): FunctionExpr; * divide("total", field("count")); * ``` * - * @param left The field name to be divided. - * @param right The expression to divide by. + * @param fieldName The field name to be divided. + * @param expressions The expression to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: string, right: Expr): FunctionExpr; +export function divide(fieldName: string, expressions: Expr): FunctionExpr; /** * @beta @@ -3756,11 +3706,11 @@ export function divide(left: string, right: Expr): FunctionExpr; * divide("value", 10); * ``` * - * @param left The field name to be divided. - * @param right The constant value to divide by. + * @param fieldName The field name to be divided. + * @param value The constant value to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(left: string, right: any): FunctionExpr; +export function divide(fieldName: string, value: any): FunctionExpr; export function divide(left: Expr | string, right: Expr | any): FunctionExpr { const normalizedLeft = typeof left === 'string' ? field(left) : left; const normalizedRight = valueToDefaultExpr(right); @@ -3793,11 +3743,11 @@ export function mod(left: Expr, right: Expr): FunctionExpr; * mod(field("field1"), 5); * ``` * - * @param left The dividend expression. - * @param right The divisor constant. + * @param expression The dividend expression. + * @param value The divisor constant. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: Expr, right: any): FunctionExpr; +export function mod(expression: Expr, value: any): FunctionExpr; /** * @beta @@ -3809,11 +3759,11 @@ export function mod(left: Expr, right: any): FunctionExpr; * mod("field1", field("field2")); * ``` * - * @param left The dividend field name. - * @param right The divisor expression. + * @param fieldName The dividend field name. + * @param expression The divisor expression. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: string, right: Expr): FunctionExpr; +export function mod(fieldName: string, expression: Expr): FunctionExpr; /** * @beta @@ -3825,17 +3775,30 @@ export function mod(left: string, right: Expr): FunctionExpr; * mod("field1", 5); * ``` * - * @param left The dividend field name. - * @param right The divisor constant. + * @param fieldName The dividend field name. + * @param value The divisor constant. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(left: string, right: any): FunctionExpr; +export function mod(fieldName: string, value: any): FunctionExpr; export function mod(left: Expr | string, right: Expr | any): FunctionExpr { const normalizedLeft = typeof left === 'string' ? field(left) : left; const normalizedRight = valueToDefaultExpr(right); return normalizedLeft.mod(normalizedRight); } +/** + * @beta + * + * Creates an expression that creates a Firestore map value from an input object. + * + * ```typescript + * // Create a map from the input object and reference the 'baz' field value from the input document. + * map({foo: 'bar', baz: Field.of('baz')}).as('data'); + * ``` + * + * @param elements The input map to evaluate in the expression. + * @return A new {@code Expr} representing the map function. + */ export function map(elements: Record): FunctionExpr { const result: any[] = []; for (const key in elements) { @@ -3870,6 +3833,19 @@ export function _mapValue(plainObject: Record): MapValue { return new MapValue(result); } +/** + * @beta + * + * Creates an expression that creates a Firestore array value from an input array. + * + * ```typescript + * // Create an array value from the input array and reference the 'baz' field value from the input document. + * array(['bar', Field.of('baz')]).as('foo'); + * ``` + * + * @param elements The input array to evaluate in the expression. + * @return A new {@code Expr} representing the array function. + */ export function array(elements: any[]): FunctionExpr { return new FunctionExpr( 'array', @@ -3903,11 +3879,11 @@ export function eq(left: Expr, right: Expr): BooleanExpr; * eq(field("age"), 21); * ``` * - * @param left The expression to compare. - * @param right The constant value to compare to. + * @param expression The expression to compare. + * @param value The constant value to compare to. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: Expr, right: any): BooleanExpr; +export function eq(expression: Expr, value: any): BooleanExpr; /** * @beta @@ -3919,11 +3895,11 @@ export function eq(left: Expr, right: any): BooleanExpr; * eq("age", field("limit")); * ``` * - * @param left The field name to compare. - * @param right The expression to compare to. + * @param fieldName The field name to compare. + * @param expression The expression to compare to. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: string, right: Expr): BooleanExpr; +export function eq(fieldName: string, expression: Expr): BooleanExpr; /** * @beta @@ -3935,11 +3911,11 @@ export function eq(left: string, right: Expr): BooleanExpr; * eq("city", "London"); * ``` * - * @param left The field name to compare. - * @param right The constant value to compare to. + * @param fieldName The field name to compare. + * @param value The constant value to compare to. * @return A new `Expr` representing the equality comparison. */ -export function eq(left: string, right: any): BooleanExpr; +export function eq(fieldName: string, value: any): BooleanExpr; export function eq(left: Expr | string, right: any): BooleanExpr { const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); @@ -3972,11 +3948,11 @@ export function neq(left: Expr, right: Expr): BooleanExpr; * neq(field("status"), "completed"); * ``` * - * @param left The expression to compare. - * @param right The constant value to compare to. + * @param expression The expression to compare. + * @param value The constant value to compare to. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: Expr, right: any): BooleanExpr; +export function neq(expression: Expr, value: any): BooleanExpr; /** * @beta @@ -3988,11 +3964,11 @@ export function neq(left: Expr, right: any): BooleanExpr; * neq("status", field("expectedStatus")); * ``` * - * @param left The field name to compare. - * @param right The expression to compare to. + * @param fieldName The field name to compare. + * @param expression The expression to compare to. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: string, right: Expr): BooleanExpr; +export function neq(fieldName: string, expression: Expr): BooleanExpr; /** * @beta @@ -4004,11 +3980,11 @@ export function neq(left: string, right: Expr): BooleanExpr; * neq("country", "USA"); * ``` * - * @param left The field name to compare. - * @param right The constant value to compare to. + * @param fieldName The field name to compare. + * @param value The constant value to compare to. * @return A new `Expr` representing the inequality comparison. */ -export function neq(left: string, right: any): BooleanExpr; +export function neq(fieldName: string, value: any): BooleanExpr; export function neq(left: Expr | string, right: any): BooleanExpr { const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); @@ -4041,11 +4017,11 @@ export function lt(left: Expr, right: Expr): BooleanExpr; * lt(field("age"), 30); * ``` * - * @param left The expression to compare. - * @param right The constant value to compare to. + * @param expression The expression to compare. + * @param value The constant value to compare to. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: Expr, right: any): BooleanExpr; +export function lt(expression: Expr, value: any): BooleanExpr; /** * @beta @@ -4057,11 +4033,11 @@ export function lt(left: Expr, right: any): BooleanExpr; * lt("age", field("limit")); * ``` * - * @param left The field name to compare. - * @param right The expression to compare to. + * @param fieldName The field name to compare. + * @param expression The expression to compare to. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: string, right: Expr): BooleanExpr; +export function lt(fieldName: string, expression: Expr): BooleanExpr; /** * @beta @@ -4073,11 +4049,11 @@ export function lt(left: string, right: Expr): BooleanExpr; * lt("price", 50); * ``` * - * @param left The field name to compare. - * @param right The constant value to compare to. + * @param fieldName The field name to compare. + * @param value The constant value to compare to. * @return A new `Expr` representing the less than comparison. */ -export function lt(left: string, right: any): BooleanExpr; +export function lt(fieldName: string, value: any): BooleanExpr; export function lt(left: Expr | string, right: any): BooleanExpr { const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); @@ -4111,11 +4087,11 @@ export function lte(left: Expr, right: Expr): BooleanExpr; * lte(field("quantity"), 20); * ``` * - * @param left The expression to compare. - * @param right The constant value to compare to. + * @param expression The expression to compare. + * @param value The constant value to compare to. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: Expr, right: any): BooleanExpr; +export function lte(expression: Expr, value: any): BooleanExpr; /** * Creates an expression that checks if a field's value is less than or equal to an expression. @@ -4125,11 +4101,11 @@ export function lte(left: Expr, right: any): BooleanExpr; * lte("quantity", field("limit")); * ``` * - * @param left The field name to compare. - * @param right The expression to compare to. + * @param fieldName The field name to compare. + * @param expression The expression to compare to. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: string, right: Expr): BooleanExpr; +export function lte(fieldName: string, expression: Expr): BooleanExpr; /** * @beta @@ -4141,11 +4117,11 @@ export function lte(left: string, right: Expr): BooleanExpr; * lte("score", 70); * ``` * - * @param left The field name to compare. - * @param right The constant value to compare to. + * @param fieldName The field name to compare. + * @param value The constant value to compare to. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(left: string, right: any): BooleanExpr; +export function lte(fieldName: string, value: any): BooleanExpr; export function lte(left: Expr | string, right: any): BooleanExpr { const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); @@ -4179,11 +4155,11 @@ export function gt(left: Expr, right: Expr): BooleanExpr; * gt(field("age"), 18); * ``` * - * @param left The expression to compare. - * @param right The constant value to compare to. + * @param expression The expression to compare. + * @param value The constant value to compare to. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: Expr, right: any): BooleanExpr; +export function gt(expression: Expr, value: any): BooleanExpr; /** * @beta @@ -4195,11 +4171,11 @@ export function gt(left: Expr, right: any): BooleanExpr; * gt("age", field("limit")); * ``` * - * @param left The field name to compare. - * @param right The expression to compare to. + * @param fieldName The field name to compare. + * @param expression The expression to compare to. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: string, right: Expr): BooleanExpr; +export function gt(fieldName: string, expression: Expr): BooleanExpr; /** * @beta @@ -4211,11 +4187,11 @@ export function gt(left: string, right: Expr): BooleanExpr; * gt("price", 100); * ``` * - * @param left The field name to compare. - * @param right The constant value to compare to. + * @param fieldName The field name to compare. + * @param value The constant value to compare to. * @return A new `Expr` representing the greater than comparison. */ -export function gt(left: string, right: any): BooleanExpr; +export function gt(fieldName: string, value: any): BooleanExpr; export function gt(left: Expr | string, right: any): BooleanExpr { const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); @@ -4250,11 +4226,11 @@ export function gte(left: Expr, right: Expr): BooleanExpr; * gte(field("quantity"), 10); * ``` * - * @param left The expression to compare. - * @param right The constant value to compare to. + * @param expression The expression to compare. + * @param value The constant value to compare to. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: Expr, right: any): BooleanExpr; +export function gte(expression: Expr, value: any): BooleanExpr; /** * @beta @@ -4266,11 +4242,11 @@ export function gte(left: Expr, right: any): BooleanExpr; * gte("age", field("limit")); * ``` * - * @param left The field name to compare. - * @param right The expression to compare to. + * @param fieldName The field name to compare. + * @param value The expression to compare to. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: string, right: Expr): BooleanExpr; +export function gte(fieldName: string, value: Expr): BooleanExpr; /** * @beta @@ -4283,11 +4259,11 @@ export function gte(left: string, right: Expr): BooleanExpr; * gte("score", 80); * ``` * - * @param left The field name to compare. - * @param right The constant value to compare to. + * @param fieldName The field name to compare. + * @param value The constant value to compare to. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(left: string, right: any): BooleanExpr; +export function gte(fieldName: string, value: any): BooleanExpr; export function gte(left: Expr | string, right: any): BooleanExpr { const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); @@ -4390,11 +4366,11 @@ export function arrayContains(array: Expr, element: any): FunctionExpr; * arrayContains("colors", field("selectedColor")); * ``` * - * @param array The field name to check. + * @param fieldName The field name to check. * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains(array: string, element: Expr): FunctionExpr; +export function arrayContains(fieldName: string, element: Expr): FunctionExpr; /** * @beta @@ -4406,11 +4382,11 @@ export function arrayContains(array: string, element: Expr): FunctionExpr; * arrayContains("colors", "red"); * ``` * - * @param array The field name to check. + * @param fieldName The field name to check. * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains(array: string, element: any): BooleanExpr; +export function arrayContains(fieldName: string, element: any): BooleanExpr; export function arrayContains(array: Expr | string, element: any): BooleanExpr { const arrayExpr = fieldOfOrExpr(array); const elementExpr = valueToDefaultExpr(element); @@ -4432,42 +4408,48 @@ export function arrayContains(array: Expr | string, element: any): BooleanExpr { * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_any' comparison. */ -export function arrayContainsAny(array: Expr, values: Expr[]): BooleanExpr; +export function arrayContainsAny( + array: Expr, + values: Array +): BooleanExpr; /** * @beta * - * Creates an expression that checks if an array expression contains any of the specified + * Creates an expression that checks if a field's array value contains any of the specified * elements. * * ```typescript - * // Check if the 'categories' array contains either values from field "cate1" or "Science" - * arrayContainsAny(field("categories"), [field("cate1"), "Science"]); + * // Check if the 'groups' array contains either the value from the 'userGroup' field + * // or the value "guest" + * arrayContainsAny("categories", [field("cate1"), "Science"]); * ``` * - * @param array The array expression to check. + * @param fieldName The field name to check. * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_any' comparison. */ -export function arrayContainsAny(array: Expr, values: any[]): BooleanExpr; +export function arrayContainsAny( + fieldName: string, + values: Array +): BooleanExpr; /** * @beta * - * Creates an expression that checks if a field's array value contains any of the specified + * Creates an expression that checks if an array expression contains any of the specified * elements. * * ```typescript - * // Check if the 'groups' array contains either the value from the 'userGroup' field - * // or the value "guest" - * arrayContainsAny("categories", [field("cate1"), "Science"]); + * // Check if the 'categories' array contains either values from field "cate1" or "Science" + * arrayContainsAny(field("categories"), array([field("cate1"), "Science"])); * ``` * - * @param array The field name to check. - * @param values The elements to check for in the array. + * @param array The array expression to check. + * @param values An expression that evaluates to an array, whose elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_any' comparison. */ -export function arrayContainsAny(array: string, values: Expr[]): BooleanExpr; +export function arrayContainsAny(array: Expr, values: Expr): BooleanExpr; /** * @beta @@ -4478,21 +4460,20 @@ export function arrayContainsAny(array: string, values: Expr[]): BooleanExpr; * ```typescript * // Check if the 'groups' array contains either the value from the 'userGroup' field * // or the value "guest" - * arrayContainsAny("categories", [field("cate1"), "Science"]); + * arrayContainsAny("categories", array([field("cate1"), "Science"])); * ``` * - * @param array The field name to check. - * @param values The elements to check for in the array. + * @param fieldName The field name to check. + * @param values An expression that evaluates to an array, whose elements to check for in the array field. * @return A new {@code Expr} representing the 'array_contains_any' comparison. */ -export function arrayContainsAny(array: string, values: any[]): BooleanExpr; +export function arrayContainsAny(fieldName: string, values: Expr): BooleanExpr; export function arrayContainsAny( array: Expr | string, - values: any[] + values: any[] | Expr ): BooleanExpr { - return fieldOfOrExpr(array).arrayContainsAny( - ...values.map(valueToDefaultExpr) - ); + // @ts-ignore implementation accepts both types + return fieldOfOrExpr(array).arrayContainsAny(values); } /** @@ -4502,47 +4483,56 @@ export function arrayContainsAny( * * ```typescript * // Check if the "tags" array contains all of the values: "SciFi", "Adventure", and the value from field "tag1" - * arrayContainsAll(field("tags"), [field("tag1"), constant("SciFi"), constant("Adventure")]); + * arrayContainsAll(field("tags"), [field("tag1"), constant("SciFi"), "Adventure"]); * ``` * * @param array The array expression to check. * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_all' comparison. */ -export function arrayContainsAll(array: Expr, values: Expr[]): BooleanExpr; +export function arrayContainsAll( + array: Expr, + values: Array +): BooleanExpr; /** * @beta * - * Creates an expression that checks if an array expression contains all the specified elements. + * Creates an expression that checks if a field's array value contains all the specified values or + * expressions. * * ```typescript - * // Check if the "tags" array contains all of the values: "SciFi", "Adventure", and the value from field "tag1" - * arrayContainsAll(field("tags"), [field("tag1"), "SciFi", "Adventure"]); + * // Check if the 'tags' array contains both of the values from field 'tag1', the value "SciFi", and "Adventure" + * arrayContainsAll("tags", [field("tag1"), "SciFi", "Adventure"]); * ``` * - * @param array The array expression to check. + * @param fieldName The field name to check. * @param values The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_all' comparison. */ -export function arrayContainsAll(array: Expr, values: any[]): BooleanExpr; +export function arrayContainsAll( + fieldName: string, + values: Array +): BooleanExpr; /** * @beta * - * Creates an expression that checks if a field's array value contains all the specified values or - * expressions. + * Creates an expression that checks if an array expression contains all the specified elements. * * ```typescript - * // Check if the 'tags' array contains both of the values from field 'tag1' and "tag2" - * arrayContainsAll("tags", [field("tag1"), "SciFi", "Adventure"]); + * // Check if the "tags" array contains all of the values: "SciFi", "Adventure", and the value from field "tag1" + * arrayContainsAll(field("tags"), [field("tag1"), constant("SciFi"), "Adventure"]); * ``` * - * @param array The field name to check. - * @param values The elements to check for in the array. + * @param array The array expression to check. + * @param arrayExpression The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_all' comparison. */ -export function arrayContainsAll(array: string, values: Expr[]): BooleanExpr; +export function arrayContainsAll( + array: Expr, + arrayExpression: Expr +): BooleanExpr; /** * @beta @@ -4551,22 +4541,24 @@ export function arrayContainsAll(array: string, values: Expr[]): BooleanExpr; * expressions. * * ```typescript - * // Check if the 'tags' array contains both of the values from field 'tag1' and "tag2" + * // Check if the 'tags' array contains both of the values from field 'tag1', the value "SciFi", and "Adventure" * arrayContainsAll("tags", [field("tag1"), "SciFi", "Adventure"]); * ``` * - * @param array The field name to check. - * @param values The elements to check for in the array. + * @param fieldName The field name to check. + * @param arrayExpression The elements to check for in the array. * @return A new {@code Expr} representing the 'array_contains_all' comparison. */ -export function arrayContainsAll(array: string, values: any[]): BooleanExpr; +export function arrayContainsAll( + fieldName: string, + arrayExpression: Expr +): BooleanExpr; export function arrayContainsAll( array: Expr | string, - values: any[] + values: any[] | Expr ): BooleanExpr { - const arrayExpr = fieldOfOrExpr(array); - const exprValues = values.map(value => valueToDefaultExpr(value)); - return arrayExpr.arrayContainsAll(exprValues); + // @ts-ignore implementation accepts both types + return fieldOfOrExpr(array).arrayContainsAll(values); } /** @@ -4589,7 +4581,7 @@ export function arrayLength(array: Expr): FunctionExpr { /** * @beta * - * Creates an expression that checks if an expression is equal to any of the provided values or + * Creates an expression that checks if an expression, when evaluated, is equal to any of the provided values or * expressions. * * ```typescript @@ -4597,28 +4589,27 @@ export function arrayLength(array: Expr): FunctionExpr { * eqAny(field("category"), [constant("Electronics"), field("primaryType")]); * ``` * - * @param element The expression to compare. - * @param others The values to check against. + * @param expression The expression whose results to compare. + * @param values The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: Expr, others: Expr[]): BooleanExpr; +export function eqAny(expression: Expr, values: Array): BooleanExpr; /** * @beta * - * Creates an expression that checks if an expression is equal to any of the provided values or - * expressions. + * Creates an expression that checks if an expression is equal to any of the provided values. * * ```typescript - * // Check if the 'category' field is either "Electronics" or value of field 'primaryType' - * eqAny(field("category"), ["Electronics", field("primaryType")]); + * // Check if the 'category' field is set to a value in the disabledCategories field + * eqAny(field("category"), field('disabledCategories')); * ``` * - * @param element The expression to compare. - * @param others The values to check against. + * @param expression The expression whose results to compare. + * @param arrayExpression An expression that evaluates to an array, whose elements to check for equality to the input. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: Expr, others: any[]): BooleanExpr; +export function eqAny(expression: Expr, arrayExpression: Expr): BooleanExpr; /** * @beta @@ -4631,11 +4622,14 @@ export function eqAny(element: Expr, others: any[]): BooleanExpr; * eqAny("category", [constant("Electronics"), field("primaryType")]); * ``` * - * @param element The field to compare. - * @param others The values to check against. + * @param fieldName The field to compare. + * @param values The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: string, others: Expr[]): BooleanExpr; +export function eqAny( + fieldName: string, + values: Array +): BooleanExpr; /** * @beta @@ -4648,15 +4642,17 @@ export function eqAny(element: string, others: Expr[]): BooleanExpr; * eqAny("category", ["Electronics", field("primaryType")]); * ``` * - * @param element The field to compare. - * @param others The values to check against. + * @param fieldName The field to compare. + * @param arrayExpression An expression that evaluates to an array, whose elements to check for equality to the input field. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(element: string, others: any[]): BooleanExpr; -export function eqAny(element: Expr | string, others: any[]): BooleanExpr { - const elementExpr = fieldOfOrExpr(element); - const exprOthers = others.map(other => valueToDefaultExpr(other)); - return elementExpr.eqAny(...exprOthers); +export function eqAny(fieldName: string, arrayExpression: Expr): BooleanExpr; +export function eqAny( + element: Expr | string, + values: any[] | Expr +): BooleanExpr { + // @ts-ignore implementation accepts both types + return fieldOfOrExpr(element).eqAny(values); } /** @@ -4667,76 +4663,80 @@ export function eqAny(element: Expr | string, others: any[]): BooleanExpr { * * ```typescript * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * notEqAny(field("status"), [constant("pending"), field("rejectedStatus")]); + * notEqAny(field("status"), ["pending", field("rejectedStatus")]); * ``` * * @param element The expression to compare. - * @param others The values to check against. + * @param values The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: Expr, others: Expr[]): BooleanExpr; +export function notEqAny(element: Expr, values: Array): BooleanExpr; /** * @beta * - * Creates an expression that checks if an expression is not equal to any of the provided values + * Creates an expression that checks if a field's value is not equal to any of the provided values * or expressions. * * ```typescript * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * notEqAny(field("status"), ["pending", field("rejectedStatus")]); + * notEqAny("status", [constant("pending"), field("rejectedStatus")]); * ``` * - * @param element The expression to compare. - * @param others The values to check against. + * @param fieldName The field name to compare. + * @param values The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: Expr, others: any[]): BooleanExpr; +export function notEqAny( + fieldName: string, + values: Array +): BooleanExpr; /** * @beta * - * Creates an expression that checks if a field's value is not equal to any of the provided values + * Creates an expression that checks if an expression is not equal to any of the provided values * or expressions. * * ```typescript - * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * notEqAny("status", [constant("pending"), field("rejectedStatus")]); + * // Check if the 'status' field is neither "pending" nor the value of the field 'rejectedStatus' + * notEqAny(field("status"), ["pending", field("rejectedStatus")]); * ``` * - * @param element The field name to compare. - * @param others The values to check against. + * @param element The expression to compare. + * @param arrayExpression The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: string, others: Expr[]): BooleanExpr; +export function notEqAny(element: Expr, arrayExpression: Expr): BooleanExpr; /** * @beta * - * Creates an expression that checks if a field's value is not equal to any of the provided values - * or expressions. + * Creates an expression that checks if a field's value is not equal to any of the values in the evaluated expression. * * ```typescript - * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * notEqAny("status", ["pending", field("rejectedStatus")]); + * // Check if the 'status' field is not equal to any value in the field 'rejectedStatuses' + * notEqAny("status", field("rejectedStatuses")); * ``` * - * @param element The field name to compare. - * @param others The values to check against. + * @param fieldName The field name to compare. + * @param arrayExpression The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: string, others: any[]): BooleanExpr; -export function notEqAny(element: Expr | string, others: any[]): BooleanExpr { - const elementExpr = fieldOfOrExpr(element); - const exprOthers = others.map(other => valueToDefaultExpr(other)); - return elementExpr.notEqAny(...exprOthers); +export function notEqAny(fieldName: string, arrayExpression: Expr): BooleanExpr; + +export function notEqAny( + element: Expr | string, + values: any[] | Expr +): BooleanExpr { + // @ts-ignore implementation accepts both types + return fieldOfOrExpr(element).notEqAny(values); } /** * @beta * - * Creates an expression that performs a logical 'XOR' (exclusive OR) operation on multiple filter - * conditions. + * Creates an expression that performs a logical 'XOR' (exclusive OR) operation on multiple BooleanExpressions. * * ```typescript * // Check if only one of the conditions is true: 'age' greater than 18, 'city' is "London", @@ -4747,17 +4747,17 @@ export function notEqAny(element: Expr | string, others: any[]): BooleanExpr { * eq("status", "active")); * ``` * - * @param first The first filter condition. - * @param second The second filter condition. - * @param more Additional filter conditions to 'XOR' together. + * @param first The first condition. + * @param second The second condition. + * @param additionalConditions Additional conditions to 'XOR' together. * @return A new {@code Expr} representing the logical 'XOR' operation. */ export function xor( first: BooleanExpr, second: BooleanExpr, - ...more: BooleanExpr[] + ...additionalConditions: BooleanExpr[] ): BooleanExpr { - return new BooleanExpr('xor', [first, second, ...more]); + return new BooleanExpr('xor', [first, second, ...additionalConditions]); } /** @@ -4782,7 +4782,7 @@ export function cond( thenExpr: Expr, elseExpr: Expr ): FunctionExpr { - return new BooleanExpr('cond', [condition, thenExpr, elseExpr]); + return new FunctionExpr('cond', [condition, thenExpr, elseExpr]); } /** @@ -4795,21 +4795,23 @@ export function cond( * not(eq("completed", true)); * ``` * - * @param filter The filter condition to negate. + * @param booleanExpr The filter condition to negate. * @return A new {@code Expr} representing the negated filter condition. */ -export function not(filter: BooleanExpr): BooleanExpr { - return filter.not(); +export function not(booleanExpr: BooleanExpr): BooleanExpr { + return booleanExpr.not(); } /** * @beta * - * Creates an expression that returns the larger value between two expressions, based on Firestore's value type ordering. + * Creates an expression that returns the largest value between multiple input + * expressions or literal values. Based on Firestore's value type ordering. * * ```typescript - * // Returns the larger value between the 'field1' field and the 'field2' field. - * logicalMaximum(field("field1"), field("field2")); + * // Returns the largest value between the 'field1' field, the 'field2' field, + * // and 1000 + * logicalMaximum(field("field1"), field("field2"), 1000); * ``` * * @param first The first operand expression. @@ -4826,11 +4828,13 @@ export function logicalMaximum( /** * @beta * - * Creates an expression that returns the larger value between a field and an expression, based on Firestore's value type ordering. + * Creates an expression that returns the largest value between multiple input + * expressions or literal values. Based on Firestore's value type ordering. * * ```typescript - * // Returns the larger value between the 'field1' field and the 'field2' field. - * logicalMaximum("field1", field('field2')); + * // Returns the largest value between the 'field1' field, the 'field2' field, + * // and 1000. + * logicalMaximum("field1", field("field2"), 1000); * ``` * * @param fieldName The first operand field name. @@ -4839,7 +4843,7 @@ export function logicalMaximum( * @return A new {@code Expr} representing the logical max operation. */ export function logicalMaximum( - left: string, + fieldName: string, second: Expr | any, ...others: Array ): FunctionExpr; @@ -4858,11 +4862,13 @@ export function logicalMaximum( /** * @beta * - * Creates an expression that returns the smaller value between two expressions, based on Firestore's value type ordering. + * Creates an expression that returns the smallest value between multiple input + * expressions and literal values. Based on Firestore's value type ordering. * * ```typescript - * // Returns the smaller value between the 'field1' field and the 'field2' field. - * logicalMinimum(field("field1"), field("field2")); + * // Returns the smallest value between the 'field1' field, the 'field2' field, + * // and 1000. + * logicalMinimum(field("field1"), field("field2"), 1000); * ``` * * @param first The first operand expression. @@ -4879,11 +4885,14 @@ export function logicalMinimum( /** * @beta * - * Creates an expression that returns the smaller value between a field and an expression, based on Firestore's value type ordering. + * Creates an expression that returns the smallest value between a field's value + * and other input expressions or literal values. + * Based on Firestore's value type ordering. * * ```typescript - * // Returns the smaller value between the 'field1' field and the 'field2' field. - * logicalMinimum("field1", field("field2")); + * // Returns the smallest value between the 'field1' field, the 'field2' field, + * // and 1000. + * logicalMinimum("field1", field("field2"), 1000); * ``` * * @param fieldName The first operand field name. @@ -4933,10 +4942,10 @@ export function exists(value: Expr): BooleanExpr; * exists("phoneNumber"); * ``` * - * @param field The field name to check. + * @param fieldName The field name to check. * @return A new {@code Expr} representing the 'exists' check. */ -export function exists(field: string): BooleanExpr; +export function exists(fieldName: string): BooleanExpr; export function exists(valueOrField: Expr | string): BooleanExpr { return fieldOfOrExpr(valueOrField).exists(); } @@ -4966,10 +4975,10 @@ export function isNan(value: Expr): BooleanExpr; * isNaN("value"); * ``` * - * @param value The name of the field to check. + * @param fieldName The name of the field to check. * @return A new {@code Expr} representing the 'isNaN' check. */ -export function isNan(value: string): BooleanExpr; +export function isNan(fieldName: string): BooleanExpr; export function isNan(value: Expr | string): BooleanExpr { return fieldOfOrExpr(value).isNan(); } @@ -4984,15 +4993,15 @@ export function isNan(value: Expr | string): BooleanExpr { * reverse(field("myString")); * ``` * - * @param expr The expression representing the string to reverse. + * @param stringExpression An expression evaluating to a string value, which will be reversed. * @return A new {@code Expr} representing the reversed string. */ -export function reverse(expr: Expr): FunctionExpr; +export function reverse(stringExpression: Expr): FunctionExpr; /** * @beta * - * Creates an expression that reverses a string represented by a field. + * Creates an expression that reverses a string value in the specified field. * * ```typescript * // Reverse the value of the 'myString' field. @@ -5060,13 +5069,13 @@ export function replaceFirst( * replaceFirst("message", "hello", "hi"); * ``` * - * @param field The name of the field representing the string to perform the replacement on. + * @param fieldName The name of the field representing the string to perform the replacement on. * @param find The substring to search for. * @param replace The substring to replace the first occurrence of 'find' with. * @return A new {@code Expr} representing the string with the first occurrence replaced. */ export function replaceFirst( - field: string, + fieldName: string, find: string, replace: string ): FunctionExpr; @@ -5134,13 +5143,13 @@ export function replaceAll( * replaceAll("message", "hello", "hi"); * ``` * - * @param field The name of the field representing the string to perform the replacement on. + * @param fieldName The name of the field representing the string to perform the replacement on. * @param find The substring to search for. * @param replace The substring to replace all occurrences of 'find' with. * @return A new {@code Expr} representing the string with all occurrences replaced. */ export function replaceAll( - field: string, + fieldName: string, find: string, replace: string ): FunctionExpr; @@ -5180,10 +5189,10 @@ export function byteLength(expr: Expr): FunctionExpr; * byteLength("myString"); * ``` * - * @param field The name of the field representing the string. + * @param fieldName The name of the field containing the string. * @return A new {@code Expr} representing the length of the string in bytes. */ -export function byteLength(field: string): FunctionExpr; +export function byteLength(fieldName: string): FunctionExpr; export function byteLength(expr: Expr | string): FunctionExpr { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.byteLength(); @@ -5199,10 +5208,10 @@ export function byteLength(expr: Expr | string): FunctionExpr { * strLength("name"); * ``` * - * @param field The name of the field containing the string. + * @param fieldName The name of the field containing the string. * @return A new {@code Expr} representing the length of the string. */ -export function charLength(field: string): FunctionExpr; +export function charLength(fieldName: string): FunctionExpr; /** * @beta @@ -5214,10 +5223,10 @@ export function charLength(field: string): FunctionExpr; * strLength(field("name")); * ``` * - * @param expr The expression representing the string to calculate the length of. + * @param stringExpression The expression representing the string to calculate the length of. * @return A new {@code Expr} representing the length of the string. */ -export function charLength(expr: Expr): FunctionExpr; +export function charLength(stringExpression: Expr): FunctionExpr; export function charLength(value: Expr | string): FunctionExpr { const valueExpr = fieldOfOrExpr(value); return valueExpr.charLength(); @@ -5234,11 +5243,11 @@ export function charLength(value: Expr | string): FunctionExpr { * like("title", "%guide%"); * ``` * - * @param left The name of the field containing the string. + * @param fieldName The name of the field containing the string. * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: string, pattern: string): BooleanExpr; +export function like(fieldName: string, pattern: string): BooleanExpr; /** * @beta @@ -5251,11 +5260,11 @@ export function like(left: string, pattern: string): BooleanExpr; * like("title", field("pattern")); * ``` * - * @param left The name of the field containing the string. + * @param fieldName The name of the field containing the string. * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: string, pattern: Expr): BooleanExpr; +export function like(fieldName: string, pattern: Expr): BooleanExpr; /** * @beta @@ -5267,11 +5276,11 @@ export function like(left: string, pattern: Expr): BooleanExpr; * like(field("title"), "%guide%"); * ``` * - * @param left The expression representing the string to perform the comparison on. + * @param stringExpression The expression representing the string to perform the comparison on. * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: Expr, pattern: string): BooleanExpr; +export function like(stringExpression: Expr, pattern: string): BooleanExpr; /** * @beta @@ -5283,11 +5292,11 @@ export function like(left: Expr, pattern: string): BooleanExpr; * like(field("title"), field("pattern")); * ``` * - * @param left The expression representing the string to perform the comparison on. + * @param stringExpression The expression representing the string to perform the comparison on. * @param pattern The pattern to search for. You can use "%" as a wildcard character. * @return A new {@code Expr} representing the 'like' comparison. */ -export function like(left: Expr, pattern: Expr): BooleanExpr; +export function like(stringExpression: Expr, pattern: Expr): BooleanExpr; export function like( left: Expr | string, pattern: Expr | string @@ -5308,11 +5317,11 @@ export function like( * regexContains("description", "(?i)example"); * ``` * - * @param left The name of the field containing the string. + * @param fieldName The name of the field containing the string. * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function regexContains(left: string, pattern: string): BooleanExpr; +export function regexContains(fieldName: string, pattern: string): BooleanExpr; /** * @beta @@ -5325,11 +5334,11 @@ export function regexContains(left: string, pattern: string): BooleanExpr; * regexContains("description", field("pattern")); * ``` * - * @param left The name of the field containing the string. + * @param fieldName The name of the field containing the string. * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function regexContains(left: string, pattern: Expr): BooleanExpr; +export function regexContains(fieldName: string, pattern: Expr): BooleanExpr; /** * @beta @@ -5342,11 +5351,14 @@ export function regexContains(left: string, pattern: Expr): BooleanExpr; * regexContains(field("description"), "(?i)example"); * ``` * - * @param left The expression representing the string to perform the comparison on. + * @param stringExpression The expression representing the string to perform the comparison on. * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function regexContains(left: Expr, pattern: string): BooleanExpr; +export function regexContains( + stringExpression: Expr, + pattern: string +): BooleanExpr; /** * @beta @@ -5359,11 +5371,14 @@ export function regexContains(left: Expr, pattern: string): BooleanExpr; * regexContains(field("description"), field("pattern")); * ``` * - * @param left The expression representing the string to perform the comparison on. + * @param stringExpression The expression representing the string to perform the comparison on. * @param pattern The regular expression to use for the search. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function regexContains(left: Expr, pattern: Expr): BooleanExpr; +export function regexContains( + stringExpression: Expr, + pattern: Expr +): BooleanExpr; export function regexContains( left: Expr | string, pattern: Expr | string @@ -5383,11 +5398,11 @@ export function regexContains( * regexMatch("email", "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"); * ``` * - * @param left The name of the field containing the string. + * @param fieldName The name of the field containing the string. * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: string, pattern: string): BooleanExpr; +export function regexMatch(fieldName: string, pattern: string): BooleanExpr; /** * @beta @@ -5399,11 +5414,11 @@ export function regexMatch(left: string, pattern: string): BooleanExpr; * regexMatch("email", field("pattern")); * ``` * - * @param left The name of the field containing the string. + * @param fieldName The name of the field containing the string. * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: string, pattern: Expr): BooleanExpr; +export function regexMatch(fieldName: string, pattern: Expr): BooleanExpr; /** * @beta @@ -5416,11 +5431,14 @@ export function regexMatch(left: string, pattern: Expr): BooleanExpr; * regexMatch(field("email"), "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"); * ``` * - * @param left The expression representing the string to match against. + * @param stringExpression The expression representing the string to match against. * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: Expr, pattern: string): BooleanExpr; +export function regexMatch( + stringExpression: Expr, + pattern: string +): BooleanExpr; /** * @beta @@ -5433,11 +5451,11 @@ export function regexMatch(left: Expr, pattern: string): BooleanExpr; * regexMatch(field("email"), field("pattern")); * ``` * - * @param left The expression representing the string to match against. + * @param stringExpression The expression representing the string to match against. * @param pattern The regular expression to use for the match. * @return A new {@code Expr} representing the regular expression match. */ -export function regexMatch(left: Expr, pattern: Expr): BooleanExpr; +export function regexMatch(stringExpression: Expr, pattern: Expr): BooleanExpr; export function regexMatch( left: Expr | string, pattern: Expr | string @@ -5457,11 +5475,11 @@ export function regexMatch( * strContains("description", "example"); * ``` * - * @param left The name of the field containing the string. + * @param fieldName The name of the field containing the string. * @param substring The substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function strContains(left: string, substring: string): BooleanExpr; +export function strContains(fieldName: string, substring: string): BooleanExpr; /** * @beta @@ -5473,11 +5491,11 @@ export function strContains(left: string, substring: string): BooleanExpr; * strContains("description", field("keyword")); * ``` * - * @param left The name of the field containing the string. + * @param fieldName The name of the field containing the string. * @param substring The expression representing the substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function strContains(left: string, substring: Expr): BooleanExpr; +export function strContains(fieldName: string, substring: Expr): BooleanExpr; /** * @beta @@ -5489,11 +5507,14 @@ export function strContains(left: string, substring: Expr): BooleanExpr; * strContains(field("description"), "example"); * ``` * - * @param left The expression representing the string to perform the comparison on. + * @param stringExpression The expression representing the string to perform the comparison on. * @param substring The substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function strContains(left: Expr, substring: string): BooleanExpr; +export function strContains( + stringExpression: Expr, + substring: string +): BooleanExpr; /** * @beta @@ -5505,11 +5526,14 @@ export function strContains(left: Expr, substring: string): BooleanExpr; * strContains(field("description"), field("keyword")); * ``` * - * @param left The expression representing the string to perform the comparison on. + * @param stringExpression The expression representing the string to perform the comparison on. * @param substring The expression representing the substring to search for. * @return A new {@code Expr} representing the 'contains' comparison. */ -export function strContains(left: Expr, substring: Expr): BooleanExpr; +export function strContains( + stringExpression: Expr, + substring: Expr +): BooleanExpr; export function strContains( left: Expr | string, substring: Expr | string @@ -5529,11 +5553,11 @@ export function strContains( * startsWith("name", "Mr."); * ``` * - * @param expr The field name to check. + * @param fieldName The field name to check. * @param prefix The prefix to check for. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: string, prefix: string): BooleanExpr; +export function startsWith(fieldName: string, prefix: string): BooleanExpr; /** * @beta @@ -5545,11 +5569,11 @@ export function startsWith(expr: string, prefix: string): BooleanExpr; * startsWith("fullName", field("firstName")); * ``` * - * @param expr The field name to check. + * @param fieldName The field name to check. * @param prefix The expression representing the prefix. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: string, prefix: Expr): BooleanExpr; +export function startsWith(fieldName: string, prefix: Expr): BooleanExpr; /** * @beta @@ -5561,11 +5585,11 @@ export function startsWith(expr: string, prefix: Expr): BooleanExpr; * startsWith(field("fullName"), "Mr."); * ``` * - * @param expr The expression to check. + * @param stringExpression The expression to check. * @param prefix The prefix to check for. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: Expr, prefix: string): BooleanExpr; +export function startsWith(stringExpression: Expr, prefix: string): BooleanExpr; /** * @beta @@ -5577,11 +5601,11 @@ export function startsWith(expr: Expr, prefix: string): BooleanExpr; * startsWith(field("fullName"), field("prefix")); * ``` * - * @param expr The expression to check. + * @param stringExpression The expression to check. * @param prefix The prefix to check for. * @return A new {@code Expr} representing the 'starts with' comparison. */ -export function startsWith(expr: Expr, prefix: Expr): BooleanExpr; +export function startsWith(stringExpression: Expr, prefix: Expr): BooleanExpr; export function startsWith( expr: Expr | string, prefix: Expr | string @@ -5599,11 +5623,11 @@ export function startsWith( * endsWith("filename", ".txt"); * ``` * - * @param expr The field name to check. + * @param fieldName The field name to check. * @param suffix The postfix to check for. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: string, suffix: string): BooleanExpr; +export function endsWith(fieldName: string, suffix: string): BooleanExpr; /** * @beta @@ -5615,11 +5639,11 @@ export function endsWith(expr: string, suffix: string): BooleanExpr; * endsWith("url", field("extension")); * ``` * - * @param expr The field name to check. + * @param fieldName The field name to check. * @param suffix The expression representing the postfix. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: string, suffix: Expr): BooleanExpr; +export function endsWith(fieldName: string, suffix: Expr): BooleanExpr; /** * @beta @@ -5631,11 +5655,11 @@ export function endsWith(expr: string, suffix: Expr): BooleanExpr; * endsWith(field("fullName"), "Jr."); * ``` * - * @param expr The expression to check. + * @param stringExpression The expression to check. * @param suffix The postfix to check for. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: Expr, suffix: string): BooleanExpr; +export function endsWith(stringExpression: Expr, suffix: string): BooleanExpr; /** * @beta @@ -5647,11 +5671,11 @@ export function endsWith(expr: Expr, suffix: string): BooleanExpr; * endsWith(field("fullName"), constant("Jr.")); * ``` * - * @param expr The expression to check. + * @param stringExpression The expression to check. * @param suffix The postfix to check for. * @return A new {@code Expr} representing the 'ends with' comparison. */ -export function endsWith(expr: Expr, suffix: Expr): BooleanExpr; +export function endsWith(stringExpression: Expr, suffix: Expr): BooleanExpr; export function endsWith( expr: Expr | string, suffix: Expr | string @@ -5669,10 +5693,10 @@ export function endsWith( * toLower("name"); * ``` * - * @param expr The name of the field containing the string. + * @param fieldName The name of the field containing the string. * @return A new {@code Expr} representing the lowercase string. */ -export function toLower(expr: string): FunctionExpr; +export function toLower(fieldName: string): FunctionExpr; /** * @beta @@ -5684,10 +5708,10 @@ export function toLower(expr: string): FunctionExpr; * toLower(field("name")); * ``` * - * @param expr The expression representing the string to convert to lowercase. + * @param stringExpression The expression representing the string to convert to lowercase. * @return A new {@code Expr} representing the lowercase string. */ -export function toLower(expr: Expr): FunctionExpr; +export function toLower(stringExpression: Expr): FunctionExpr; export function toLower(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).toLower(); } @@ -5702,10 +5726,10 @@ export function toLower(expr: Expr | string): FunctionExpr { * toUpper("title"); * ``` * - * @param expr The name of the field containing the string. + * @param fieldName The name of the field containing the string. * @return A new {@code Expr} representing the uppercase string. */ -export function toUpper(expr: string): FunctionExpr; +export function toUpper(fieldName: string): FunctionExpr; /** * @beta @@ -5717,10 +5741,10 @@ export function toUpper(expr: string): FunctionExpr; * toUppercase(field("title")); * ``` * - * @param expr The expression representing the string to convert to uppercase. + * @param stringExpression The expression representing the string to convert to uppercase. * @return A new {@code Expr} representing the uppercase string. */ -export function toUpper(expr: Expr): FunctionExpr; +export function toUpper(stringExpression: Expr): FunctionExpr; export function toUpper(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).toUpper(); } @@ -5735,10 +5759,10 @@ export function toUpper(expr: Expr | string): FunctionExpr { * trim("userInput"); * ``` * - * @param expr The name of the field containing the string. + * @param fieldName The name of the field containing the string. * @return A new {@code Expr} representing the trimmed string. */ -export function trim(expr: string): FunctionExpr; +export function trim(fieldName: string): FunctionExpr; /** * @beta @@ -5750,10 +5774,10 @@ export function trim(expr: string): FunctionExpr; * trim(field("userInput")); * ``` * - * @param expr The expression representing the string to trim. + * @param stringExpression The expression representing the string to trim. * @return A new {@code Expr} representing the trimmed string. */ -export function trim(expr: Expr): FunctionExpr; +export function trim(stringExpression: Expr): FunctionExpr; export function trim(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).trim(); } @@ -5819,11 +5843,11 @@ export function strConcat( * mapGet("address", "city"); * ``` * - * @param mapField The field name of the map field. + * @param fieldName The field name of the map field. * @param subField The key to access in the map. * @return A new {@code Expr} representing the value associated with the given key in the map. */ -export function mapGet(mapField: string, subField: string): FunctionExpr; +export function mapGet(fieldName: string, subField: string): FunctionExpr; /** * @beta @@ -5835,11 +5859,11 @@ export function mapGet(mapField: string, subField: string): FunctionExpr; * mapGet(field("address"), "city"); * ``` * - * @param mapExpr The expression representing the map. + * @param mapExpression The expression representing the map. * @param subField The key to access in the map. * @return A new {@code Expr} representing the value associated with the given key in the map. */ -export function mapGet(mapExpr: Expr, subField: string): FunctionExpr; +export function mapGet(mapExpression: Expr, subField: string): FunctionExpr; export function mapGet( fieldOrExpr: string | Expr, subField: string @@ -5874,10 +5898,10 @@ export function countAll(): AggregateFunction { * count(field("price").gt(10)).as("expensiveItemCount"); * ``` * - * @param value The expression to count. + * @param expression The expression to count. * @return A new {@code AggregateFunction} representing the 'count' aggregation. */ -export function countFunction(value: Expr): AggregateFunction; +export function countFunction(expression: Expr): AggregateFunction; /** * Creates an aggregation that counts the number of stage inputs with valid evaluations of the @@ -5888,10 +5912,10 @@ export function countFunction(value: Expr): AggregateFunction; * count("productId").as("totalProducts"); * ``` * - * @param value The name of the field to count. + * @param fieldName The name of the field to count. * @return A new {@code AggregateFunction} representing the 'count' aggregation. */ -export function countFunction(value: string): AggregateFunction; +export function countFunction(fieldName: string): AggregateFunction; export function countFunction(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).count(); } @@ -5907,10 +5931,10 @@ export function countFunction(value: Expr | string): AggregateFunction { * sum(field("orderAmount")).as("totalRevenue"); * ``` * - * @param value The expression to sum up. + * @param expression The expression to sum up. * @return A new {@code AggregateFunction} representing the 'sum' aggregation. */ -export function sumFunction(value: Expr): AggregateFunction; +export function sumFunction(expression: Expr): AggregateFunction; /** * @beta @@ -5923,10 +5947,10 @@ export function sumFunction(value: Expr): AggregateFunction; * sum("orderAmount").as("totalRevenue"); * ``` * - * @param value The name of the field containing numeric values to sum up. + * @param fieldName The name of the field containing numeric values to sum up. * @return A new {@code AggregateFunction} representing the 'sum' aggregation. */ -export function sumFunction(value: string): AggregateFunction; +export function sumFunction(fieldName: string): AggregateFunction; export function sumFunction(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).sum(); } @@ -5942,10 +5966,10 @@ export function sumFunction(value: Expr | string): AggregateFunction { * avg(field("age")).as("averageAge"); * ``` * - * @param value The expression representing the values to average. + * @param expression The expression representing the values to average. * @return A new {@code AggregateFunction} representing the 'avg' aggregation. */ -export function avgFunction(value: Expr): AggregateFunction; +export function avgFunction(expression: Expr): AggregateFunction; /** * @beta @@ -5958,10 +5982,10 @@ export function avgFunction(value: Expr): AggregateFunction; * avg("age").as("averageAge"); * ``` * - * @param value The name of the field containing numeric values to average. + * @param fieldName The name of the field containing numeric values to average. * @return A new {@code AggregateFunction} representing the 'avg' aggregation. */ -export function avgFunction(value: string): AggregateFunction; +export function avgFunction(fieldName: string): AggregateFunction; export function avgFunction(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).avg(); } @@ -5977,10 +6001,10 @@ export function avgFunction(value: Expr | string): AggregateFunction { * minimum(field("price")).as("lowestPrice"); * ``` * - * @param value The expression to find the minimum value of. + * @param expression The expression to find the minimum value of. * @return A new {@code AggregateFunction} representing the 'min' aggregation. */ -export function minimum(value: Expr): AggregateFunction; +export function minimum(expression: Expr): AggregateFunction; /** * @beta @@ -5992,10 +6016,10 @@ export function minimum(value: Expr): AggregateFunction; * minimum("price").as("lowestPrice"); * ``` * - * @param value The name of the field to find the minimum value of. + * @param fieldName The name of the field to find the minimum value of. * @return A new {@code AggregateFunction} representing the 'min' aggregation. */ -export function minimum(value: string): AggregateFunction; +export function minimum(fieldName: string): AggregateFunction; export function minimum(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).minimum(); } @@ -6011,10 +6035,10 @@ export function minimum(value: Expr | string): AggregateFunction { * maximum(field("score")).as("highestScore"); * ``` * - * @param value The expression to find the maximum value of. + * @param expression The expression to find the maximum value of. * @return A new {@code AggregateFunction} representing the 'max' aggregation. */ -export function maximum(value: Expr): AggregateFunction; +export function maximum(expression: Expr): AggregateFunction; /** * @beta @@ -6026,10 +6050,10 @@ export function maximum(value: Expr): AggregateFunction; * maximum("score").as("highestScore"); * ``` * - * @param value The name of the field to find the maximum value of. + * @param fieldName The name of the field to find the maximum value of. * @return A new {@code AggregateFunction} representing the 'max' aggregation. */ -export function maximum(value: string): AggregateFunction; +export function maximum(fieldName: string): AggregateFunction; export function maximum(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).maximum(); } @@ -6037,34 +6061,21 @@ export function maximum(value: Expr | string): AggregateFunction { /** * @beta * - * Calculates the Cosine distance between a field's vector value and a double array. + * Calculates the Cosine distance between a field's vector value and a literal vector value. * * ```typescript * // Calculate the Cosine distance between the 'location' field and a target location * cosineDistance("location", [37.7749, -122.4194]); * ``` * - * @param expr The name of the field containing the first vector. - * @param other The other vector (as an array of doubles) to compare against. - * @return A new {@code Expr} representing the Cosine distance between the two vectors. - */ -export function cosineDistance(expr: string, other: number[]): FunctionExpr; - -/** - * @beta - * - * Calculates the Cosine distance between a field's vector value and a VectorValue. - * - * ```typescript - * // Calculate the Cosine distance between the 'location' field and a target location - * cosineDistance("location", new VectorValue([37.7749, -122.4194])); - * ``` - * - * @param expr The name of the field containing the first vector. - * @param other The other vector (as a VectorValue) to compare against. + * @param fieldName The name of the field containing the first vector. + * @param vector The other vector (as an array of doubles) or {@link VectorValue} to compare against. * @return A new {@code Expr} representing the Cosine distance between the two vectors. */ -export function cosineDistance(expr: string, other: VectorValue): FunctionExpr; +export function cosineDistance( + fieldName: string, + vector: number[] | VectorValue +): FunctionExpr; /** * @beta @@ -6076,43 +6087,33 @@ export function cosineDistance(expr: string, other: VectorValue): FunctionExpr; * cosineDistance("userVector", field("itemVector")); * ``` * - * @param expr The name of the field containing the first vector. - * @param other The other vector (represented as an Expr) to compare against. + * @param fieldName The name of the field containing the first vector. + * @param vectorExpression The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance(expr: string, other: Expr): FunctionExpr; +export function cosineDistance( + fieldName: string, + vectorExpression: Expr +): FunctionExpr; /** * @beta * - * Calculates the Cosine distance between a vector expression and a double array. + * Calculates the Cosine distance between a vector expression and a vector literal. * * ```typescript * // Calculate the cosine distance between the 'location' field and a target location * cosineDistance(field("location"), [37.7749, -122.4194]); * ``` * - * @param expr The first vector (represented as an Expr) to compare against. - * @param other The other vector (as an array of doubles) to compare against. - * @return A new {@code Expr} representing the cosine distance between the two vectors. - */ -export function cosineDistance(expr: Expr, other: number[]): FunctionExpr; - -/** - * @beta - * - * Calculates the Cosine distance between a vector expression and a VectorValue. - * - * ```typescript - * // Calculate the cosine distance between the 'location' field and a target location - * cosineDistance(field("location"), new VectorValue([37.7749, -122.4194])); - * ``` - * - * @param expr The first vector (represented as an Expr) to compare against. - * @param other The other vector (as a VectorValue) to compare against. + * @param vectorExpression The first vector (represented as an Expr) to compare against. + * @param vector The other vector (as an array of doubles or VectorValue) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance(expr: Expr, other: VectorValue): FunctionExpr; +export function cosineDistance( + vectorExpression: Expr, + vector: number[] | Expr +): FunctionExpr; /** * @beta @@ -6124,11 +6125,14 @@ export function cosineDistance(expr: Expr, other: VectorValue): FunctionExpr; * cosineDistance(field("userVector"), field("itemVector")); * ``` * - * @param expr The first vector (represented as an Expr) to compare against. - * @param other The other vector (represented as an Expr) to compare against. + * @param vectorExpression The first vector (represented as an Expr) to compare against. + * @param otherVectorExpression The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the cosine distance between the two vectors. */ -export function cosineDistance(expr: Expr, other: Expr): FunctionExpr; +export function cosineDistance( + vectorExpression: Expr, + otherVectorExpression: Expr +): FunctionExpr; export function cosineDistance( expr: Expr | string, other: Expr | number[] | VectorValue @@ -6148,27 +6152,14 @@ export function cosineDistance( * dotProduct("features", [0.5, 0.8, 0.2]); * ``` * - * @param expr The name of the field containing the first vector. - * @param other The other vector (as an array of doubles) to calculate with. - * @return A new {@code Expr} representing the dot product between the two vectors. - */ -export function dotProduct(expr: string, other: number[]): FunctionExpr; - -/** - * @beta - * - * Calculates the dot product between a field's vector value and a VectorValue. - * - * ```typescript - * // Calculate the dot product distance between a feature vector and a target vector - * dotProduct("features", new VectorValue([0.5, 0.8, 0.2])); - * ``` - * - * @param expr The name of the field containing the first vector. - * @param other The other vector (as a VectorValue) to calculate with. + * @param fieldName The name of the field containing the first vector. + * @param vector The other vector (as an array of doubles or VectorValue) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: string, other: VectorValue): FunctionExpr; +export function dotProduct( + fieldName: string, + vector: number[] | VectorValue +): FunctionExpr; /** * @beta @@ -6180,11 +6171,14 @@ export function dotProduct(expr: string, other: VectorValue): FunctionExpr; * dotProduct("docVector1", field("docVector2")); * ``` * - * @param expr The name of the field containing the first vector. - * @param other The other vector (represented as an Expr) to calculate with. + * @param fieldName The name of the field containing the first vector. + * @param vectorExpression The other vector (represented as an Expr) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: string, other: Expr): FunctionExpr; +export function dotProduct( + fieldName: string, + vectorExpression: Expr +): FunctionExpr; /** * @beta @@ -6196,27 +6190,14 @@ export function dotProduct(expr: string, other: Expr): FunctionExpr; * dotProduct(field("features"), [0.5, 0.8, 0.2]); * ``` * - * @param expr The first vector (represented as an Expr) to calculate with. - * @param other The other vector (as an array of doubles) to calculate with. + * @param vectorExpression The first vector (represented as an Expr) to calculate with. + * @param vector The other vector (as an array of doubles or VectorValue) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: Expr, other: number[]): FunctionExpr; - -/** - * @beta - * - * Calculates the dot product between a vector expression and a VectorValue. - * - * ```typescript - * // Calculate the dot product between a feature vector and a target vector - * dotProduct(field("features"), new VectorValue([0.5, 0.8, 0.2])); - * ``` - * - * @param expr The first vector (represented as an Expr) to calculate with. - * @param other The other vector (as a VectorValue) to calculate with. - * @return A new {@code Expr} representing the dot product between the two vectors. - */ -export function dotProduct(expr: Expr, other: VectorValue): FunctionExpr; +export function dotProduct( + vectorExpression: Expr, + vector: number[] | VectorValue +): FunctionExpr; /** * @beta @@ -6228,11 +6209,14 @@ export function dotProduct(expr: Expr, other: VectorValue): FunctionExpr; * dotProduct(field("docVector1"), field("docVector2")); * ``` * - * @param expr The first vector (represented as an Expr) to calculate with. - * @param other The other vector (represented as an Expr) to calculate with. + * @param vectorExpression The first vector (represented as an Expr) to calculate with. + * @param otherVectorExpression The other vector (represented as an Expr) to calculate with. * @return A new {@code Expr} representing the dot product between the two vectors. */ -export function dotProduct(expr: Expr, other: Expr): FunctionExpr; +export function dotProduct( + vectorExpression: Expr, + otherVectorExpression: Expr +): FunctionExpr; export function dotProduct( expr: Expr | string, other: Expr | number[] | VectorValue @@ -6252,29 +6236,13 @@ export function dotProduct( * euclideanDistance("location", [37.7749, -122.4194]); * ``` * - * @param expr The name of the field containing the first vector. - * @param other The other vector (as an array of doubles) to compare against. - * @return A new {@code Expr} representing the Euclidean distance between the two vectors. - */ -export function euclideanDistance(expr: string, other: number[]): FunctionExpr; - -/** - * @beta - * - * Calculates the Euclidean distance between a field's vector value and a VectorValue. - * - * ```typescript - * // Calculate the Euclidean distance between the 'location' field and a target location - * euclideanDistance("location", new VectorValue([37.7749, -122.4194])); - * ``` - * - * @param expr The name of the field containing the first vector. - * @param other The other vector (as a VectorValue) to compare against. + * @param fieldName The name of the field containing the first vector. + * @param vector The other vector (as an array of doubles or VectorValue) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ export function euclideanDistance( - expr: string, - other: VectorValue + fieldName: string, + vector: number[] | VectorValue ): FunctionExpr; /** @@ -6287,11 +6255,14 @@ export function euclideanDistance( * euclideanDistance("pointA", field("pointB")); * ``` * - * @param expr The name of the field containing the first vector. - * @param other The other vector (represented as an Expr) to compare against. + * @param fieldName The name of the field containing the first vector. + * @param vectorExpression The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ -export function euclideanDistance(expr: string, other: Expr): FunctionExpr; +export function euclideanDistance( + fieldName: string, + vectorExpression: Expr +): FunctionExpr; /** * @beta @@ -6304,27 +6275,14 @@ export function euclideanDistance(expr: string, other: Expr): FunctionExpr; * euclideanDistance(field("location"), [37.7749, -122.4194]); * ``` * - * @param expr The first vector (represented as an Expr) to compare against. - * @param other The other vector (as an array of doubles) to compare against. - * @return A new {@code Expr} representing the Euclidean distance between the two vectors. - */ -export function euclideanDistance(expr: Expr, other: number[]): FunctionExpr; - -/** - * @beta - * - * Calculates the Euclidean distance between a vector expression and a VectorValue. - * - * ```typescript - * // Calculate the Euclidean distance between the 'location' field and a target location - * euclideanDistance(field("location"), new VectorValue([37.7749, -122.4194])); - * ``` - * - * @param expr The first vector (represented as an Expr) to compare against. - * @param other The other vector (as a VectorValue) to compare against. + * @param vectorExpression The first vector (represented as an Expr) to compare against. + * @param vector The other vector (as an array of doubles or VectorValue) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ -export function euclideanDistance(expr: Expr, other: VectorValue): FunctionExpr; +export function euclideanDistance( + vectorExpression: Expr, + vector: number[] | VectorValue +): FunctionExpr; /** * @beta @@ -6336,11 +6294,14 @@ export function euclideanDistance(expr: Expr, other: VectorValue): FunctionExpr; * euclideanDistance(field("pointA"), field("pointB")); * ``` * - * @param expr The first vector (represented as an Expr) to compare against. - * @param other The other vector (represented as an Expr) to compare against. + * @param vectorExpression The first vector (represented as an Expr) to compare against. + * @param otherVectorExpression The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Euclidean distance between the two vectors. */ -export function euclideanDistance(expr: Expr, other: Expr): FunctionExpr; +export function euclideanDistance( + vectorExpression: Expr, + otherVectorExpression: Expr +): FunctionExpr; export function euclideanDistance( expr: Expr | string, other: Expr | number[] | VectorValue @@ -6360,29 +6321,13 @@ export function euclideanDistance( * manhattanDistance("location", [37.7749, -122.4194]); * ``` * - * @param field The name of the field containing the first vector. - * @param other The other vector (as an array of doubles) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ -export function manhattanDistance(field: string, other: number[]): FunctionExpr; - -/** - * @beta - * - * Calculates the Manhattan distance between a field's vector value and a VectorValue. - * - * ```typescript - * // Calculate the Manhattan distance between the 'location' field and a target location - * manhattanDistance("location", new VectorValue([37.7749, -122.4194])); - * ``` - * - * @param expr The name of the field containing the first vector. - * @param other The other vector (as a VectorValue) to compare against. + * @param fieldName The name of the field containing the first vector. + * @param vector The other vector (as an array of doubles or VectorValue) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ export function manhattanDistance( - expr: string, - other: VectorValue + fieldName: string, + vector: number[] | VectorValue ): FunctionExpr; /** @@ -6395,11 +6340,14 @@ export function manhattanDistance( * manhattanDistance("pointA", field("pointB")); * ``` * - * @param expr The name of the field containing the first vector. - * @param other The other vector (represented as an Expr) to compare against. + * @param fieldName The name of the field containing the first vector. + * @param vectorExpression The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ -export function manhattanDistance(expr: string, other: Expr): FunctionExpr; +export function manhattanDistance( + fieldName: string, + vectorExpression: Expr +): FunctionExpr; /** * @beta @@ -6412,27 +6360,14 @@ export function manhattanDistance(expr: string, other: Expr): FunctionExpr; * manhattanDistance(field("location"), [37.7749, -122.4194]); * ``` * - * @param expr The first vector (represented as an Expr) to compare against. - * @param other The other vector (as an array of doubles) to compare against. + * @param vectorExpression The first vector (represented as an Expr) to compare against. + * @param vector The other vector (as an array of doubles or Vectorvalue) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ -export function manhattanDistance(expr: Expr, other: number[]): FunctionExpr; - -/** - * @beta - * - * Calculates the Manhattan distance between a vector expression and a VectorValue. - * - * ```typescript - * // Calculate the Manhattan distance between the 'location' field and a target location - * manhattanDistance(field("location"), new VectorValue([37.7749, -122.4194])); - * ``` - * - * @param expr The first vector (represented as an Expr) to compare against. - * @param other The other vector (as a VectorValue) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ -export function manhattanDistance(expr: Expr, other: VectorValue): FunctionExpr; +export function manhattanDistance( + vectorExpression: Expr, + vector: number[] | VectorValue +): FunctionExpr; /** * @beta @@ -6444,11 +6379,14 @@ export function manhattanDistance(expr: Expr, other: VectorValue): FunctionExpr; * manhattanDistance(field("pointA"), field("pointB")); * ``` * - * @param expr The first vector (represented as an Expr) to compare against. - * @param other The other vector (represented as an Expr) to compare against. + * @param vectorExpression The first vector (represented as an Expr) to compare against. + * @param otherVectorExpression The other vector (represented as an Expr) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ -export function manhattanDistance(expr: Expr, other: Expr): FunctionExpr; +export function manhattanDistance( + vectorExpression: Expr, + otherVectorExpression: Expr +): FunctionExpr; export function manhattanDistance( fieldOrExpr: Expr | string, other: Expr | number[] | VectorValue @@ -6468,10 +6406,10 @@ export function manhattanDistance( * vectorLength(field("embedding")); * ``` * - * @param expr The expression representing the Firestore Vector. + * @param vectorExpression The expression representing the Firestore Vector. * @return A new {@code Expr} representing the length of the array. */ -export function vectorLength(expr: Expr): FunctionExpr; +export function vectorLength(vectorExpression: Expr): FunctionExpr; /** * @beta @@ -6483,10 +6421,10 @@ export function vectorLength(expr: Expr): FunctionExpr; * vectorLength("embedding"); * ``` * - * @param field The name of the field representing the Firestore Vector. + * @param fieldName The name of the field representing the Firestore Vector. * @return A new {@code Expr} representing the length of the array. */ -export function vectorLength(field: string): FunctionExpr; +export function vectorLength(fieldName: string): FunctionExpr; export function vectorLength(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).vectorLength(); } @@ -6518,10 +6456,10 @@ export function unixMicrosToTimestamp(expr: Expr): FunctionExpr; * unixMicrosToTimestamp("microseconds"); * ``` * - * @param field The name of the field representing the number of microseconds since epoch. + * @param fieldName The name of the field representing the number of microseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMicrosToTimestamp(field: string): FunctionExpr; +export function unixMicrosToTimestamp(fieldName: string): FunctionExpr; export function unixMicrosToTimestamp(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).unixMicrosToTimestamp(); } @@ -6551,10 +6489,10 @@ export function timestampToUnixMicros(expr: Expr): FunctionExpr; * timestampToUnixMicros("timestamp"); * ``` * - * @param field The name of the field representing the timestamp. + * @param fieldName The name of the field representing the timestamp. * @return A new {@code Expr} representing the number of microseconds since epoch. */ -export function timestampToUnixMicros(field: string): FunctionExpr; +export function timestampToUnixMicros(fieldName: string): FunctionExpr; export function timestampToUnixMicros(expr: Expr | string): FunctionExpr { return fieldOfOrExpr(expr).timestampToUnixMicros(); } @@ -6586,10 +6524,10 @@ export function unixMillisToTimestamp(expr: Expr): FunctionExpr; * unixMillisToTimestamp("milliseconds"); * ``` * - * @param field The name of the field representing the number of milliseconds since epoch. + * @param fieldName The name of the field representing the number of milliseconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixMillisToTimestamp(field: string): FunctionExpr; +export function unixMillisToTimestamp(fieldName: string): FunctionExpr; export function unixMillisToTimestamp(expr: Expr | string): FunctionExpr { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.unixMillisToTimestamp(); @@ -6620,10 +6558,10 @@ export function timestampToUnixMillis(expr: Expr): FunctionExpr; * timestampToUnixMillis("timestamp"); * ``` * - * @param field The name of the field representing the timestamp. + * @param fieldName The name of the field representing the timestamp. * @return A new {@code Expr} representing the number of milliseconds since epoch. */ -export function timestampToUnixMillis(field: string): FunctionExpr; +export function timestampToUnixMillis(fieldName: string): FunctionExpr; export function timestampToUnixMillis(expr: Expr | string): FunctionExpr { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.timestampToUnixMillis(); @@ -6656,10 +6594,10 @@ export function unixSecondsToTimestamp(expr: Expr): FunctionExpr; * unixSecondsToTimestamp("seconds"); * ``` * - * @param field The name of the field representing the number of seconds since epoch. + * @param fieldName The name of the field representing the number of seconds since epoch. * @return A new {@code Expr} representing the timestamp. */ -export function unixSecondsToTimestamp(field: string): FunctionExpr; +export function unixSecondsToTimestamp(fieldName: string): FunctionExpr; export function unixSecondsToTimestamp(expr: Expr | string): FunctionExpr { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.unixSecondsToTimestamp(); @@ -6690,10 +6628,10 @@ export function timestampToUnixSeconds(expr: Expr): FunctionExpr; * timestampToUnixSeconds("timestamp"); * ``` * - * @param field The name of the field representing the timestamp. + * @param fieldName The name of the field representing the timestamp. * @return A new {@code Expr} representing the number of seconds since epoch. */ -export function timestampToUnixSeconds(field: string): FunctionExpr; +export function timestampToUnixSeconds(fieldName: string): FunctionExpr; export function timestampToUnixSeconds(expr: Expr | string): FunctionExpr { const normalizedExpr = fieldOfOrExpr(expr); return normalizedExpr.timestampToUnixSeconds(); @@ -6751,13 +6689,13 @@ export function timestampAdd( * timestampAdd("timestamp", "day", 1); * ``` * - * @param field The name of the field representing the timestamp. + * @param fieldName The name of the field representing the timestamp. * @param unit The unit of time to add (e.g., "day", "hour"). * @param amount The amount of time to add. * @return A new {@code Expr} representing the resulting timestamp. */ export function timestampAdd( - field: string, + fieldName: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number ): FunctionExpr; @@ -6831,13 +6769,13 @@ export function timestampSub( * timestampSub("timestamp", "day", 1); * ``` * - * @param field The name of the field representing the timestamp. + * @param fieldName The name of the field representing the timestamp. * @param unit The unit of time to subtract (e.g., "day", "hour"). * @param amount The amount of time to subtract. * @return A new {@code Expr} representing the resulting timestamp. */ export function timestampSub( - field: string, + fieldName: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number ): FunctionExpr; From 5cc68d265dd0f766ef74d8305f5aaf10c3be80d8 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 6 Mar 2025 13:45:03 -0700 Subject: [PATCH 57/75] Fix build issues --- packages/firestore/src/core/pipeline-util.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index c1ca7c71353..0a4f5d9e0fa 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -112,7 +112,13 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { const values = value?.arrayValue?.values?.map((val: any) => Constant._fromProto(val) ); - return andFunction(fieldValue.exists(), fieldValue.eqAny(...values!)); + if (!values) { + return fieldValue.exists(); + } else if (values.length == 1) { + return andFunction(fieldValue.exists(), fieldValue.eq(values[0])); + } else { + return andFunction(fieldValue.exists(), fieldValue.eqAny(values)); + } } case Operator.ARRAY_CONTAINS_ANY: { const values = value?.arrayValue?.values?.map((val: any) => @@ -127,10 +133,13 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { const values = value?.arrayValue?.values?.map((val: any) => Constant._fromProto(val) ); - return andFunction( - fieldValue.exists(), - fieldValue.notEqAny(...values!) - ); + if (!values) { + return fieldValue.exists(); + } else if (values.length == 1) { + return andFunction(fieldValue.exists(), fieldValue.neq(values[0])); + } else { + return andFunction(fieldValue.exists(), fieldValue.notEqAny(values)); + } } default: fail('Unexpected operator'); From 2ccdac604648e2db5fd83f5de4eecb0341e6952a Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 6 Mar 2025 14:47:22 -0700 Subject: [PATCH 58/75] New integration util pipeline_export file to support the pipelines subpackage --- .../test/integration/util/pipeline_export.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 packages/firestore/test/integration/util/pipeline_export.ts diff --git a/packages/firestore/test/integration/util/pipeline_export.ts b/packages/firestore/test/integration/util/pipeline_export.ts new file mode 100644 index 00000000000..bb3edcda114 --- /dev/null +++ b/packages/firestore/test/integration/util/pipeline_export.ts @@ -0,0 +1,24 @@ +/** + * @license + * Copyright 2017 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Imports firebase via the raw sources and re-exports it. The +// "/integration/firestore" test suite replaces this file with a +// reference to the minified sources. If you change any exports in this file, +// you need to also adjust "integration/firestore/pipeline_export.ts". + + +export * from '../../../pipelines/pipelines'; From cfb0879d50e54c16e1b9cb2a41e3293381bb3e38 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 6 Mar 2025 14:51:38 -0700 Subject: [PATCH 59/75] Rename several FunctionExpr standalone exports from Function to . Meets API design --- packages/firestore/src/api.ts | 3 +- packages/firestore/src/api_pipelines.ts | 14 ++-- packages/firestore/src/core/pipeline-util.ts | 57 ++++++--------- .../firestore/src/lite-api/expressions.ts | 36 +++++----- .../test/integration/api/pipeline.test.ts | 72 ++++++++++--------- .../integration/api/query_to_pipeline.test.ts | 6 +- .../test/integration/util/firebase_export.ts | 1 - .../test/integration/util/pipeline_export.ts | 1 - 8 files changed, 90 insertions(+), 100 deletions(-) diff --git a/packages/firestore/src/api.ts b/packages/firestore/src/api.ts index 14390d57b49..ea969c6b94c 100644 --- a/packages/firestore/src/api.ts +++ b/packages/firestore/src/api.ts @@ -224,8 +224,7 @@ export { isBase64Available as _isBase64Available } from './platform/base64'; export { DatabaseId as _DatabaseId } from './core/database_info'; export { _internalQueryToProtoQueryTarget, - _internalAggregationQueryToProtoRunAggregationQueryRequest, - _internalPipelineToExecutePipelineRequestProto + _internalAggregationQueryToProtoRunAggregationQueryRequest } from './remote/internal_serializer'; export { cast as _cast, diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index 1d5f98c54ab..1b3d3cbd517 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -87,11 +87,11 @@ export { strConcat, mapGet, countAll, - countFunction, - sumFunction, - avgFunction, - andFunction, - orFunction, + count, + sum, + avg, + and, + or, minimum, maximum, cosineDistance, @@ -128,7 +128,7 @@ export { map, mapRemove, mapMerge, - documentIdFunction, + documentId, substr, manhattanDistance, Expr, @@ -146,3 +146,5 @@ export type { BooleanExpr, AggregateFunction } from './lite-api/expressions'; + +export { _internalPipelineToExecutePipelineRequestProto } from './remote/internal_serializer'; diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index 0a4f5d9e0fa..7cf6bae2588 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -20,8 +20,8 @@ import { Constant, Field, BooleanExpr, - andFunction, - orFunction, + and, + or, Ordering, lt, gt, @@ -59,52 +59,52 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { const fieldValue = field(f.field.toString()); if (isNanValue(f.value)) { if (f.op === Operator.EQUAL) { - return andFunction(fieldValue.exists(), fieldValue.isNan()); + return and(fieldValue.exists(), fieldValue.isNan()); } else { - return andFunction(fieldValue.exists(), fieldValue.isNotNan()); + return and(fieldValue.exists(), fieldValue.isNotNan()); } } else if (isNullValue(f.value)) { if (f.op === Operator.EQUAL) { - return andFunction(fieldValue.exists(), fieldValue.eq(null)); + return and(fieldValue.exists(), fieldValue.eq(null)); } else { - return andFunction(fieldValue.exists(), fieldValue.neq(null)); + return and(fieldValue.exists(), fieldValue.neq(null)); } } else { // Comparison filters const value = f.value; switch (f.op) { case Operator.LESS_THAN: - return andFunction( + return and( fieldValue.exists(), fieldValue.lt(Constant._fromProto(value)) ); case Operator.LESS_THAN_OR_EQUAL: - return andFunction( + return and( fieldValue.exists(), fieldValue.lte(Constant._fromProto(value)) ); case Operator.GREATER_THAN: - return andFunction( + return and( fieldValue.exists(), fieldValue.gt(Constant._fromProto(value)) ); case Operator.GREATER_THAN_OR_EQUAL: - return andFunction( + return and( fieldValue.exists(), fieldValue.gte(Constant._fromProto(value)) ); case Operator.EQUAL: - return andFunction( + return and( fieldValue.exists(), fieldValue.eq(Constant._fromProto(value)) ); case Operator.NOT_EQUAL: - return andFunction( + return and( fieldValue.exists(), fieldValue.neq(Constant._fromProto(value)) ); case Operator.ARRAY_CONTAINS: - return andFunction( + return and( fieldValue.exists(), fieldValue.arrayContains(Constant._fromProto(value)) ); @@ -115,19 +115,16 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { if (!values) { return fieldValue.exists(); } else if (values.length == 1) { - return andFunction(fieldValue.exists(), fieldValue.eq(values[0])); + return and(fieldValue.exists(), fieldValue.eq(values[0])); } else { - return andFunction(fieldValue.exists(), fieldValue.eqAny(values)); + return and(fieldValue.exists(), fieldValue.eqAny(values)); } } case Operator.ARRAY_CONTAINS_ANY: { const values = value?.arrayValue?.values?.map((val: any) => Constant._fromProto(val) ); - return andFunction( - fieldValue.exists(), - fieldValue.arrayContainsAny(values!) - ); + return and(fieldValue.exists(), fieldValue.arrayContainsAny(values!)); } case Operator.NOT_IN: { const values = value?.arrayValue?.values?.map((val: any) => @@ -136,9 +133,9 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { if (!values) { return fieldValue.exists(); } else if (values.length == 1) { - return andFunction(fieldValue.exists(), fieldValue.neq(values[0])); + return and(fieldValue.exists(), fieldValue.neq(values[0])); } else { - return andFunction(fieldValue.exists(), fieldValue.notEqAny(values)); + return and(fieldValue.exists(), fieldValue.notEqAny(values)); } } default: @@ -149,15 +146,11 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { switch (f.op) { case CompositeOperator.AND: { const conditions = f.getFilters().map(f => toPipelineBooleanExpr(f)); - return andFunction( - conditions[0], - conditions[1], - ...conditions.slice(2) - ); + return and(conditions[0], conditions[1], ...conditions.slice(2)); } case CompositeOperator.OR: { const conditions = f.getFilters().map(f => toPipelineBooleanExpr(f)); - return orFunction(conditions[0], conditions[1], ...conditions.slice(2)); + return or(conditions[0], conditions[1], ...conditions.slice(2)); } default: fail('Unexpected operator'); @@ -199,7 +192,7 @@ export function toPipeline(query: Query, db: Firestore): Pipeline { ); if (existsConditions.length > 1) { pipeline = pipeline.where( - andFunction( + and( existsConditions[0], existsConditions[1], ...existsConditions.slice(2) @@ -283,7 +276,7 @@ function whereConditionsFromCursor( orConditions.push(conditions[0]); } else { orConditions.push( - andFunction(conditions[0], conditions[1], ...conditions.slice(2)) + and(conditions[0], conditions[1], ...conditions.slice(2)) ); } } @@ -291,10 +284,6 @@ function whereConditionsFromCursor( if (orConditions.length === 1) { return orConditions[0]; } else { - return orFunction( - orConditions[0], - orConditions[1], - ...orConditions.slice(2) - ); + return or(orConditions[0], orConditions[1], ...orConditions.slice(2)); } } diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 651a682eb96..653a9f6e81a 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -36,7 +36,7 @@ import { isFirestoreValue } from '../util/proto'; import { isString } from '../util/types'; import { Bytes } from './bytes'; -import { documentId, FieldPath } from './field_path'; +import { documentId as documentIdFieldPath, FieldPath } from './field_path'; import { GeoPoint } from './geo_point'; import { DocumentReference } from './reference'; import { Timestamp } from './timestamp'; @@ -2232,12 +2232,12 @@ export function field(path: FieldPath): Field; export function field(nameOrPath: string | FieldPath): Field { if (typeof nameOrPath === 'string') { if (DOCUMENT_KEY_NAME === nameOrPath) { - return new Field(documentId()._internalPath); + return new Field(documentIdFieldPath()._internalPath); } return new Field(fieldPathFromArgument('of', nameOrPath)); } else { - if (documentId().isEqual(nameOrPath)) { - return new Field(documentId()._internalPath); + if (documentIdFieldPath().isEqual(nameOrPath)) { + return new Field(documentIdFieldPath()._internalPath); } return new Field(nameOrPath._internalPath); } @@ -3375,7 +3375,7 @@ export function mapMerge( * * @return A new {@code Expr} representing the documentId operation. */ -export function documentIdFunction( +export function documentId( documentPath: string | DocumentReference ): FunctionExpr; @@ -3391,9 +3391,9 @@ export function documentIdFunction( * * @return A new {@code Expr} representing the documentId operation. */ -export function documentIdFunction(documentPathExpr: Expr): FunctionExpr; +export function documentId(documentPathExpr: Expr): FunctionExpr; -export function documentIdFunction( +export function documentId( documentPath: Expr | string | DocumentReference ): FunctionExpr { // @ts-ignore @@ -5901,7 +5901,7 @@ export function countAll(): AggregateFunction { * @param expression The expression to count. * @return A new {@code AggregateFunction} representing the 'count' aggregation. */ -export function countFunction(expression: Expr): AggregateFunction; +export function count(expression: Expr): AggregateFunction; /** * Creates an aggregation that counts the number of stage inputs with valid evaluations of the @@ -5915,8 +5915,8 @@ export function countFunction(expression: Expr): AggregateFunction; * @param fieldName The name of the field to count. * @return A new {@code AggregateFunction} representing the 'count' aggregation. */ -export function countFunction(fieldName: string): AggregateFunction; -export function countFunction(value: Expr | string): AggregateFunction { +export function count(fieldName: string): AggregateFunction; +export function count(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).count(); } @@ -5934,7 +5934,7 @@ export function countFunction(value: Expr | string): AggregateFunction { * @param expression The expression to sum up. * @return A new {@code AggregateFunction} representing the 'sum' aggregation. */ -export function sumFunction(expression: Expr): AggregateFunction; +export function sum(expression: Expr): AggregateFunction; /** * @beta @@ -5950,8 +5950,8 @@ export function sumFunction(expression: Expr): AggregateFunction; * @param fieldName The name of the field containing numeric values to sum up. * @return A new {@code AggregateFunction} representing the 'sum' aggregation. */ -export function sumFunction(fieldName: string): AggregateFunction; -export function sumFunction(value: Expr | string): AggregateFunction { +export function sum(fieldName: string): AggregateFunction; +export function sum(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).sum(); } @@ -5969,7 +5969,7 @@ export function sumFunction(value: Expr | string): AggregateFunction { * @param expression The expression representing the values to average. * @return A new {@code AggregateFunction} representing the 'avg' aggregation. */ -export function avgFunction(expression: Expr): AggregateFunction; +export function avg(expression: Expr): AggregateFunction; /** * @beta @@ -5985,8 +5985,8 @@ export function avgFunction(expression: Expr): AggregateFunction; * @param fieldName The name of the field containing numeric values to average. * @return A new {@code AggregateFunction} representing the 'avg' aggregation. */ -export function avgFunction(fieldName: string): AggregateFunction; -export function avgFunction(value: Expr | string): AggregateFunction { +export function avg(fieldName: string): AggregateFunction; +export function avg(value: Expr | string): AggregateFunction { return fieldOfOrExpr(value).avg(); } @@ -6813,7 +6813,7 @@ export function timestampSub( * @param more Additional filter conditions to 'AND' together. * @return A new {@code Expr} representing the logical 'AND' operation. */ -export function andFunction( +export function and( first: BooleanExpr, second: BooleanExpr, ...more: BooleanExpr[] @@ -6837,7 +6837,7 @@ export function andFunction( * @param more Additional filter conditions to 'OR' together. * @return A new {@code Expr} representing the logical 'OR' operation. */ -export function orFunction( +export function or( first: BooleanExpr, second: BooleanExpr, ...more: BooleanExpr[] diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 2ed82824c2f..f1f26800a67 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -30,49 +30,53 @@ import { Deferred } from '../../util/promise'; import { GeoPoint, Timestamp, - array, - descending, - isNan, - map, Bytes, getFirestore, terminate, vector, + CollectionReference, + doc, + DocumentData, + Firestore, + setDoc, + setLogLevel, + collection, + documentId as documentIdFieldPath, + writeBatch +} from '../util/firebase_export'; +import { apiDescribe, withTestCollection } from '../util/helpers'; +import { + array, + descending, + isNan, + map, execute, - _internalPipelineToExecutePipelineRequestProto, add, - andFunction, + and, arrayContains, arrayContainsAny, - avgFunction, - CollectionReference, + avg, cosineDistance, countAll, - doc, - DocumentData, dotProduct, endsWith, eq, euclideanDistance, - Firestore, gt, like, lt, lte, mapGet, neq, - orFunction, + or, regexContains, regexMatch, - setDoc, startsWith, subtract, - setLogLevel, cond, eqAny, logicalMaximum, notEqAny, - collection, multiply, countIf, bitAnd, @@ -92,23 +96,21 @@ import { isNotNan, mapRemove, mapMerge, - documentIdFunction, + documentId, substr, manhattanDistance, - documentId, logicalMinimum, xor, field, constant, - writeBatch -} from '../util/firebase_export'; -import { apiDescribe, withTestCollection } from '../util/helpers'; + _internalPipelineToExecutePipelineRequestProto +} from '../util/pipeline_export'; use(chaiAsPromised); setLogLevel('debug'); -apiDescribe.only('Pipelines', persistence => { +apiDescribe('Pipelines', persistence => { addEqualityMatcher(); let firestore: Firestore; @@ -377,7 +379,7 @@ apiDescribe.only('Pipelines', persistence => { }).as('metadata') ) .where( - andFunction( + and( eq('metadataArray', [ 1, 2, @@ -627,7 +629,7 @@ apiDescribe.only('Pipelines', persistence => { const pipeline = firestore .pipeline() .collection(randomCol.path) - .aggregate(avgFunction('rating').as('avgRating')); + .aggregate(avg('rating').as('avgRating')); const snapshot = await execute(pipeline); const end = new Date().valueOf(); @@ -645,7 +647,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .aggregate({ - accumulators: [avgFunction('rating').as('avgRating')], + accumulators: [avg('rating').as('avgRating')], groups: ['genre'] }); @@ -678,7 +680,7 @@ apiDescribe.only('Pipelines', persistence => { .where(eq('genre', 'Science Fiction')) .aggregate( countAll().as('count'), - avgFunction('rating').as('avgRating'), + avg('rating').as('avgRating'), field('rating').maximum().as('maxRating') ) ); @@ -707,7 +709,7 @@ apiDescribe.only('Pipelines', persistence => { .collection(randomCol.path) .where(lt(field('published'), 1984)) .aggregate({ - accumulators: [avgFunction('rating').as('avgRating')], + accumulators: [avg('rating').as('avgRating')], groups: ['genre'] }) .where(gt('avgRating', 4.3)) @@ -919,7 +921,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .where( - andFunction( + and( gt('rating', 4.5), eq('genre', 'Science Fiction'), lte('published', 1965) @@ -934,7 +936,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .where( - orFunction( + or( eq('genre', 'Romance'), eq('genre', 'Dystopian'), eq('genre', 'Fantasy') @@ -1188,7 +1190,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .union(firestore.pipeline().collection(randomCol.path)) - .sort(field(documentId()).ascending()) + .sort(field(documentIdFieldPath()).ascending()) ); expectResults( snapshot, @@ -1629,7 +1631,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .where( - andFunction( + and( gt('rating', 4.2), lte(field('rating'), 4.5), neq('genre', 'Science Fiction') @@ -1655,8 +1657,8 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .where( - orFunction( - andFunction(gt('rating', 4.5), eq('genre', 'Science Fiction')), + or( + and(gt('rating', 4.5), eq('genre', 'Science Fiction')), lt('published', 1900) ) ) @@ -2126,7 +2128,7 @@ apiDescribe.only('Pipelines', persistence => { .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) - .select(documentIdFunction(field('__path__')).as('docId')) + .select(documentId(field('__path__')).as('docId')) ); expectResults(snapshot, { docId: 'book4' @@ -2529,8 +2531,8 @@ apiDescribe.only('Pipelines', persistence => { snapshot = await execute( pipeline .where( - orFunction( - andFunction( + or( + and( field('rating').eq(lastDoc.get('rating')), field('__path__').gt(lastDoc.ref?.id) ), diff --git a/packages/firestore/test/integration/api/query_to_pipeline.test.ts b/packages/firestore/test/integration/api/query_to_pipeline.test.ts index ab29f8634e9..99aa6771143 100644 --- a/packages/firestore/test/integration/api/query_to_pipeline.test.ts +++ b/packages/firestore/test/integration/api/query_to_pipeline.test.ts @@ -40,14 +40,14 @@ import { and, documentId, addDoc, - getDoc, - execute + getDoc } from '../util/firebase_export'; import { apiDescribe, PERSISTENCE_MODE_UNSPECIFIED, withTestCollection } from '../util/helpers'; +import { execute } from '../util/pipeline_export'; use(chaiAsPromised); @@ -55,7 +55,7 @@ setLogLevel('debug'); // This is the Query integration tests from the lite API (no cache support) // with some additional test cases added for more complete coverage. -apiDescribe('Query to Pipeline', persistence => { +apiDescribe.only('Query to Pipeline', persistence => { addEqualityMatcher(); function verifyResults( diff --git a/packages/firestore/test/integration/util/firebase_export.ts b/packages/firestore/test/integration/util/firebase_export.ts index a6739dfe72f..f58b3ce045b 100644 --- a/packages/firestore/test/integration/util/firebase_export.ts +++ b/packages/firestore/test/integration/util/firebase_export.ts @@ -51,5 +51,4 @@ export function newTestFirestore( } export * from '../../../src'; -export * from '../../../pipelines/pipelines'; export { PrivateSettings }; diff --git a/packages/firestore/test/integration/util/pipeline_export.ts b/packages/firestore/test/integration/util/pipeline_export.ts index bb3edcda114..d2495d772a5 100644 --- a/packages/firestore/test/integration/util/pipeline_export.ts +++ b/packages/firestore/test/integration/util/pipeline_export.ts @@ -20,5 +20,4 @@ // reference to the minified sources. If you change any exports in this file, // you need to also adjust "integration/firestore/pipeline_export.ts". - export * from '../../../pipelines/pipelines'; From 03fd4dda4cefe87d94d7e37f91b5d17366b2ba1d Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 6 Mar 2025 15:00:30 -0700 Subject: [PATCH 60/75] Removing the all-packages api report script because it is no longer needed --- packages/firestore/package.json | 3 +-- packages/firestore/src/all_packages.ts | 25 ------------------------- 2 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 packages/firestore/src/all_packages.ts diff --git a/packages/firestore/package.json b/packages/firestore/package.json index a615a5559a5..9f894de073e 100644 --- a/packages/firestore/package.json +++ b/packages/firestore/package.json @@ -48,12 +48,11 @@ "test:minified": "(cd ../../integration/firestore ; yarn test)", "trusted-type-check": "tsec -p tsconfig.json --noEmit", "api-report:main": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/index.d.ts --rollupDts ./dist/private.d.ts --untrimmedRollupDts ./dist/internal.d.ts --publicDts ./dist/index.d.ts", - "api-report:all-packages": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/all_packages.d.ts --rollupDts ./dist/private.all_packages.d.ts --untrimmedRollupDts ./dist/internal.all_packages.d.ts --publicDts ./dist/all_packages.d.ts", "api-report:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-pipelines --packageRoot . --typescriptDts ./dist/firestore/pipelines/pipelines.d.ts --rollupDts ./dist/private.pipelines.d.ts --untrimmedRollupDts ./dist/internal.pipelines.d.ts --publicDts ./dist/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", "api-report:lite": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite --packageRoot . --typescriptDts ./dist/firestore/lite/index.d.ts --rollupDts ./dist/lite/private.d.ts --untrimmedRollupDts ./dist/lite/internal.d.ts --publicDts ./dist/lite/index.d.ts", "api-report:lite:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite-pipelines --packageRoot . --typescriptDts ./dist/firestore/lite/pipelines/pipelines.d.ts --rollupDts ./dist/lite/private.pipelines.d.ts --untrimmedRollupDts ./dist/lite/internal.pipelines.d.ts --publicDts ./dist/lite/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", "api-report:api-json": "rm -rf temp && api-extractor run --local --verbose", - "api-report": "run-s --npm-path npm api-report:main api-report:pipelines api-report:all-packages api-report:lite api-report:lite:pipelines && yarn api-report:api-json", + "api-report": "run-s --npm-path npm api-report:main api-report:pipelines api-report:lite api-report:lite:pipelines && yarn api-report:api-json", "doc": "api-documenter markdown --input temp --output docs", "typings:public": "node ../../scripts/build/use_typings.js ./dist/all-packages.d.ts" }, diff --git a/packages/firestore/src/all_packages.ts b/packages/firestore/src/all_packages.ts deleted file mode 100644 index 82babeea706..00000000000 --- a/packages/firestore/src/all_packages.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Cloud Firestore - * - * @packageDocumentation - */ - -/** - * @license - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export * from './api'; -export * from './api_pipelines'; From ec03a5e37dbb40f296d43da7ea24acc52ad623d5 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 6 Mar 2025 15:22:08 -0700 Subject: [PATCH 61/75] Remove any from the public api surface --- .../firestore/src/lite-api/expressions.ts | 284 +++++++++--------- packages/firestore/src/lite-api/pipeline.ts | 14 +- 2 files changed, 156 insertions(+), 142 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 653a9f6e81a..fbed850a1bb 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -/* eslint @typescript-eslint/no-explicit-any: 0 */ - import { DOCUMENT_KEY_NAME, FieldPath as InternalFieldPath @@ -69,15 +67,15 @@ export type ExprType = * @internal * @param value */ -function valueToDefaultExpr(value: any): Expr { +function valueToDefaultExpr(value: unknown): Expr { if (value instanceof Expr) { return value; } else if (isPlainObject(value)) { - return map(value); + return map(value as Record); } else if (value instanceof Array) { return array(value); } else { - return constant(value); + return new Constant(value); } } @@ -107,7 +105,7 @@ function vectorToExpr(value: VectorValue | number[] | Expr): Expr { * @internal * @param value */ -function fieldOfOrExpr(value: any): Expr { +function fieldOfOrExpr(value: unknown): Expr { if (isString(value)) { return field(value); } else { @@ -159,7 +157,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param others Optional additional expressions or literals to add to this expression. * @return A new `Expr` representing the addition operation. */ - add(second: Expr | any, ...others: Array): FunctionExpr { + add(second: Expr | unknown, ...others: Array): FunctionExpr { const values = [second, ...others]; return new FunctionExpr('add', [ this, @@ -191,8 +189,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The constant value to subtract. * @return A new `Expr` representing the subtraction operation. */ - subtract(other: any): FunctionExpr; - subtract(other: any): FunctionExpr { + subtract(other: unknown): FunctionExpr; + subtract(other: unknown): FunctionExpr { return new FunctionExpr('subtract', [this, valueToDefaultExpr(other)]); } @@ -208,7 +206,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param others Optional additional expressions or literals to multiply by. * @return A new `Expr` representing the multiplication operation. */ - multiply(second: Expr | any, ...others: Array): FunctionExpr { + multiply( + second: Expr | unknown, + ...others: Array + ): FunctionExpr { return new FunctionExpr('multiply', [ this, valueToDefaultExpr(second), @@ -240,8 +241,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The constant value to divide by. * @return A new `Expr` representing the division operation. */ - divide(other: any): FunctionExpr; - divide(other: any): FunctionExpr { + divide(other: unknown): FunctionExpr; + divide(other: unknown): FunctionExpr { return new FunctionExpr('divide', [this, valueToDefaultExpr(other)]); } @@ -269,8 +270,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param value The constant value to divide by. * @return A new `Expr` representing the modulo operation. */ - mod(value: any): FunctionExpr; - mod(other: any): FunctionExpr { + mod(value: unknown): FunctionExpr; + mod(other: unknown): FunctionExpr { return new FunctionExpr('mod', [this, valueToDefaultExpr(other)]); } @@ -298,8 +299,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param value The constant value to compare for equality. * @return A new `Expr` representing the equality comparison. */ - eq(value: any): BooleanExpr; - eq(other: any): BooleanExpr { + eq(value: unknown): BooleanExpr; + eq(other: unknown): BooleanExpr { return new BooleanExpr('eq', [this, valueToDefaultExpr(other)]); } @@ -327,8 +328,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param value The constant value to compare for inequality. * @return A new `Expr` representing the inequality comparison. */ - neq(value: any): BooleanExpr; - neq(other: any): BooleanExpr { + neq(value: unknown): BooleanExpr; + neq(other: unknown): BooleanExpr { return new BooleanExpr('neq', [this, valueToDefaultExpr(other)]); } @@ -356,8 +357,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param value The constant value to compare for less than. * @return A new `Expr` representing the less than comparison. */ - lt(value: any): BooleanExpr; - lt(other: any): BooleanExpr { + lt(value: unknown): BooleanExpr; + lt(other: unknown): BooleanExpr { return new BooleanExpr('lt', [this, valueToDefaultExpr(other)]); } @@ -386,8 +387,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param value The constant value to compare for less than or equal to. * @return A new `Expr` representing the less than or equal to comparison. */ - lte(value: any): BooleanExpr; - lte(other: any): BooleanExpr { + lte(value: unknown): BooleanExpr; + lte(other: unknown): BooleanExpr { return new BooleanExpr('lte', [this, valueToDefaultExpr(other)]); } @@ -415,8 +416,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param value The constant value to compare for greater than. * @return A new `Expr` representing the greater than comparison. */ - gt(value: any): BooleanExpr; - gt(other: any): BooleanExpr { + gt(value: unknown): BooleanExpr; + gt(other: unknown): BooleanExpr { return new BooleanExpr('gt', [this, valueToDefaultExpr(other)]); } @@ -446,8 +447,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param value The constant value to compare for greater than or equal to. * @return A new `Expr` representing the greater than or equal to comparison. */ - gte(value: any): BooleanExpr; - gte(other: any): BooleanExpr { + gte(value: unknown): BooleanExpr; + gte(other: unknown): BooleanExpr { return new BooleanExpr('gte', [this, valueToDefaultExpr(other)]); } @@ -463,8 +464,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @return A new `Expr` representing the concatenated array. */ arrayConcat( - secondArray: Expr | any[], - ...otherArrays: Array + secondArray: Expr | unknown[], + ...otherArrays: Array ): FunctionExpr { const elements = [secondArray, ...otherArrays]; const exprValues = elements.map(value => valueToDefaultExpr(value)); @@ -495,8 +496,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param value The element to search for in the array. * @return A new `Expr` representing the 'array_contains' comparison. */ - arrayContains(value: any): BooleanExpr; - arrayContains(element: any): BooleanExpr { + arrayContains(value: unknown): BooleanExpr; + arrayContains(element: unknown): BooleanExpr { return new BooleanExpr('array_contains', [ this, valueToDefaultExpr(element) @@ -514,7 +515,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param values The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_all' comparison. */ - arrayContainsAll(values: Array): BooleanExpr; + arrayContainsAll(values: Array): BooleanExpr; /** * Creates an expression that checks if an array contains all the specified elements. @@ -528,7 +529,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @return A new `Expr` representing the 'array_contains_all' comparison. */ arrayContainsAll(arrayExpression: Expr): BooleanExpr; - arrayContainsAll(values: any[] | Expr): BooleanExpr { + arrayContainsAll(values: unknown[] | Expr): BooleanExpr { const normalizedExpr = Array.isArray(values) ? new ListOfExprs(values.map(valueToDefaultExpr)) : values; @@ -546,7 +547,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param values The elements to check for in the array. * @return A new `Expr` representing the 'array_contains_any' comparison. */ - arrayContainsAny(values: Array): BooleanExpr; + arrayContainsAny(values: Array): BooleanExpr; /** * Creates an expression that checks if an array contains any of the specified elements. @@ -561,7 +562,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @return A new `Expr` representing the 'array_contains_any' comparison. */ arrayContainsAny(arrayExpression: Expr): BooleanExpr; - arrayContainsAny(values: Array | Expr): BooleanExpr { + arrayContainsAny(values: Array | Expr): BooleanExpr { const normalizedExpr = Array.isArray(values) ? new ListOfExprs(values.map(valueToDefaultExpr)) : values; @@ -594,7 +595,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param values The values or expressions to check against. * @return A new `Expr` representing the 'IN' comparison. */ - eqAny(values: Array): BooleanExpr; + eqAny(values: Array): BooleanExpr; /** * Creates an expression that checks if this expression is equal to any of the provided values or @@ -609,7 +610,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @return A new `Expr` representing the 'IN' comparison. */ eqAny(arrayExpression: Expr): BooleanExpr; - eqAny(others: any[] | Expr): BooleanExpr { + eqAny(others: unknown[] | Expr): BooleanExpr { const exprOthers = Array.isArray(others) ? new ListOfExprs(others.map(valueToDefaultExpr)) : others; @@ -628,7 +629,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param values The values or expressions to check against. * @return A new `Expr` representing the 'NotEqAny' comparison. */ - notEqAny(values: Array): BooleanExpr; + notEqAny(values: Array): BooleanExpr; /** * Creates an expression that checks if this expression is not equal to any of the values in the evaluated expression. @@ -642,7 +643,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @return A new `Expr` representing the 'NotEqAny' comparison. */ notEqAny(arrayExpression: Expr): BooleanExpr; - notEqAny(others: any[] | Expr): BooleanExpr { + notEqAny(others: unknown[] | Expr): BooleanExpr { const exprOthers = Array.isArray(others) ? new ListOfExprs(others.map(valueToDefaultExpr)) : others; @@ -1161,8 +1162,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @return A new {@code Expr} representing the logical max operation. */ logicalMaximum( - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr { const values = [second, ...others]; return new FunctionExpr('logical_maximum', [ @@ -1184,8 +1185,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @return A new {@code Expr} representing the logical min operation. */ logicalMinimum( - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr { const values = [second, ...others]; return new FunctionExpr('logical_min', [ @@ -1837,8 +1838,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * produces an error. * @return A new {@code Expr} representing the 'ifError' operation. */ - ifError(catchValue: any): FunctionExpr; - ifError(catchValue: any): FunctionExpr { + ifError(catchValue: unknown): FunctionExpr; + ifError(catchValue: unknown): FunctionExpr { return new FunctionExpr('if_error', [this, valueToDefaultExpr(catchValue)]); } @@ -1945,8 +1946,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @returns A new {@code FirestoreFunction} representing the 'mapMerge' operation. */ mapMerge( - secondMap: Record | Expr, - ...otherMaps: Array | Expr> + secondMap: Record | Expr, + ...otherMaps: Array | Expr> ): FunctionExpr { const secondMapExpr = valueToDefaultExpr(secondMap); const otherMapExprs = otherMaps.map(valueToDefaultExpr); @@ -2269,7 +2270,7 @@ export class Constant extends Expr { * @hideconstructor * @param value The value of the constant. */ - constructor(private value: any) { + constructor(private value: unknown) { super(); } @@ -2416,7 +2417,7 @@ export function constant(value: ProtoValue): Constant; */ export function constant(value: VectorValue): Constant; -export function constant(value: any): Constant { +export function constant(value: unknown): Constant { return new Constant(value); } @@ -3104,8 +3105,8 @@ export function ifError(tryExpr: Expr, catchExpr: Expr): FunctionExpr; * error. * @return A new {@code Expr} representing the 'ifError' operation. */ -export function ifError(tryExpr: Expr, catchValue: any): FunctionExpr; -export function ifError(tryExpr: Expr, catchValue: any): FunctionExpr { +export function ifError(tryExpr: Expr, catchValue: unknown): FunctionExpr; +export function ifError(tryExpr: Expr, catchValue: unknown): FunctionExpr { return tryExpr.ifError(valueToDefaultExpr(catchValue)); } @@ -3326,8 +3327,8 @@ export function mapRemove( */ export function mapMerge( mapField: string, - secondMap: Record | Expr, - ...otherMaps: Array | Expr> + secondMap: Record | Expr, + ...otherMaps: Array | Expr> ): FunctionExpr; /** @@ -3348,15 +3349,15 @@ export function mapMerge( * as a literal or an expression that returns a map. */ export function mapMerge( - firstMap: Record | Expr, - secondMap: Record | Expr, - ...otherMaps: Array | Expr> + firstMap: Record | Expr, + secondMap: Record | Expr, + ...otherMaps: Array | Expr> ): FunctionExpr; export function mapMerge( - firstMap: string | Record | Expr, - secondMap: Record | Expr, - ...otherMaps: Array | Expr> + firstMap: string | Record | Expr, + secondMap: Record | Expr, + ...otherMaps: Array | Expr> ): FunctionExpr { const secondMapExpr = valueToDefaultExpr(secondMap); const otherMapExprs = otherMaps.map(valueToDefaultExpr); @@ -3490,8 +3491,8 @@ export function substr( */ export function add( first: Expr, - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr; /** @@ -3511,14 +3512,14 @@ export function add( */ export function add( fieldName: string, - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr; export function add( first: Expr | string, - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr { return fieldOfOrExpr(first).add( valueToDefaultExpr(second), @@ -3556,7 +3557,7 @@ export function subtract(left: Expr, right: Expr): FunctionExpr; * @param value The constant value to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(expression: Expr, value: any): FunctionExpr; +export function subtract(expression: Expr, value: unknown): FunctionExpr; /** * @beta @@ -3588,8 +3589,11 @@ export function subtract(fieldName: string, expression: Expr): FunctionExpr; * @param value The constant value to subtract. * @return A new {@code Expr} representing the subtraction operation. */ -export function subtract(fieldName: string, value: any): FunctionExpr; -export function subtract(left: Expr | string, right: Expr | any): FunctionExpr { +export function subtract(fieldName: string, value: unknown): FunctionExpr; +export function subtract( + left: Expr | string, + right: Expr | unknown +): FunctionExpr { const normalizedLeft = typeof left === 'string' ? field(left) : left; const normalizedRight = valueToDefaultExpr(right); return normalizedLeft.subtract(normalizedRight); @@ -3612,8 +3616,8 @@ export function subtract(left: Expr | string, right: Expr | any): FunctionExpr { */ export function multiply( first: Expr, - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr; /** @@ -3633,14 +3637,14 @@ export function multiply( */ export function multiply( fieldName: string, - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr; export function multiply( first: Expr | string, - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr { return fieldOfOrExpr(first).multiply( valueToDefaultExpr(second), @@ -3678,7 +3682,7 @@ export function divide(left: Expr, right: Expr): FunctionExpr; * @param value The constant value to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(expression: Expr, value: any): FunctionExpr; +export function divide(expression: Expr, value: unknown): FunctionExpr; /** * @beta @@ -3710,8 +3714,11 @@ export function divide(fieldName: string, expressions: Expr): FunctionExpr; * @param value The constant value to divide by. * @return A new {@code Expr} representing the division operation. */ -export function divide(fieldName: string, value: any): FunctionExpr; -export function divide(left: Expr | string, right: Expr | any): FunctionExpr { +export function divide(fieldName: string, value: unknown): FunctionExpr; +export function divide( + left: Expr | string, + right: Expr | unknown +): FunctionExpr { const normalizedLeft = typeof left === 'string' ? field(left) : left; const normalizedRight = valueToDefaultExpr(right); return normalizedLeft.divide(normalizedRight); @@ -3747,7 +3754,7 @@ export function mod(left: Expr, right: Expr): FunctionExpr; * @param value The divisor constant. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(expression: Expr, value: any): FunctionExpr; +export function mod(expression: Expr, value: unknown): FunctionExpr; /** * @beta @@ -3779,8 +3786,8 @@ export function mod(fieldName: string, expression: Expr): FunctionExpr; * @param value The divisor constant. * @return A new {@code Expr} representing the modulo operation. */ -export function mod(fieldName: string, value: any): FunctionExpr; -export function mod(left: Expr | string, right: Expr | any): FunctionExpr { +export function mod(fieldName: string, value: unknown): FunctionExpr; +export function mod(left: Expr | string, right: Expr | unknown): FunctionExpr { const normalizedLeft = typeof left === 'string' ? field(left) : left; const normalizedRight = valueToDefaultExpr(right); return normalizedLeft.mod(normalizedRight); @@ -3799,8 +3806,8 @@ export function mod(left: Expr | string, right: Expr | any): FunctionExpr { * @param elements The input map to evaluate in the expression. * @return A new {@code Expr} representing the map function. */ -export function map(elements: Record): FunctionExpr { - const result: any[] = []; +export function map(elements: Record): FunctionExpr { + const result: Expr[] = []; for (const key in elements) { if (Object.prototype.hasOwnProperty.call(elements, key)) { const value = elements[key]; @@ -3822,7 +3829,7 @@ export function map(elements: Record): FunctionExpr { * @internal * @param plainObject */ -export function _mapValue(plainObject: Record): MapValue { +export function _mapValue(plainObject: Record): MapValue { const result: Map = new Map(); for (const key in plainObject) { if (Object.prototype.hasOwnProperty.call(plainObject, key)) { @@ -3846,7 +3853,7 @@ export function _mapValue(plainObject: Record): MapValue { * @param elements The input array to evaluate in the expression. * @return A new {@code Expr} representing the array function. */ -export function array(elements: any[]): FunctionExpr { +export function array(elements: unknown[]): FunctionExpr { return new FunctionExpr( 'array', elements.map(element => valueToDefaultExpr(element)) @@ -3883,7 +3890,7 @@ export function eq(left: Expr, right: Expr): BooleanExpr; * @param value The constant value to compare to. * @return A new `Expr` representing the equality comparison. */ -export function eq(expression: Expr, value: any): BooleanExpr; +export function eq(expression: Expr, value: unknown): BooleanExpr; /** * @beta @@ -3915,8 +3922,8 @@ export function eq(fieldName: string, expression: Expr): BooleanExpr; * @param value The constant value to compare to. * @return A new `Expr` representing the equality comparison. */ -export function eq(fieldName: string, value: any): BooleanExpr; -export function eq(left: Expr | string, right: any): BooleanExpr { +export function eq(fieldName: string, value: unknown): BooleanExpr; +export function eq(left: Expr | string, right: unknown): BooleanExpr { const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.eq(rightExpr); @@ -3952,7 +3959,7 @@ export function neq(left: Expr, right: Expr): BooleanExpr; * @param value The constant value to compare to. * @return A new `Expr` representing the inequality comparison. */ -export function neq(expression: Expr, value: any): BooleanExpr; +export function neq(expression: Expr, value: unknown): BooleanExpr; /** * @beta @@ -3984,8 +3991,8 @@ export function neq(fieldName: string, expression: Expr): BooleanExpr; * @param value The constant value to compare to. * @return A new `Expr` representing the inequality comparison. */ -export function neq(fieldName: string, value: any): BooleanExpr; -export function neq(left: Expr | string, right: any): BooleanExpr { +export function neq(fieldName: string, value: unknown): BooleanExpr; +export function neq(left: Expr | string, right: unknown): BooleanExpr { const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.neq(rightExpr); @@ -4021,7 +4028,7 @@ export function lt(left: Expr, right: Expr): BooleanExpr; * @param value The constant value to compare to. * @return A new `Expr` representing the less than comparison. */ -export function lt(expression: Expr, value: any): BooleanExpr; +export function lt(expression: Expr, value: unknown): BooleanExpr; /** * @beta @@ -4053,8 +4060,8 @@ export function lt(fieldName: string, expression: Expr): BooleanExpr; * @param value The constant value to compare to. * @return A new `Expr` representing the less than comparison. */ -export function lt(fieldName: string, value: any): BooleanExpr; -export function lt(left: Expr | string, right: any): BooleanExpr { +export function lt(fieldName: string, value: unknown): BooleanExpr; +export function lt(left: Expr | string, right: unknown): BooleanExpr { const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.lt(rightExpr); @@ -4091,7 +4098,7 @@ export function lte(left: Expr, right: Expr): BooleanExpr; * @param value The constant value to compare to. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(expression: Expr, value: any): BooleanExpr; +export function lte(expression: Expr, value: unknown): BooleanExpr; /** * Creates an expression that checks if a field's value is less than or equal to an expression. @@ -4121,8 +4128,8 @@ export function lte(fieldName: string, expression: Expr): BooleanExpr; * @param value The constant value to compare to. * @return A new `Expr` representing the less than or equal to comparison. */ -export function lte(fieldName: string, value: any): BooleanExpr; -export function lte(left: Expr | string, right: any): BooleanExpr { +export function lte(fieldName: string, value: unknown): BooleanExpr; +export function lte(left: Expr | string, right: unknown): BooleanExpr { const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.lte(rightExpr); @@ -4159,7 +4166,7 @@ export function gt(left: Expr, right: Expr): BooleanExpr; * @param value The constant value to compare to. * @return A new `Expr` representing the greater than comparison. */ -export function gt(expression: Expr, value: any): BooleanExpr; +export function gt(expression: Expr, value: unknown): BooleanExpr; /** * @beta @@ -4191,8 +4198,8 @@ export function gt(fieldName: string, expression: Expr): BooleanExpr; * @param value The constant value to compare to. * @return A new `Expr` representing the greater than comparison. */ -export function gt(fieldName: string, value: any): BooleanExpr; -export function gt(left: Expr | string, right: any): BooleanExpr { +export function gt(fieldName: string, value: unknown): BooleanExpr; +export function gt(left: Expr | string, right: unknown): BooleanExpr { const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.gt(rightExpr); @@ -4230,7 +4237,7 @@ export function gte(left: Expr, right: Expr): BooleanExpr; * @param value The constant value to compare to. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(expression: Expr, value: any): BooleanExpr; +export function gte(expression: Expr, value: unknown): BooleanExpr; /** * @beta @@ -4263,8 +4270,8 @@ export function gte(fieldName: string, value: Expr): BooleanExpr; * @param value The constant value to compare to. * @return A new `Expr` representing the greater than or equal to comparison. */ -export function gte(fieldName: string, value: any): BooleanExpr; -export function gte(left: Expr | string, right: any): BooleanExpr { +export function gte(fieldName: string, value: unknown): BooleanExpr; +export function gte(left: Expr | string, right: unknown): BooleanExpr { const leftExpr = left instanceof Expr ? left : field(left); const rightExpr = valueToDefaultExpr(right); return leftExpr.gte(rightExpr); @@ -4287,8 +4294,8 @@ export function gte(left: Expr | string, right: any): BooleanExpr { */ export function arrayConcat( firstArray: Expr, - secondArray: Expr | any, - ...otherArrays: Array + secondArray: Expr | unknown[], + ...otherArrays: Array ): FunctionExpr; /** @@ -4308,14 +4315,14 @@ export function arrayConcat( */ export function arrayConcat( firstArrayField: string, - secondArray: Expr | any[], - ...otherArrays: Array + secondArray: Expr | unknown[], + ...otherArrays: Array ): FunctionExpr; export function arrayConcat( firstArray: Expr | string, - secondArray: Expr | any[], - ...otherArrays: Array + secondArray: Expr | unknown[], + ...otherArrays: Array ): FunctionExpr { const exprValues = otherArrays.map(element => valueToDefaultExpr(element)); return fieldOfOrExpr(firstArray).arrayConcat( @@ -4354,7 +4361,7 @@ export function arrayContains(array: Expr, element: Expr): FunctionExpr; * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains(array: Expr, element: any): FunctionExpr; +export function arrayContains(array: Expr, element: unknown): FunctionExpr; /** * @beta @@ -4386,8 +4393,11 @@ export function arrayContains(fieldName: string, element: Expr): FunctionExpr; * @param element The element to search for in the array. * @return A new {@code Expr} representing the 'array_contains' comparison. */ -export function arrayContains(fieldName: string, element: any): BooleanExpr; -export function arrayContains(array: Expr | string, element: any): BooleanExpr { +export function arrayContains(fieldName: string, element: unknown): BooleanExpr; +export function arrayContains( + array: Expr | string, + element: unknown +): BooleanExpr { const arrayExpr = fieldOfOrExpr(array); const elementExpr = valueToDefaultExpr(element); return arrayExpr.arrayContains(elementExpr); @@ -4410,7 +4420,7 @@ export function arrayContains(array: Expr | string, element: any): BooleanExpr { */ export function arrayContainsAny( array: Expr, - values: Array + values: Array ): BooleanExpr; /** @@ -4431,7 +4441,7 @@ export function arrayContainsAny( */ export function arrayContainsAny( fieldName: string, - values: Array + values: Array ): BooleanExpr; /** @@ -4470,7 +4480,7 @@ export function arrayContainsAny(array: Expr, values: Expr): BooleanExpr; export function arrayContainsAny(fieldName: string, values: Expr): BooleanExpr; export function arrayContainsAny( array: Expr | string, - values: any[] | Expr + values: unknown[] | Expr ): BooleanExpr { // @ts-ignore implementation accepts both types return fieldOfOrExpr(array).arrayContainsAny(values); @@ -4492,7 +4502,7 @@ export function arrayContainsAny( */ export function arrayContainsAll( array: Expr, - values: Array + values: Array ): BooleanExpr; /** @@ -4512,7 +4522,7 @@ export function arrayContainsAll( */ export function arrayContainsAll( fieldName: string, - values: Array + values: Array ): BooleanExpr; /** @@ -4555,7 +4565,7 @@ export function arrayContainsAll( ): BooleanExpr; export function arrayContainsAll( array: Expr | string, - values: any[] | Expr + values: unknown[] | Expr ): BooleanExpr { // @ts-ignore implementation accepts both types return fieldOfOrExpr(array).arrayContainsAll(values); @@ -4593,7 +4603,10 @@ export function arrayLength(array: Expr): FunctionExpr { * @param values The values to check against. * @return A new {@code Expr} representing the 'IN' comparison. */ -export function eqAny(expression: Expr, values: Array): BooleanExpr; +export function eqAny( + expression: Expr, + values: Array +): BooleanExpr; /** * @beta @@ -4628,7 +4641,7 @@ export function eqAny(expression: Expr, arrayExpression: Expr): BooleanExpr; */ export function eqAny( fieldName: string, - values: Array + values: Array ): BooleanExpr; /** @@ -4649,7 +4662,7 @@ export function eqAny( export function eqAny(fieldName: string, arrayExpression: Expr): BooleanExpr; export function eqAny( element: Expr | string, - values: any[] | Expr + values: unknown[] | Expr ): BooleanExpr { // @ts-ignore implementation accepts both types return fieldOfOrExpr(element).eqAny(values); @@ -4670,7 +4683,10 @@ export function eqAny( * @param values The values to check against. * @return A new {@code Expr} representing the 'NOT IN' comparison. */ -export function notEqAny(element: Expr, values: Array): BooleanExpr; +export function notEqAny( + element: Expr, + values: Array +): BooleanExpr; /** * @beta @@ -4689,7 +4705,7 @@ export function notEqAny(element: Expr, values: Array): BooleanExpr; */ export function notEqAny( fieldName: string, - values: Array + values: Array ): BooleanExpr; /** @@ -4727,7 +4743,7 @@ export function notEqAny(fieldName: string, arrayExpression: Expr): BooleanExpr; export function notEqAny( element: Expr | string, - values: any[] | Expr + values: unknown[] | Expr ): BooleanExpr { // @ts-ignore implementation accepts both types return fieldOfOrExpr(element).notEqAny(values); @@ -4821,8 +4837,8 @@ export function not(booleanExpr: BooleanExpr): BooleanExpr { */ export function logicalMaximum( first: Expr, - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr; /** @@ -4844,14 +4860,14 @@ export function logicalMaximum( */ export function logicalMaximum( fieldName: string, - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr; export function logicalMaximum( first: Expr | string, - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr { return fieldOfOrExpr(first).logicalMaximum( valueToDefaultExpr(second), @@ -4878,8 +4894,8 @@ export function logicalMaximum( */ export function logicalMinimum( first: Expr, - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr; /** @@ -4902,14 +4918,14 @@ export function logicalMinimum( */ export function logicalMinimum( fieldName: string, - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr; export function logicalMinimum( first: Expr | string, - second: Expr | any, - ...others: Array + second: Expr | unknown, + ...others: Array ): FunctionExpr { return fieldOfOrExpr(first).logicalMinimum( valueToDefaultExpr(second), diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index a655ab153b8..a6c5090fa99 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -/* eslint @typescript-eslint/no-explicit-any: 0 */ - import { ObjectValue } from '../model/object_value'; import { Pipeline as ProtoPipeline, @@ -37,7 +35,7 @@ import { Ordering, Selectable, field, - constant + Constant } from './expressions'; import { AddFields, @@ -69,7 +67,7 @@ interface ReadableUserData { _readUserData(dataReader: UserDataReader): void; } -function isReadableUserData(value: any): value is ReadableUserData { +function isReadableUserData(value: unknown): value is ReadableUserData { return typeof (value as ReadableUserData)._readUserData === 'function'; } @@ -757,21 +755,21 @@ export class Pipeline implements ProtoSerializable { * @param params A list of parameters to configure the generic stage's behavior. * @return A new {@code Pipeline} object with this stage appended to the stage list. */ - genericStage(name: string, params: any[]): Pipeline { + genericStage(name: string, params: unknown[]): Pipeline { // Convert input values to Expressions. // We treat objects as mapValues and arrays as arrayValues, // this is unlike the default conversion for objects and arrays // passed to an expression. - const expressionParams = params.map((value: any) => { + const expressionParams = params.map((value: unknown) => { if (value instanceof Expr) { return value; } if (value instanceof AggregateFunction) { return value; } else if (isPlainObject(value)) { - return _mapValue(value); + return _mapValue(value as Record); } else { - return constant(value); + return new Constant(value); } }); From 458412c330e22c6966494987597f6356caeabb83 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Thu, 6 Mar 2025 15:56:59 -0700 Subject: [PATCH 62/75] lint fix --- packages/firestore/src/core/pipeline-util.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index 7cf6bae2588..dcc4a327687 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -114,7 +114,7 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { ); if (!values) { return fieldValue.exists(); - } else if (values.length == 1) { + } else if (values.length === 1) { return and(fieldValue.exists(), fieldValue.eq(values[0])); } else { return and(fieldValue.exists(), fieldValue.eqAny(values)); @@ -132,7 +132,7 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { ); if (!values) { return fieldValue.exists(); - } else if (values.length == 1) { + } else if (values.length === 1) { return and(fieldValue.exists(), fieldValue.neq(values[0])); } else { return and(fieldValue.exists(), fieldValue.notEqAny(values)); From a7b5deb105cf6c3222fd51daddc5e3b9d1d7f771 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 7 Mar 2025 10:20:42 -0700 Subject: [PATCH 63/75] Code cleanup --- .../firestore/src/lite-api/expressions.ts | 33 +++++++------------ packages/firestore/src/lite-api/pipeline.ts | 18 +++++----- .../integration/api/query_to_pipeline.test.ts | 2 +- 3 files changed, 20 insertions(+), 33 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index fbed850a1bb..295c2b8b581 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -22,7 +22,6 @@ import { import { Value as ProtoValue } from '../protos/firestore_proto_api'; import { JsonProtoSerializer, - ProtoSerializable, ProtoValueSerializable, toMapValue, toStringValue, @@ -623,7 +622,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * * ```typescript * // Check if the 'status' field is neither "pending" nor the value of 'rejectedStatus' - * field("status").notEqAny([]"pending", field("rejectedStatus")]); + * field("status").notEqAny(["pending", field("rejectedStatus")]); * ``` * * @param values The values or expressions to check against. @@ -2079,19 +2078,9 @@ export class AggregateFunction implements ProtoValueSerializable, UserData { * * An AggregateFunction with alias. */ -export class AggregateWithAlias - implements UserData, ProtoSerializable -{ +export class AggregateWithAlias implements UserData { constructor(readonly aggregate: AggregateFunction, readonly alias: string) {} - /** - * @private - * @internal - */ - _toProto(serializer: JsonProtoSerializer): ProtoValue { - throw new Error('ExprWithAlias should not be serialized directly.'); - } - /** * @private * @internal @@ -2470,7 +2459,7 @@ export class MapValue extends Expr { * execution. * * Typically, you would not use this class or its children directly. Use either the functions like {@link and}, {@link eq}, - * or the methods on {@link Expr} ({@link Expr#eq}, {@link Expr#lt}, etc) to construct new Function instances. + * or the methods on {@link Expr} ({@link Expr#eq}, {@link Expr#lt}, etc.) to construct new Function instances. */ export class FunctionExpr extends Expr { readonly exprType: ExprType = 'Function'; @@ -2548,11 +2537,11 @@ export class BooleanExpr extends FunctionExpr { * * ```typescript * // Count the number of documents where 'is_active' field equals true - * countif(field("is_active").eq(true)).as("numActiveDocuments"); + * countIf(field("is_active").eq(true)).as("numActiveDocuments"); * ``` * * @param booleanExpr - The boolean expression to evaluate on each input. - * @returns A new `AggregateFunction` representing the 'countif' aggregation. + * @returns A new `AggregateFunction` representing the 'countIf' aggregation. */ export function countIf(booleanExpr: BooleanExpr): AggregateFunction { return booleanExpr.countIf(); @@ -2882,7 +2871,7 @@ export function bitLeftShift(xValue: Expr, y: number): FunctionExpr; * ``` * * @param xValue An expression returning bits. - * @param right The right operand expression representing the number of bits to shift. + * @param numberExpr The right operand expression representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise left shift operation. */ export function bitLeftShift(xValue: Expr, numberExpr: Expr): FunctionExpr; @@ -2903,8 +2892,8 @@ export function bitLeftShift( * bitRightShift("field1", 2); * ``` * - * @param left The left operand field name. - * @param right The right operand constant representing the number of bits to shift. + * @param field The left operand field name. + * @param y The right operand constant representing the number of bits to shift. * @return A new {@code Expr} representing the bitwise right shift operation. */ export function bitRightShift(field: string, y: number): FunctionExpr; @@ -3342,7 +3331,7 @@ export function mapMerge( * mapMerge(field('settings'), { enabled: true }, cond(field('isAdmin'), { admin: true}, {}) * ``` * - * @param firstMap An expression or literal map map value that will be merged. + * @param firstMap An expression or literal map value that will be merged. * @param secondMap A required second map to merge. Represented as a literal or * an expression that returns a map. * @param otherMaps Optional additional maps to merge. Each map is represented @@ -3822,7 +3811,7 @@ export function map(elements: Record): FunctionExpr { * Internal use only * Converts a plainObject to a mapValue in the proto representation, * rather than a functionValue+map that is the result of the map(...) function. - * This behaves different than constant(plainObject) because it + * This behaves different from constant(plainObject) because it * traverses the input object, converts values in the object to expressions, * and calls _readUserData on each of these expressions. * @private @@ -6377,7 +6366,7 @@ export function manhattanDistance( * ``` * * @param vectorExpression The first vector (represented as an Expr) to compare against. - * @param vector The other vector (as an array of doubles or Vectorvalue) to compare against. + * @param vector The other vector (as an array of doubles or VectorValue) to compare against. * @return A new {@code Expr} representing the Manhattan distance between the two vectors. */ export function manhattanDistance( diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index a6c5090fa99..c768de0a550 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -347,17 +347,17 @@ export class Pipeline implements ProtoSerializable { * @private * * @param limit - * @param convertedFromLimitTolast + * @param convertedFromLimitToLast */ - _limit(limit: number, convertedFromLimitTolast: boolean): Pipeline { - return this._addStage(new Limit(limit, convertedFromLimitTolast)); + _limit(limit: number, convertedFromLimitToLast: boolean): Pipeline { + return this._addStage(new Limit(limit, convertedFromLimitToLast)); } /** * Returns a set of distinct {@link Expr} values from the inputs to this stage. * *

    This stage run through the results from previous stages to include only results with unique - * combinations of {@link Expr} values ({@link Field}, {@link Function}, etc). + * combinations of {@link Expr} values ({@link Field}, {@link Function}, etc.). * *

    The parameters to this stage are defined using {@link Selectable} expressions or {@code string}s: * @@ -605,7 +605,7 @@ export class Pipeline implements ProtoSerializable { * // } * ``` * - * @param field The {@link Field} field containing the nested map. + * @param fieldValue The {@link Field} field containing the nested map. * @return A new {@code Pipeline} object with this stage appended to the stage list. */ replaceWith(fieldValue: Field | string): Pipeline { @@ -628,7 +628,7 @@ export class Pipeline implements ProtoSerializable { * .sample(25); * ``` * - * @param documents The number of documents to sample.. + * @param documents The number of documents to sample. * @return A new {@code Pipeline} object with this stage appended to the stage list. */ sample(documents: number): Pipeline; @@ -648,8 +648,6 @@ export class Pipeline implements ProtoSerializable { * // Sample 50% of books. * firestore.pipeline().collection("books") * .sample({ percentage: 0.5 }); - * } - * * * @param options The {@code SampleOptions} specifies how sampling is performed. * @return A new {@code Pipeline} object with this stage appended to the stage list. @@ -722,8 +720,8 @@ export class Pipeline implements ProtoSerializable { * // { "title": "The Hitchhiker's Guide to the Galaxy", "tag": "adventure", "tagIndex": 2, ... } * ``` * - * @param selectable A selectable expression defining the field to unnest and the alias to use for each unnested element in the output documents. - * @param indexField An optional string value specifying the field path to write the offset (starting at zero) into the array the unnested element is from + * @param selectable A selectable expression defining the field to unnest and the alias to use for each un-nested element in the output documents. + * @param indexField An optional string value specifying the field path to write the offset (starting at zero) into the array the un-nested element is from * @return A new {@code Pipeline} object with this stage appended to the stage list. */ unnest(selectable: Selectable, indexField?: string): Pipeline { diff --git a/packages/firestore/test/integration/api/query_to_pipeline.test.ts b/packages/firestore/test/integration/api/query_to_pipeline.test.ts index 99aa6771143..763ac0ab57a 100644 --- a/packages/firestore/test/integration/api/query_to_pipeline.test.ts +++ b/packages/firestore/test/integration/api/query_to_pipeline.test.ts @@ -55,7 +55,7 @@ setLogLevel('debug'); // This is the Query integration tests from the lite API (no cache support) // with some additional test cases added for more complete coverage. -apiDescribe.only('Query to Pipeline', persistence => { +apiDescribe('Query to Pipeline', persistence => { addEqualityMatcher(); function verifyResults( From f6cc94bc86b67ed349b8ec43f033555421ee8f95 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 7 Mar 2025 10:21:38 -0700 Subject: [PATCH 64/75] FindNearest integration tests --- packages/firestore/src/lite-api/pipeline.ts | 2 +- packages/firestore/src/lite-api/stage.ts | 2 +- .../test/integration/api/pipeline.test.ts | 120 ++++++++++++++++-- 3 files changed, 110 insertions(+), 14 deletions(-) diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index c768de0a550..edbaaced940 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -516,7 +516,7 @@ export class Pipeline implements ProtoSerializable { const vectorObjectValue = new ObjectValue(value); return this._addStage( new FindNearest( - options.field, + options.field instanceof Field ? options.field : field(options.field), vectorObjectValue, options.distanceMeasure, options.limit, diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index c5e1cbdbfa5..7e29f2b0aaa 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -254,7 +254,7 @@ export class Where implements Stage { * @beta */ export interface FindNearestOptions { - field: Field; + field: Field | string; vectorValue: VectorValue | number[]; distanceMeasure: 'euclidean' | 'cosine' | 'dot_product'; limit?: number; diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index f1f26800a67..24586b94501 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -103,14 +103,15 @@ import { xor, field, constant, - _internalPipelineToExecutePipelineRequestProto + _internalPipelineToExecutePipelineRequestProto, + FindNearestOptions } from '../util/pipeline_export'; use(chaiAsPromised); setLogLevel('debug'); -apiDescribe('Pipelines', persistence => { +apiDescribe.only('Pipelines', persistence => { addEqualityMatcher(); let firestore: Firestore; @@ -172,7 +173,8 @@ apiDescribe('Pipelines', persistence => { nebula: false, others: { unknown: { year: 1980 } } }, - nestedField: { 'level.1': { 'level.2': true } } + nestedField: { 'level.1': { 'level.2': true } }, + embedding: vector([10, 1, 1, 1, 1, 1, 1, 1, 1, 1]) }, book2: { title: 'Pride and Prejudice', @@ -181,7 +183,8 @@ apiDescribe('Pipelines', persistence => { published: 1813, rating: 4.5, tags: ['classic', 'social commentary', 'love'], - awards: { none: true } + awards: { none: true }, + embedding: vector([1, 10, 1, 1, 1, 1, 1, 1, 1, 1]) }, book3: { title: 'One Hundred Years of Solitude', @@ -190,7 +193,8 @@ apiDescribe('Pipelines', persistence => { published: 1967, rating: 4.3, tags: ['family', 'history', 'fantasy'], - awards: { nobel: true, nebula: false } + awards: { nobel: true, nebula: false }, + embedding: vector([1, 1, 10, 1, 1, 1, 1, 1, 1, 1]) }, book4: { title: 'The Lord of the Rings', @@ -201,7 +205,8 @@ apiDescribe('Pipelines', persistence => { tags: ['adventure', 'magic', 'epic'], awards: { hugo: false, nebula: false }, remarks: null, - cost: NaN + cost: NaN, + embedding: vector([1, 1, 1, 10, 1, 1, 1, 1, 1, 1]) }, book5: { title: "The Handmaid's Tale", @@ -210,7 +215,8 @@ apiDescribe('Pipelines', persistence => { published: 1985, rating: 4.1, tags: ['feminism', 'totalitarianism', 'resistance'], - awards: { 'arthur c. clarke': true, 'booker prize': false } + awards: { 'arthur c. clarke': true, 'booker prize': false }, + embedding: vector([1, 1, 1, 1, 10, 1, 1, 1, 1, 1]) }, book6: { title: 'Crime and Punishment', @@ -219,7 +225,8 @@ apiDescribe('Pipelines', persistence => { published: 1866, rating: 4.3, tags: ['philosophy', 'crime', 'redemption'], - awards: { none: true } + awards: { none: true }, + embedding: vector([1, 1, 1, 1, 1, 10, 1, 1, 1, 1]) }, book7: { title: 'To Kill a Mockingbird', @@ -228,7 +235,8 @@ apiDescribe('Pipelines', persistence => { published: 1960, rating: 4.2, tags: ['racism', 'injustice', 'coming-of-age'], - awards: { pulitzer: true } + awards: { pulitzer: true }, + embedding: vector([1, 1, 1, 1, 1, 1, 10, 1, 1, 1]) }, book8: { title: '1984', @@ -237,7 +245,8 @@ apiDescribe('Pipelines', persistence => { published: 1949, rating: 4.2, tags: ['surveillance', 'totalitarianism', 'propaganda'], - awards: { prometheus: true } + awards: { prometheus: true }, + embedding: vector([1, 1, 1, 1, 1, 1, 1, 10, 1, 1]) }, book9: { title: 'The Great Gatsby', @@ -246,7 +255,8 @@ apiDescribe('Pipelines', persistence => { published: 1925, rating: 4.0, tags: ['wealth', 'american dream', 'love'], - awards: { none: true } + awards: { none: true }, + embedding: vector([1, 1, 1, 1, 1, 1, 1, 1, 10, 1]) }, book10: { title: 'Dune', @@ -255,7 +265,8 @@ apiDescribe('Pipelines', persistence => { published: 1965, rating: 4.6, tags: ['politics', 'desert', 'ecology'], - awards: { hugo: true, nebula: true } + awards: { hugo: true, nebula: true }, + embedding: vector([1, 1, 1, 1, 1, 1, 1, 1, 1, 10]) } }; return testCollectionWithDocs(bookDocs); @@ -1226,6 +1237,17 @@ apiDescribe('Pipelines', persistence => { .collection(randomCol.path) .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) .unnest(field('tags').as('tag')) + .select( + 'title', + 'author', + 'genre', + 'published', + 'rating', + 'tags', + 'tag', + 'awards', + 'nestedField' + ) ); expectResults( snapshot, @@ -1283,6 +1305,17 @@ apiDescribe('Pipelines', persistence => { .collection(randomCol.path) .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) .unnest(array([1, 2, 3]).as('copy')) + .select( + 'title', + 'author', + 'genre', + 'published', + 'rating', + 'tags', + 'copy', + 'awards', + 'nestedField' + ) ); expectResults( snapshot, @@ -1334,6 +1367,69 @@ apiDescribe('Pipelines', persistence => { ); }); }); + + describe('findNearest stage', () => { + it('run pipeline with findNearest', async () => { + const measures: Array = [ + 'euclidean', + 'dot_product', + 'cosine' + ]; + for (const measure of measures) { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol) + .findNearest({ + field: 'embedding', + vectorValue: vector([10, 1, 3, 1, 2, 1, 1, 1, 1, 1]), + limit: 3, + distanceMeasure: measure + }) + .select('title') + ); + expectResults( + snapshot, + { + title: "The Hitchhiker's Guide to the Galaxy" + }, + { + title: 'One Hundred Years of Solitude' + }, + { + title: "The Handmaid's Tale" + } + ); + } + }); + + it('optionally returns the computed distance', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol) + .findNearest({ + field: 'embedding', + vectorValue: vector([10, 1, 2, 1, 1, 1, 1, 1, 1, 1]), + limit: 2, + distanceMeasure: 'euclidean', + distanceField: 'computedDistance' + }) + .select('title', 'computedDistance') + ); + expectResults( + snapshot, + { + title: "The Hitchhiker's Guide to the Galaxy", + computedDistance: 1 + }, + { + title: 'One Hundred Years of Solitude', + computedDistance: 12.041594578792296 + } + ); + }); + }); }); describe('function expressions', () => { From 96e3d19ed0fefbdb8d26f6959dd4d9a527626b99 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 10 Mar 2025 14:03:52 -0600 Subject: [PATCH 65/75] Filling in gaps in test coverage --- .../firestore/src/lite-api/expressions.ts | 23 +- .../firestore/src/lite-api/pipeline-result.ts | 2 +- packages/firestore/src/lite-api/pipeline.ts | 15 +- packages/firestore/src/remote/serializer.ts | 1 + .../test/integration/api/pipeline.test.ts | 1461 ++++++++++------- 5 files changed, 869 insertions(+), 633 deletions(-) diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 295c2b8b581..646d29714ff 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -2225,10 +2225,9 @@ export function field(nameOrPath: string | FieldPath): Field { return new Field(documentIdFieldPath()._internalPath); } return new Field(fieldPathFromArgument('of', nameOrPath)); + } else if (documentIdFieldPath().isEqual(nameOrPath)) { + return new Field(documentIdFieldPath()._internalPath); } else { - if (documentIdFieldPath().isEqual(nameOrPath)) { - return new Field(documentIdFieldPath()._internalPath); - } return new Field(nameOrPath._internalPath); } } @@ -2292,14 +2291,11 @@ export class Constant extends Expr { _readUserData(dataReader: UserDataReader): void { const context = dataReader.createContext( UserDataSource.Argument, - 'Constant.of' + 'constant' ); if (isFirestoreValue(this._protoValue)) { return; - } else if (this.value === undefined) { - // TODO(pipeline) how should we treat the value of `undefined`? - this._protoValue = parseData(null, context)!; } else { this._protoValue = parseData(this.value, context)!; } @@ -2338,16 +2334,6 @@ export function constant(value: boolean): Constant; */ export function constant(value: null): Constant; -/** - * Creates a `Constant` instance for an undefined value. - * @private - * @internal - * - * @param value The undefined value. - * @return A new `Constant` instance. - */ -export function constant(value: undefined): Constant; - /** * Creates a `Constant` instance for a GeoPoint value. * @@ -5909,8 +5895,7 @@ export function countAll(): AggregateFunction { export function count(expression: Expr): AggregateFunction; /** - * Creates an aggregation that counts the number of stage inputs with valid evaluations of the - * provided field. + * Creates an aggregation that counts the number of stage inputs where the input field exists. * * ```typescript * // Count the total number of products diff --git a/packages/firestore/src/lite-api/pipeline-result.ts b/packages/firestore/src/lite-api/pipeline-result.ts index 27c41de1908..635636ac46b 100644 --- a/packages/firestore/src/lite-api/pipeline-result.ts +++ b/packages/firestore/src/lite-api/pipeline-result.ts @@ -103,7 +103,7 @@ export class PipelineResult { * * @param userDataWriter The serializer used to encode/decode protobuf. * @param ref The reference to the document. - * @param _fieldsProto The fields of the Firestore `Document` Protobuf backing + * @param fields The fields of the Firestore `Document` Protobuf backing * this document (or undefined if the document does not exist). * @param readTime The time when this result was read (or undefined if * the document exists only locally). diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index edbaaced940..299e5b89a93 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -475,13 +475,16 @@ export class Pipeline implements ProtoSerializable { return this._addStage( new Aggregate( new Map( - optionsOrTarget.accumulators.map((target: AggregateWithAlias) => [ - (target as unknown as AggregateWithAlias).alias, + optionsOrTarget.accumulators.map((target: AggregateWithAlias) => { this.readUserData( 'aggregate', + target as unknown as AggregateWithAlias + ); + return [ + (target as unknown as AggregateWithAlias).alias, (target as unknown as AggregateWithAlias).aggregate - ) - ]) + ]; + }) ), this.readUserData( 'aggregate', @@ -611,6 +614,7 @@ export class Pipeline implements ProtoSerializable { replaceWith(fieldValue: Field | string): Pipeline { const fieldExpr = typeof fieldValue === 'string' ? field(fieldValue) : fieldValue; + this.readUserData('replaceWith', fieldExpr); return this._addStage(new Replace(fieldExpr, 'full_replace')); } @@ -761,8 +765,7 @@ export class Pipeline implements ProtoSerializable { const expressionParams = params.map((value: unknown) => { if (value instanceof Expr) { return value; - } - if (value instanceof AggregateFunction) { + } else if (value instanceof AggregateFunction) { return value; } else if (isPlainObject(value)) { return _mapValue(value as Record); diff --git a/packages/firestore/src/remote/serializer.ts b/packages/firestore/src/remote/serializer.ts index 095e377eba6..45e771f1371 100644 --- a/packages/firestore/src/remote/serializer.ts +++ b/packages/firestore/src/remote/serializer.ts @@ -1444,6 +1444,7 @@ export function isProtoValueSerializable( value: any ): value is ProtoValueSerializable { return ( + !!value && typeof value._toProto === 'function' && value._protoValueType === 'ProtoValue' ); diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 24586b94501..35c68b7fd53 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -20,9 +20,17 @@ import chaiAsPromised from 'chai-as-promised'; import { AggregateFunction, + ascending, BooleanExpr, constantVector, - FunctionExpr + FunctionExpr, + timestampAdd, + timestampToUnixMicros, + timestampToUnixMillis, + timestampToUnixSeconds, + unixMicrosToTimestamp, + unixMillisToTimestamp, + vectorLength } from '../../../src/lite-api/expressions'; import { PipelineSnapshot } from '../../../src/lite-api/pipeline-result'; import { addEqualityMatcher } from '../../util/equality_matcher'; @@ -42,30 +50,37 @@ import { setLogLevel, collection, documentId as documentIdFieldPath, - writeBatch + writeBatch, + addDoc } from '../util/firebase_export'; import { apiDescribe, withTestCollection } from '../util/helpers'; import { array, + mod, descending, isNan, map, execute, add, + unixSecondsToTimestamp, and, arrayContains, arrayContainsAny, + count, avg, cosineDistance, countAll, dotProduct, endsWith, eq, + reverse, euclideanDistance, gt, like, lt, + strContains, lte, + arrayConcat, mapGet, neq, or, @@ -83,10 +98,13 @@ import { bitOr, bitXor, bitNot, + exists, bitLeftShift, bitRightShift, rand, arrayOffset, + minimum, + maximum, currentContext, isError, ifError, @@ -94,6 +112,7 @@ import { isNull, isNotNull, isNotNan, + timestampSub, mapRemove, mapMerge, documentId, @@ -149,7 +168,7 @@ apiDescribe.only('Pipelines', persistence => { if (data.length > 0) { if (typeof data[0] === 'string') { - const actualIds = docs.map(doc => doc.ref?.id); + const actualIds = docs.map(doc => doc.id); expect(actualIds).to.deep.equal(data); } else { docs.forEach(r => { @@ -299,277 +318,34 @@ apiDescribe.only('Pipelines', persistence => { await withTestCollectionPromise; }); - it('empty snapshot as expected', async () => { - const snapshot = await execute( - firestore.pipeline().collection(randomCol.path).limit(0) - ); - expect(snapshot.results.length).to.equal(0); - }); - - it('full snapshot as expected', async () => { - const snapshot = await execute( - firestore.pipeline().collection(randomCol.path) - ); - expect(snapshot.results.length).to.equal(10); - }); - - it('supports CollectionReference as source', async () => { - const snapshot = await execute(firestore.pipeline().collection(randomCol)); - expect(snapshot.results.length).to.equal(10); - }); - - it('supports list of documents as source', async () => { - const collName = randomCol.id; - - const snapshot = await execute( - firestore - .pipeline() - .documents([ - `${collName}/book1`, - doc(randomCol, 'book2'), - doc(randomCol, 'book3').path - ]) - ); - expect(snapshot.results.length).to.equal(3); - }); - - it('reject CollectionReference for another DB', async () => { - const db2 = getFirestore(firestore.app, 'notDefault'); - - expect(() => { - firestore.pipeline().collection(collection(db2, 'foo')); - }).to.throw(/Invalid CollectionReference/); - - await terminate(db2); - }); - - it('reject DocumentReference for another DB', async () => { - const db2 = getFirestore(firestore.app, 'notDefault'); - - expect(() => { - firestore.pipeline().documents([doc(db2, 'foo/bar')]); - }).to.throw(/Invalid DocumentReference/); - - await terminate(db2); - }); - - it('converts arrays and plain objects to functionValues if the customer intent is unspecified', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select( - 'title', - 'author', - 'genre', - 'rating', - 'published', - 'tags', - 'awards' - ) - .addFields( - array([ - 1, - 2, - field('genre'), - multiply('rating', 10), - [field('title')], - { - published: field('published') - } - ]).as('metadataArray'), - map({ - genre: field('genre'), - rating: multiply('rating', 10), - nestedArray: [field('title')], - nestedMap: { - published: field('published') - } - }).as('metadata') - ) - .where( - and( - eq('metadataArray', [ - 1, - 2, - field('genre'), - multiply('rating', 10), - [field('title')], - { - published: field('published') - } - ]), - eq('metadata', { - genre: field('genre'), - rating: multiply('rating', 10), - nestedArray: [field('title')], - nestedMap: { - published: field('published') - } - }) - ) - ) - ); - - expect(snapshot.results.length).to.equal(1); - - expectResults(snapshot, { - title: 'The Lord of the Rings', - author: 'J.R.R. Tolkien', - genre: 'Fantasy', - published: 1954, - rating: 4.7, - tags: ['adventure', 'magic', 'epic'], - awards: { hugo: false, nebula: false }, - metadataArray: [ - 1, - 2, - 'Fantasy', - 47, - ['The Lord of the Rings'], - { - published: 1954 - } - ], - metadata: { - genre: 'Fantasy', - rating: 47, - nestedArray: ['The Lord of the Rings'], - nestedMap: { - published: 1954 - } - } - }); - }); - - it('accepts and returns all data types', async () => { - const refDate = new Date(); - const refTimestamp = Timestamp.now(); - const constants = [ - constant(1).as('number'), - constant('a string').as('string'), - constant(true).as('boolean'), - constant(null).as('null'), - constant(new GeoPoint(0.1, 0.2)).as('geoPoint'), - constant(refTimestamp).as('timestamp'), - constant(refDate).as('date'), - constant( - Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])) - ).as('bytes'), - constant(doc(firestore, 'foo', 'bar')).as('documentReference'), - constant(vector([1, 2, 3])).as('vectorValue'), - map({ - 'number': 1, - 'string': 'a string', - 'boolean': true, - 'null': null, - 'geoPoint': new GeoPoint(0.1, 0.2), - 'timestamp': refTimestamp, - 'date': refDate, - 'uint8Array': Bytes.fromUint8Array( - new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0]) - ), - 'documentReference': doc(firestore, 'foo', 'bar'), - 'vectorValue': vector([1, 2, 3]), - 'map': { - 'number': 2, - 'string': 'b string' - }, - 'array': [1, 'c string'] - }).as('map'), - array([ - 1, - 'a string', - true, - null, - new GeoPoint(0.1, 0.2), - refTimestamp, - refDate, - Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), - doc(firestore, 'foo', 'bar'), - vector([1, 2, 3]), - { - 'number': 2, - 'string': 'b string' - } - ]).as('array') - ]; - - const snapshots = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select(constants[0], ...constants.slice(1)) - ); - - expectResults(snapshots, { - 'number': 1, - 'string': 'a string', - 'boolean': true, - 'null': null, - 'geoPoint': new GeoPoint(0.1, 0.2), - 'timestamp': refTimestamp, - 'date': Timestamp.fromDate(refDate), - 'bytes': Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), - 'documentReference': doc(firestore, 'foo', 'bar'), - 'vectorValue': vector([1, 2, 3]), - 'map': { - 'number': 1, - 'string': 'a string', - 'boolean': true, - 'null': null, - 'geoPoint': new GeoPoint(0.1, 0.2), - 'timestamp': refTimestamp, - 'date': Timestamp.fromDate(refDate), - 'uint8Array': Bytes.fromUint8Array( - new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0]) - ), - 'documentReference': doc(firestore, 'foo', 'bar'), - 'vectorValue': vector([1, 2, 3]), - 'map': { - 'number': 2, - 'string': 'b string' - }, - 'array': [1, 'c string'] - }, - 'array': [ - 1, - 'a string', - true, - null, - new GeoPoint(0.1, 0.2), - refTimestamp, - Timestamp.fromDate(refDate), - Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), - doc(firestore, 'foo', 'bar'), - vector([1, 2, 3]), - { - 'number': 2, - 'string': 'b string' - } - ] + describe('pipeline results', () => { + it('empty snapshot as expected', async () => { + const snapshot = await execute( + firestore.pipeline().collection(randomCol.path).limit(0) + ); + expect(snapshot.results.length).to.equal(0); }); - }); - it('supports internal serialization to proto', async () => { - const pipeline = firestore - .pipeline() - .collection('books') - .where(eq('awards.hugo', true)) - .select( - 'title', - field('nestedField.level.1'), - mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') + it('full snapshot as expected', async () => { + const ppl = firestore.pipeline().collection(randomCol.path); + const snapshot = await execute(ppl); + expect(snapshot.results.length).to.equal(10); + expect(snapshot.pipeline).to.equal(ppl); + expectResults( + snapshot, + 'book1', + 'book10', + 'book2', + 'book3', + 'book4', + 'book5', + 'book6', + 'book7', + 'book8', + 'book9' ); + }); - const proto = _internalPipelineToExecutePipelineRequestProto(pipeline); - expect(proto).not.to.be.null; - }); - - describe('timestamps', () => { it('returns execution time', async () => { const start = new Date().valueOf(); const pipeline = firestore.pipeline().collection(randomCol.path); @@ -673,6 +449,323 @@ apiDescribe.only('Pipelines', persistence => { }); }); + describe('pipeline sources', () => { + it('supports CollectionReference as source', async () => { + const snapshot = await execute( + firestore.pipeline().collection(randomCol) + ); + expect(snapshot.results.length).to.equal(10); + }); + + it('supports list of documents as source', async () => { + const collName = randomCol.id; + + const snapshot = await execute( + firestore + .pipeline() + .documents([ + `${collName}/book1`, + doc(randomCol, 'book2'), + doc(randomCol, 'book3').path + ]) + ); + expect(snapshot.results.length).to.equal(3); + }); + + it('reject CollectionReference for another DB', async () => { + const db2 = getFirestore(firestore.app, 'notDefault'); + + expect(() => { + firestore.pipeline().collection(collection(db2, 'foo')); + }).to.throw(/Invalid CollectionReference/); + + await terminate(db2); + }); + + it('reject DocumentReference for another DB', async () => { + const db2 = getFirestore(firestore.app, 'notDefault'); + + expect(() => { + firestore.pipeline().documents([doc(db2, 'foo/bar')]); + }).to.throw(/Invalid DocumentReference/); + + await terminate(db2); + }); + + it('supports collection group as source', async () => { + const randomSubCollectionId = Math.random().toString(16).slice(2); + const doc1 = await addDoc( + collection(randomCol, 'book1', randomSubCollectionId), + { order: 1 } + ); + const doc2 = await addDoc( + collection(randomCol, 'book2', randomSubCollectionId), + { order: 2 } + ); + const snapshot = await execute( + firestore + .pipeline() + .collectionGroup(randomSubCollectionId) + .sort(ascending('order')) + ); + expectResults(snapshot, doc1.id, doc2.id); + }); + + it('supports database as source', async () => { + const randomId = Math.random().toString(16).slice(2); + const doc1 = await addDoc(collection(randomCol, 'book1', 'sub'), { + order: 1, + randomId + }); + const doc2 = await addDoc(collection(randomCol, 'book2', 'sub'), { + order: 2, + randomId + }); + const snapshot = await execute( + firestore + .pipeline() + .database() + .where(eq('randomId', randomId)) + .sort(ascending('order')) + ); + expectResults(snapshot, doc1.id, doc2.id); + }); + }); + + describe('supported data types', () => { + it('accepts and returns all data types', async () => { + const refDate = new Date(); + const refTimestamp = Timestamp.now(); + const constants = [ + constant(1).as('number'), + constant('a string').as('string'), + constant(true).as('boolean'), + constant(null).as('null'), + constant(new GeoPoint(0.1, 0.2)).as('geoPoint'), + constant(refTimestamp).as('timestamp'), + constant(refDate).as('date'), + constant( + Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])) + ).as('bytes'), + constant(doc(firestore, 'foo', 'bar')).as('documentReference'), + constantVector(vector([1, 2, 3])).as('vectorValue'), + constantVector([1, 2, 3]).as('vectorValue2'), + map({ + 'number': 1, + 'string': 'a string', + 'boolean': true, + 'null': null, + 'geoPoint': new GeoPoint(0.1, 0.2), + 'timestamp': refTimestamp, + 'date': refDate, + 'uint8Array': Bytes.fromUint8Array( + new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0]) + ), + 'documentReference': doc(firestore, 'foo', 'bar'), + 'vectorValue': vector([1, 2, 3]), + 'map': { + 'number': 2, + 'string': 'b string' + }, + 'array': [1, 'c string'] + }).as('map'), + array([ + 1, + 'a string', + true, + null, + new GeoPoint(0.1, 0.2), + refTimestamp, + refDate, + Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), + doc(firestore, 'foo', 'bar'), + vector([1, 2, 3]), + { + 'number': 2, + 'string': 'b string' + } + ]).as('array') + ]; + + const snapshots = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constants[0], ...constants.slice(1)) + ); + + expectResults(snapshots, { + 'number': 1, + 'string': 'a string', + 'boolean': true, + 'null': null, + 'geoPoint': new GeoPoint(0.1, 0.2), + 'timestamp': refTimestamp, + 'date': Timestamp.fromDate(refDate), + 'bytes': Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), + 'documentReference': doc(firestore, 'foo', 'bar'), + 'vectorValue': vector([1, 2, 3]), + 'vectorValue2': vector([1, 2, 3]), + 'map': { + 'number': 1, + 'string': 'a string', + 'boolean': true, + 'null': null, + 'geoPoint': new GeoPoint(0.1, 0.2), + 'timestamp': refTimestamp, + 'date': Timestamp.fromDate(refDate), + 'uint8Array': Bytes.fromUint8Array( + new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0]) + ), + 'documentReference': doc(firestore, 'foo', 'bar'), + 'vectorValue': vector([1, 2, 3]), + 'map': { + 'number': 2, + 'string': 'b string' + }, + 'array': [1, 'c string'] + }, + 'array': [ + 1, + 'a string', + true, + null, + new GeoPoint(0.1, 0.2), + refTimestamp, + Timestamp.fromDate(refDate), + Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), + doc(firestore, 'foo', 'bar'), + vector([1, 2, 3]), + { + 'number': 2, + 'string': 'b string' + } + ] + }); + }); + + it.only('throws on undefined in a map', async () => { + expect(() => { + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + map({ + 'number': 1, + 'undefined': array([undefined]) + }).as('foo') + ); + }).to.throw( + 'Function constant() called with invalid data. Unsupported field value: undefined' + ); + }); + + it.only('throws on undefined in an array', async () => { + expect(() => { + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(array([1, undefined]).as('foo')); + }).to.throw( + 'Function constant() called with invalid data. Unsupported field value: undefined' + ); + }); + + it('converts arrays and plain objects to functionValues if the customer intent is unspecified', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + 'title', + 'author', + 'genre', + 'rating', + 'published', + 'tags', + 'awards' + ) + .addFields( + array([ + 1, + 2, + field('genre'), + multiply('rating', 10), + [field('title')], + { + published: field('published') + } + ]).as('metadataArray'), + map({ + genre: field('genre'), + rating: multiply('rating', 10), + nestedArray: [field('title')], + nestedMap: { + published: field('published') + } + }).as('metadata') + ) + .where( + and( + eq('metadataArray', [ + 1, + 2, + field('genre'), + multiply('rating', 10), + [field('title')], + { + published: field('published') + } + ]), + eq('metadata', { + genre: field('genre'), + rating: multiply('rating', 10), + nestedArray: [field('title')], + nestedMap: { + published: field('published') + } + }) + ) + ) + ); + + expect(snapshot.results.length).to.equal(1); + + expectResults(snapshot, { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + genre: 'Fantasy', + published: 1954, + rating: 4.7, + tags: ['adventure', 'magic', 'epic'], + awards: { hugo: false, nebula: false }, + metadataArray: [ + 1, + 2, + 'Fantasy', + 47, + ['The Lord of the Rings'], + { + published: 1954 + } + ], + metadata: { + genre: 'Fantasy', + rating: 47, + nestedArray: ['The Lord of the Rings'], + nestedMap: { + published: 1954 + } + } + }); + }); + }); + describe('stages', () => { describe('aggregate stage', () => { it('supports aggregate', async () => { @@ -734,18 +827,20 @@ apiDescribe.only('Pipelines', persistence => { ); }); - it('returns min and max accumulations', async () => { + it('returns min, max, count, and countAll accumulations', async () => { const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) .aggregate( + count('cost').as('booksWithCost'), countAll().as('count'), - field('rating').maximum().as('maxRating'), - field('published').minimum().as('minPublished') + maximum('rating').as('maxRating'), + minimum('published').as('minPublished') ) ); expectResults(snapshot, { + booksWithCost: 1, count: 10, maxRating: 4.7, minPublished: 1813 @@ -926,7 +1021,21 @@ apiDescribe.only('Pipelines', persistence => { }); describe('where stage', () => { - it('where with and', async () => { + it('where with and (2 conditions)', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where( + and( + gt('rating', 4.5), + eqAny('genre', ['Science Fiction', 'Romance', 'Fantasy']) + ) + ) + ); + expectResults(snapshot, 'book10', 'book4'); + }); + it('where with and (3 conditions)', async () => { const snapshot = await execute( firestore .pipeline() @@ -934,12 +1043,12 @@ apiDescribe.only('Pipelines', persistence => { .where( and( gt('rating', 4.5), - eq('genre', 'Science Fiction'), - lte('published', 1965) + eqAny('genre', ['Science Fiction', 'Romance', 'Fantasy']), + lt('published', 1965) ) ) ); - expectResults(snapshot, 'book10'); + expectResults(snapshot, 'book4'); }); it('where with or', async () => { const snapshot = await execute( @@ -1631,6 +1740,22 @@ apiDescribe.only('Pipelines', persistence => { ); }); + it('testStrContains', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(strContains('title', "'s")) + .select('title') + .sort(field('title').ascending()) + ); + expectResults( + snapshot, + { title: "The Handmaid's Tale" }, + { title: "The Hitchhiker's Guide to the Galaxy" } + ); + }); + it('testLength', async () => { const snapshot = await execute( firestore @@ -1707,7 +1832,8 @@ apiDescribe.only('Pipelines', persistence => { field('rating').multiply(10).as('ratingTimesTen'), field('rating').divide(2).as('ratingDividedByTwo'), multiply('rating', 10, 2).as('ratingTimes20'), - add('rating', 1, 2).as('ratingPlus3') + add('rating', 1, 2).as('ratingPlus3'), + mod('rating', 2).as('ratingMod2') ) .limit(1) ); @@ -1717,7 +1843,8 @@ apiDescribe.only('Pipelines', persistence => { ratingTimesTen: 42, ratingDividedByTwo: 2.1, ratingTimes20: 84, - ratingPlus3: 7.2 + ratingPlus3: 7.2, + ratingMod2: 0.2 }); }); @@ -1785,7 +1912,9 @@ apiDescribe.only('Pipelines', persistence => { ), isAbsent('foo').as('isAbsent'), isNotNull('title').as('titleIsNotNull'), - isNotNan('cost').as('costIsNotNan') + isNotNan('cost').as('costIsNotNan'), + exists('fooBarBaz').as('fooBarBazExists'), + field('title').as('titleExists') ) ); expectResults(snapshot, { @@ -1795,7 +1924,9 @@ apiDescribe.only('Pipelines', persistence => { ifError: 'was error', isAbsent: true, titleIsNotNull: true, - costIsNotNan: false + costIsNotNan: false, + fooBarBazExists: false, + titleExists: true }); snapshot = await execute( @@ -1911,6 +2042,19 @@ apiDescribe.only('Pipelines', persistence => { }); }); + it('testVectorLength', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(vectorLength(constantVector([1, 2, 3])).as('vectorLength')) + ); + expectResults(snapshot, { + vectorLength: 3 + }); + }); + it('testNestedFields', async () => { const snapshot = await execute( firestore @@ -2051,7 +2195,7 @@ apiDescribe.only('Pipelines', persistence => { }); }); - describe.skip('not implemented in backend', () => { + describe('not implemented in backend', () => { it('supports Bit_and', async () => { const snapshot = await execute( firestore @@ -2063,394 +2207,405 @@ apiDescribe.only('Pipelines', persistence => { expectResults(snapshot, { result: 4 }); - it('supports Bit_and', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select(constant(5).bitAnd(12).as('result')) - ); - expectResults(snapshot, { - result: 4 - }); - }); + }); - it('supports Bit_or', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select(bitOr(constant(5), 12).as('result')) - ); - expectResults(snapshot, { - result: 13 - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select(constant(5).bitOr(12).as('result')) - ); - expectResults(snapshot, { - result: 13 - }); + it('supports Bit_and', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constant(5).bitAnd(12).as('result')) + ); + expectResults(snapshot, { + result: 4 }); + }); - it('supports Bit_xor', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select(bitXor(constant(5), 12).as('result')) - ); - expectResults(snapshot, { - result: 9 - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select(constant(5).bitXor(12).as('result')) - ); - expectResults(snapshot, { - result: 9 - }); + it('supports Bit_or', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(bitOr(constant(5), 12).as('result')) + ); + expectResults(snapshot, { + result: 13 }); - - it('supports Bit_not', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select( - bitNot(constant(Bytes.fromUint8Array(Uint8Array.of(0xfd)))).as( - 'result' - ) - ) - ); - expectResults(snapshot, { - result: Bytes.fromUint8Array(Uint8Array.of(0x02)) - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select( - constant(Bytes.fromUint8Array(Uint8Array.of(0xfd))) - .bitNot() - .as('result') - ) - ); - expectResults(snapshot, { - result: Bytes.fromUint8Array(Uint8Array.of(0x02)) - }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constant(5).bitOr(12).as('result')) + ); + expectResults(snapshot, { + result: 13 }); + }); - it('supports Bit_left_shift', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select( - bitLeftShift( - constant(Bytes.fromUint8Array(Uint8Array.of(0x02))), - 2 - ).as('result') - ) - ); - expectResults(snapshot, { - result: Bytes.fromUint8Array(Uint8Array.of(0x04)) - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select( - constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) - .bitLeftShift(2) - .as('result') - ) - ); - expectResults(snapshot, { - result: Bytes.fromUint8Array(Uint8Array.of(0x04)) - }); + it('supports Bit_xor', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(bitXor(constant(5), 12).as('result')) + ); + expectResults(snapshot, { + result: 9 }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constant(5).bitXor(12).as('result')) + ); + expectResults(snapshot, { + result: 9 + }); + }); - it('supports Bit_right_shift', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select( - bitRightShift( - constant(Bytes.fromUint8Array(Uint8Array.of(0x02))), - 2 - ).as('result') - ) - ); - expectResults(snapshot, { - result: Bytes.fromUint8Array(Uint8Array.of(0x01)) - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select( - constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) - .bitRightShift(2) - .as('result') + it('supports Bit_not', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + bitNot(constant(Bytes.fromUint8Array(Uint8Array.of(0xfd)))).as( + 'result' ) - ); - expectResults(snapshot, { - result: Bytes.fromUint8Array(Uint8Array.of(0x01)) - }); + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x02)) }); - - it('supports Document_id', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(documentId(field('__path__')).as('docId')) - ); - expectResults(snapshot, { - docId: 'book4' - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(field('__path__').documentId().as('docId')) - ); - expectResults(snapshot, { - docId: 'book4' - }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + constant(Bytes.fromUint8Array(Uint8Array.of(0xfd))) + .bitNot() + .as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x02)) }); + }); - it('supports Substr', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(substr('title', 9, 2).as('of')) - ); - expectResults(snapshot, { - of: 'of' - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(field('title').substr(9, 2).as('of')) - ); - expectResults(snapshot, { - of: 'of' - }); + it('supports Bit_left_shift', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + bitLeftShift( + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x04)) }); - - it('supports Substr without length', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(substr('title', 9).as('of')) - ); - expectResults(snapshot, { - of: 'of the Rings' - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(field('title').substr(9).as('of')) - ); - expectResults(snapshot, { - of: 'of the Rings' - }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) + .bitLeftShift(2) + .as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x04)) }); + }); - it('arrayConcat works', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .select( - field('tags') - .arrayConcat(['newTag1', 'newTag2'], field('tags'), [null]) - .as('modifiedTags') - ) - .limit(1) - ); - expectResults(snapshot, { - modifiedTags: [ - 'comedy', - 'space', - 'adventure', - 'newTag1', - 'newTag2', - 'comedy', - 'space', - 'adventure', - null - ] - }); + it('supports Bit_right_shift', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + bitRightShift( + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x01)) }); - - it('testToLowercase', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .select(field('title').toLower().as('lowercaseTitle')) - .limit(1) - ); - expectResults(snapshot, { - lowercaseTitle: "the hitchhiker's guide to the galaxy" - }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) + .bitRightShift(2) + .as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x01)) }); + }); - it('testToUppercase', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .select(field('author').toUpper().as('uppercaseAuthor')) - .limit(1) - ); - expectResults(snapshot, { uppercaseAuthor: 'DOUGLAS ADAMS' }); + it('supports Document_id', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(documentId(field('__path__')).as('docId')) + ); + expectResults(snapshot, { + docId: 'book4' }); - - it('testTrim', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .addFields( - constant(" The Hitchhiker's Guide to the Galaxy ").as( - 'spacedTitle' - ) - ) - .select( - field('spacedTitle').trim().as('trimmedTitle'), - field('spacedTitle') - ) - .limit(1) - ); - expectResults(snapshot, { - spacedTitle: " The Hitchhiker's Guide to the Galaxy ", - trimmedTitle: "The Hitchhiker's Guide to the Galaxy" - }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('__path__').documentId().as('docId')) + ); + expectResults(snapshot, { + docId: 'book4' }); }); - it('supports Rand', async () => { - const snapshot = await execute( + it('supports Substr', async () => { + let snapshot = await execute( firestore .pipeline() .collection(randomCol.path) - .limit(10) - .select(rand().as('result')) + .sort(field('rating').descending()) + .limit(1) + .select(substr('title', 9, 2).as('of')) ); - expect(snapshot.results.length).to.equal(10); - snapshot.results.forEach(d => { - expect(d.get('result')).to.be.lt(1); - expect(d.get('result')).to.be.gte(0); + expectResults(snapshot, { + of: 'of' + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('title').substr(9, 2).as('of')) + ); + expectResults(snapshot, { + of: 'of' }); }); - it('supports array', async () => { - const snapshot = await execute( + it('supports Substr without length', async () => { + let snapshot = await execute( firestore .pipeline() .collection(randomCol.path) .sort(field('rating').descending()) .limit(1) - .select(array([1, 2, 3, 4]).as('metadata')) + .select(substr('title', 9).as('of')) ); - expect(snapshot.results.length).to.equal(1); expectResults(snapshot, { - metadata: [1, 2, 3, 4] + of: 'of the Rings' + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('title').substr(9).as('of')) + ); + expectResults(snapshot, { + of: 'of the Rings' }); }); - it('evaluates expression in array', async () => { + it('arrayConcat works', async () => { const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) .select( - array([1, 2, field('genre'), multiply('rating', 10)]).as( - 'metadata' - ) + arrayConcat('tags', ['newTag1', 'newTag2'], field('tags'), [ + null + ]).as('modifiedTags') ) + .limit(1) ); - expect(snapshot.results.length).to.equal(1); expectResults(snapshot, { - metadata: [1, 2, 'Fantasy', 47] + modifiedTags: [ + 'comedy', + 'space', + 'adventure', + 'newTag1', + 'newTag2', + 'comedy', + 'space', + 'adventure', + null + ] }); }); - it('supports arrayOffset', async () => { - let snapshot = await execute( + it('testToLowercase', async () => { + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(3) - .select(arrayOffset('tags', 0).as('firstTag')) + .select(field('title').toLower().as('lowercaseTitle')) + .limit(1) ); - const expectedResults = [ - { - firstTag: 'adventure' - }, - { - firstTag: 'politics' - }, - { - firstTag: 'classic' - } - ]; - expectResults(snapshot, ...expectedResults); + expectResults(snapshot, { + lowercaseTitle: "the hitchhiker's guide to the galaxy" + }); + }); - snapshot = await execute( + it('testToUppercase', async () => { + const snapshot = await execute( firestore .pipeline() .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(3) - .select(field('tags').arrayOffset(0).as('firstTag')) + .select(field('author').toUpper().as('uppercaseAuthor')) + .limit(1) + ); + expectResults(snapshot, { uppercaseAuthor: 'DOUGLAS ADAMS' }); + }); + + it('testTrim', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .addFields( + constant(" The Hitchhiker's Guide to the Galaxy ").as( + 'spacedTitle' + ) + ) + .select( + field('spacedTitle').trim().as('trimmedTitle'), + field('spacedTitle') + ) + .limit(1) ); - expectResults(snapshot, ...expectedResults); + expectResults(snapshot, { + spacedTitle: " The Hitchhiker's Guide to the Galaxy ", + trimmedTitle: "The Hitchhiker's Guide to the Galaxy" + }); }); + + it('test reverse', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eq('title', '1984')) + .limit(1) + .select(reverse('title').as('reverseTitle')) + ); + expectResults(snapshot, { title: '4891' }); + }); + }); + + it('supports Rand', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(10) + .select(rand().as('result')) + ); + expect(snapshot.results.length).to.equal(10); + snapshot.results.forEach(d => { + expect(d.get('result')).to.be.lt(1); + expect(d.get('result')).to.be.gte(0); + }); + }); + + it('supports array', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(array([1, 2, 3, 4]).as('metadata')) + ); + expect(snapshot.results.length).to.equal(1); + expectResults(snapshot, { + metadata: [1, 2, 3, 4] + }); + }); + + it('evaluates expression in array', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + array([1, 2, field('genre'), multiply('rating', 10)]).as('metadata') + ) + ); + expect(snapshot.results.length).to.equal(1); + expectResults(snapshot, { + metadata: [1, 2, 'Fantasy', 47] + }); + }); + + it('supports arrayOffset', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(arrayOffset('tags', 0).as('firstTag')) + ); + const expectedResults = [ + { + firstTag: 'adventure' + }, + { + firstTag: 'politics' + }, + { + firstTag: 'classic' + } + ]; + expectResults(snapshot, ...expectedResults); + + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(field('tags').arrayOffset(0).as('firstTag')) + ); + expectResults(snapshot, ...expectedResults); }); // TODO: current_context tests with are failing because of b/395937453 - it.skip('supports currentContext', async () => { + it('supports currentContext', async () => { const snapshot = await execute( firestore .pipeline() @@ -2559,6 +2714,81 @@ apiDescribe.only('Pipelines', persistence => { awards: { nebula: false, hugo: false, fakeAward: true } }); }); + + it('supports timestamp conversions', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + unixSecondsToTimestamp(constant(1741380235)).as( + 'unixSecondsToTimestamp' + ), + unixMillisToTimestamp(constant(1741380235123)).as( + 'unixMillisToTimestamp' + ), + unixMicrosToTimestamp(constant(1741380235123456)).as( + 'unixMicrosToTimestamp' + ), + timestampToUnixSeconds( + constant(new Timestamp(1741380235, 123456789)) + ).as('timestampToUnixSeconds'), + timestampToUnixMicros( + constant(new Timestamp(1741380235, 123456789)) + ).as('timestampToUnixMicros'), + timestampToUnixMillis( + constant(new Timestamp(1741380235, 123456789)) + ).as('timestampToUnixMillis') + ) + ); + expectResults(snapshot, { + unixMicrosToTimestamp: new Timestamp(1741380235, 123456000), + unixMillisToTimestamp: new Timestamp(1741380235, 123000000), + unixSecondsToTimestamp: new Timestamp(1741380235, 0), + timestampToUnixSeconds: 1741380235, + timestampToUnixMicros: 1741380235123456, + timestampToUnixMillis: 1741380235123 + }); + }); + + it('supports timestamp math', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constant(new Timestamp(1741380235, 0)).as('timestamp')) + .select( + timestampAdd('timestamp', 'day', 10).as('plus10days'), + timestampAdd('timestamp', 'hour', 10).as('plus10hours'), + timestampAdd('timestamp', 'minute', 10).as('plus10minutes'), + timestampAdd('timestamp', 'second', 10).as('plus10seconds'), + timestampAdd('timestamp', 'microsecond', 10).as('plus10micros'), + timestampAdd('timestamp', 'millisecond', 10).as('plus10millis'), + timestampSub('timestamp', 'day', 10).as('minus10days'), + timestampSub('timestamp', 'hour', 10).as('minus10hours'), + timestampSub('timestamp', 'minute', 10).as('minus10minutes'), + timestampSub('timestamp', 'second', 10).as('minus10seconds'), + timestampSub('timestamp', 'microsecond', 10).as('minus10micros'), + timestampSub('timestamp', 'millisecond', 10).as('minus10millis') + ) + ); + expectResults(snapshot, { + plus10days: new Timestamp(1742244235, 0), + plus10hours: new Timestamp(1741416235, 0), + plus10minutes: new Timestamp(1741380835, 0), + plus10seconds: new Timestamp(1741380245, 0), + plus10micros: new Timestamp(1741380235, 10000), + plus10millis: new Timestamp(1741380235, 10000000), + minus10days: new Timestamp(1740516235, 0), + minus10hours: new Timestamp(1741344235, 0), + minus10minutes: new Timestamp(1741379635, 0), + minus10seconds: new Timestamp(1741380225, 0), + minus10micros: new Timestamp(1741380234, 999990000), + minus10millis: new Timestamp(1741380234, 990000000) + }); + }); }); describe('pagination', () => { @@ -2702,4 +2932,21 @@ apiDescribe.only('Pipelines', persistence => { ); }); }); + + describe('console support', () => { + it('supports internal serialization to proto', async () => { + const pipeline = firestore + .pipeline() + .collection('books') + .where(eq('awards.hugo', true)) + .select( + 'title', + field('nestedField.level.1'), + mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') + ); + + const proto = _internalPipelineToExecutePipelineRequestProto(pipeline); + expect(proto).not.to.be.null; + }); + }); }); From fc614791b6acbd1398593ca12f5bebee268004b5 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:39:42 -0600 Subject: [PATCH 66/75] Implement Pipeline tests for the lite SDK --- .../test/integration/api/pipeline.test.ts | 4 +- .../integration/api/query_to_pipeline.test.ts | 2 +- packages/firestore/test/lite/pipeline.test.ts | 2928 +++++++++++++++++ 3 files changed, 2931 insertions(+), 3 deletions(-) create mode 100644 packages/firestore/test/lite/pipeline.test.ts diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 35c68b7fd53..7e5b329a982 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -645,7 +645,7 @@ apiDescribe.only('Pipelines', persistence => { }); }); - it.only('throws on undefined in a map', async () => { + it('throws on undefined in a map', async () => { expect(() => { firestore .pipeline() @@ -662,7 +662,7 @@ apiDescribe.only('Pipelines', persistence => { ); }); - it.only('throws on undefined in an array', async () => { + it('throws on undefined in an array', async () => { expect(() => { firestore .pipeline() diff --git a/packages/firestore/test/integration/api/query_to_pipeline.test.ts b/packages/firestore/test/integration/api/query_to_pipeline.test.ts index 763ac0ab57a..99aa6771143 100644 --- a/packages/firestore/test/integration/api/query_to_pipeline.test.ts +++ b/packages/firestore/test/integration/api/query_to_pipeline.test.ts @@ -55,7 +55,7 @@ setLogLevel('debug'); // This is the Query integration tests from the lite API (no cache support) // with some additional test cases added for more complete coverage. -apiDescribe('Query to Pipeline', persistence => { +apiDescribe.only('Query to Pipeline', persistence => { addEqualityMatcher(); function verifyResults( diff --git a/packages/firestore/test/lite/pipeline.test.ts b/packages/firestore/test/lite/pipeline.test.ts new file mode 100644 index 00000000000..f82a224ec5c --- /dev/null +++ b/packages/firestore/test/lite/pipeline.test.ts @@ -0,0 +1,2928 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// eslint-disable-next-line import/no-extraneous-dependencies +import { expect, use } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; + +import { Bytes } from '../../src/lite-api/bytes'; +import { + Firestore, + getFirestore, + terminate +} from '../../src/lite-api/database'; +import { + field, + and, + array, + arrayOffset, + constant, + add, + subtract, + multiply, + avg, + bitAnd, + substr, + constantVector, + bitLeftShift, + bitNot, + count, + mapMerge, + mapRemove, + bitOr, + ifError, + isAbsent, + isError, + or, + rand, + bitRightShift, + bitXor, + isNotNan, + manhattanDistance, + map, + isNotNull, + isNull, + mod, + documentId, + eq, + neq, + lt, + countIf, + currentContext, + lte, + gt, + arrayConcat, + arrayContains, + arrayContainsAny, + eqAny, + notEqAny, + xor, + cond, + logicalMaximum, + logicalMinimum, + exists, + isNan, + reverse, + like, + regexContains, + regexMatch, + strContains, + startsWith, + endsWith, + mapGet, + countAll, + minimum, + maximum, + cosineDistance, + dotProduct, + euclideanDistance, + vectorLength, + unixMicrosToTimestamp, + timestampToUnixMicros, + unixMillisToTimestamp, + timestampToUnixMillis, + unixSecondsToTimestamp, + timestampToUnixSeconds, + timestampAdd, + timestampSub, + ascending, + descending, + FunctionExpr, + BooleanExpr, + AggregateFunction +} from '../../src/lite-api/expressions'; +import { documentId as documentIdFieldPath } from '../../src/lite-api/field_path'; +import { vector } from '../../src/lite-api/field_value_impl'; +import { GeoPoint } from '../../src/lite-api/geo_point'; +import { PipelineSnapshot } from '../../src/lite-api/pipeline-result'; +import { execute } from '../../src/lite-api/pipeline_impl'; +import { + DocumentData, + CollectionReference, + collection, + doc +} from '../../src/lite-api/reference'; +import { addDoc, setDoc } from '../../src/lite-api/reference_impl'; +import { FindNearestOptions } from '../../src/lite-api/stage'; +import { Timestamp } from '../../src/lite-api/timestamp'; +import { writeBatch } from '../../src/lite-api/write_batch'; +import { addEqualityMatcher } from '../util/equality_matcher'; +import { Deferred } from '../util/promise'; + +import { withTestCollection } from './helpers'; + +use(chaiAsPromised); + +describe('Firestore Pipelines', () => { + addEqualityMatcher(); + + let firestore: Firestore; + let randomCol: CollectionReference; + let beginDocCreation: number = 0; + let endDocCreation: number = 0; + + async function testCollectionWithDocs(docs: { + [id: string]: DocumentData; + }): Promise> { + beginDocCreation = new Date().valueOf(); + for (const id in docs) { + if (docs.hasOwnProperty(id)) { + const ref = doc(randomCol, id); + await setDoc(ref, docs[id]); + } + } + endDocCreation = new Date().valueOf(); + return randomCol; + } + + function expectResults(snapshot: PipelineSnapshot, ...docs: string[]): void; + function expectResults( + snapshot: PipelineSnapshot, + ...data: DocumentData[] + ): void; + + function expectResults( + snapshot: PipelineSnapshot, + ...data: DocumentData[] | string[] + ): void { + const docs = snapshot.results; + + expect(docs.length).to.equal(data.length); + + if (data.length > 0) { + if (typeof data[0] === 'string') { + const actualIds = docs.map(doc => doc.id); + expect(actualIds).to.deep.equal(data); + } else { + docs.forEach(r => { + expect(r.data()).to.deep.equal(data.shift()); + }); + } + } + } + + async function setupBookDocs(): Promise> { + const bookDocs: { [id: string]: DocumentData } = { + book1: { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } }, + embedding: vector([10, 1, 1, 1, 1, 1, 1, 1, 1, 1]) + }, + book2: { + title: 'Pride and Prejudice', + author: 'Jane Austen', + genre: 'Romance', + published: 1813, + rating: 4.5, + tags: ['classic', 'social commentary', 'love'], + awards: { none: true }, + embedding: vector([1, 10, 1, 1, 1, 1, 1, 1, 1, 1]) + }, + book3: { + title: 'One Hundred Years of Solitude', + author: 'Gabriel García Márquez', + genre: 'Magical Realism', + published: 1967, + rating: 4.3, + tags: ['family', 'history', 'fantasy'], + awards: { nobel: true, nebula: false }, + embedding: vector([1, 1, 10, 1, 1, 1, 1, 1, 1, 1]) + }, + book4: { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + genre: 'Fantasy', + published: 1954, + rating: 4.7, + tags: ['adventure', 'magic', 'epic'], + awards: { hugo: false, nebula: false }, + remarks: null, + cost: NaN, + embedding: vector([1, 1, 1, 10, 1, 1, 1, 1, 1, 1]) + }, + book5: { + title: "The Handmaid's Tale", + author: 'Margaret Atwood', + genre: 'Dystopian', + published: 1985, + rating: 4.1, + tags: ['feminism', 'totalitarianism', 'resistance'], + awards: { 'arthur c. clarke': true, 'booker prize': false }, + embedding: vector([1, 1, 1, 1, 10, 1, 1, 1, 1, 1]) + }, + book6: { + title: 'Crime and Punishment', + author: 'Fyodor Dostoevsky', + genre: 'Psychological Thriller', + published: 1866, + rating: 4.3, + tags: ['philosophy', 'crime', 'redemption'], + awards: { none: true }, + embedding: vector([1, 1, 1, 1, 1, 10, 1, 1, 1, 1]) + }, + book7: { + title: 'To Kill a Mockingbird', + author: 'Harper Lee', + genre: 'Southern Gothic', + published: 1960, + rating: 4.2, + tags: ['racism', 'injustice', 'coming-of-age'], + awards: { pulitzer: true }, + embedding: vector([1, 1, 1, 1, 1, 1, 10, 1, 1, 1]) + }, + book8: { + title: '1984', + author: 'George Orwell', + genre: 'Dystopian', + published: 1949, + rating: 4.2, + tags: ['surveillance', 'totalitarianism', 'propaganda'], + awards: { prometheus: true }, + embedding: vector([1, 1, 1, 1, 1, 1, 1, 10, 1, 1]) + }, + book9: { + title: 'The Great Gatsby', + author: 'F. Scott Fitzgerald', + genre: 'Modernist', + published: 1925, + rating: 4.0, + tags: ['wealth', 'american dream', 'love'], + awards: { none: true }, + embedding: vector([1, 1, 1, 1, 1, 1, 1, 1, 10, 1]) + }, + book10: { + title: 'Dune', + author: 'Frank Herbert', + genre: 'Science Fiction', + published: 1965, + rating: 4.6, + tags: ['politics', 'desert', 'ecology'], + awards: { hugo: true, nebula: true }, + embedding: vector([1, 1, 1, 1, 1, 1, 1, 1, 1, 10]) + } + }; + return testCollectionWithDocs(bookDocs); + } + + let testDeferred: Deferred | undefined; + let withTestCollectionPromise: Promise | undefined; + + beforeEach(async () => { + const setupDeferred = new Deferred(); + testDeferred = new Deferred(); + withTestCollectionPromise = withTestCollection(async collectionRef => { + randomCol = collectionRef; + firestore = collectionRef.firestore; + await setupBookDocs(); + setupDeferred.resolve(); + + return testDeferred?.promise; + }); + + await setupDeferred.promise; + }); + + afterEach(async () => { + testDeferred?.resolve(); + await withTestCollectionPromise; + }); + + describe('pipeline results', () => { + it('empty snapshot as expected', async () => { + const snapshot = await execute( + firestore.pipeline().collection(randomCol.path).limit(0) + ); + expect(snapshot.results.length).to.equal(0); + }); + + it('full snapshot as expected', async () => { + const ppl = firestore.pipeline().collection(randomCol.path); + const snapshot = await execute(ppl); + expect(snapshot.results.length).to.equal(10); + expect(snapshot.pipeline).to.equal(ppl); + expectResults( + snapshot, + 'book1', + 'book10', + 'book2', + 'book3', + 'book4', + 'book5', + 'book6', + 'book7', + 'book8', + 'book9' + ); + }); + + it('returns execution time', async () => { + const start = new Date().valueOf(); + const pipeline = firestore.pipeline().collection(randomCol.path); + + const snapshot = await execute(pipeline); + const end = new Date().valueOf(); + + expect(snapshot.executionTime.toDate().valueOf()).to.approximately( + (start + end) / 2, + end - start + ); + }); + + it('returns execution time for an empty query', async () => { + const start = new Date().valueOf(); + const pipeline = firestore.pipeline().collection(randomCol.path).limit(0); + + const snapshot = await execute(pipeline); + const end = new Date().valueOf(); + + expect(snapshot.results.length).to.equal(0); + + expect(snapshot.executionTime.toDate().valueOf()).to.approximately( + (start + end) / 2, + end - start + ); + }); + + it('returns create and update time for each document', async () => { + const pipeline = firestore.pipeline().collection(randomCol.path); + + let snapshot = await execute(pipeline); + expect(snapshot.results.length).to.equal(10); + snapshot.results.forEach(doc => { + expect(doc.createTime).to.not.be.null; + expect(doc.updateTime).to.not.be.null; + + expect(doc.createTime!.toDate().valueOf()).to.approximately( + (beginDocCreation + endDocCreation) / 2, + endDocCreation - beginDocCreation + ); + expect(doc.updateTime!.toDate().valueOf()).to.approximately( + (beginDocCreation + endDocCreation) / 2, + endDocCreation - beginDocCreation + ); + expect(doc.createTime?.valueOf()).to.equal(doc.updateTime?.valueOf()); + }); + + const wb = writeBatch(firestore); + snapshot.results.forEach(doc => { + wb.update(doc.ref!, { newField: 'value' }); + }); + await wb.commit(); + + snapshot = await execute(pipeline); + expect(snapshot.results.length).to.equal(10); + snapshot.results.forEach(doc => { + expect(doc.createTime).to.not.be.null; + expect(doc.updateTime).to.not.be.null; + expect(doc.createTime!.toDate().valueOf()).to.be.lessThan( + doc.updateTime!.toDate().valueOf() + ); + }); + }); + + it('returns execution time for an aggregate query', async () => { + const start = new Date().valueOf(); + const pipeline = firestore + .pipeline() + .collection(randomCol.path) + .aggregate(avg('rating').as('avgRating')); + + const snapshot = await execute(pipeline); + const end = new Date().valueOf(); + + expect(snapshot.results.length).to.equal(1); + + expect(snapshot.executionTime.toDate().valueOf()).to.approximately( + (start + end) / 2, + end - start + ); + }); + + it('returns undefined create and update time for each result in an aggregate query', async () => { + const pipeline = firestore + .pipeline() + .collection(randomCol.path) + .aggregate({ + accumulators: [avg('rating').as('avgRating')], + groups: ['genre'] + }); + + const snapshot = await execute(pipeline); + + expect(snapshot.results.length).to.equal(8); + + snapshot.results.forEach(doc => { + expect(doc.updateTime).to.be.undefined; + expect(doc.createTime).to.be.undefined; + }); + }); + }); + + describe('pipeline sources', () => { + it('supports CollectionReference as source', async () => { + const snapshot = await execute( + firestore.pipeline().collection(randomCol) + ); + expect(snapshot.results.length).to.equal(10); + }); + + it('supports list of documents as source', async () => { + const collName = randomCol.id; + + const snapshot = await execute( + firestore + .pipeline() + .documents([ + `${collName}/book1`, + doc(randomCol, 'book2'), + doc(randomCol, 'book3').path + ]) + ); + expect(snapshot.results.length).to.equal(3); + }); + + it('reject CollectionReference for another DB', async () => { + const db2 = getFirestore(firestore.app, 'notDefault'); + + expect(() => { + firestore.pipeline().collection(collection(db2, 'foo')); + }).to.throw(/Invalid CollectionReference/); + + await terminate(db2); + }); + + it('reject DocumentReference for another DB', async () => { + const db2 = getFirestore(firestore.app, 'notDefault'); + + expect(() => { + firestore.pipeline().documents([doc(db2, 'foo/bar')]); + }).to.throw(/Invalid DocumentReference/); + + await terminate(db2); + }); + + it('supports collection group as source', async () => { + const randomSubCollectionId = Math.random().toString(16).slice(2); + const doc1 = await addDoc( + collection(randomCol, 'book1', randomSubCollectionId), + { order: 1 } + ); + const doc2 = await addDoc( + collection(randomCol, 'book2', randomSubCollectionId), + { order: 2 } + ); + const snapshot = await execute( + firestore + .pipeline() + .collectionGroup(randomSubCollectionId) + .sort(ascending('order')) + ); + expectResults(snapshot, doc1.id, doc2.id); + }); + + it('supports database as source', async () => { + const randomId = Math.random().toString(16).slice(2); + const doc1 = await addDoc(collection(randomCol, 'book1', 'sub'), { + order: 1, + randomId + }); + const doc2 = await addDoc(collection(randomCol, 'book2', 'sub'), { + order: 2, + randomId + }); + const snapshot = await execute( + firestore + .pipeline() + .database() + .where(eq('randomId', randomId)) + .sort(ascending('order')) + ); + expectResults(snapshot, doc1.id, doc2.id); + }); + }); + + describe('supported data types', () => { + it('accepts and returns all data types', async () => { + const refDate = new Date(); + const refTimestamp = Timestamp.now(); + const constants = [ + constant(1).as('number'), + constant('a string').as('string'), + constant(true).as('boolean'), + constant(null).as('null'), + constant(new GeoPoint(0.1, 0.2)).as('geoPoint'), + constant(refTimestamp).as('timestamp'), + constant(refDate).as('date'), + constant( + Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])) + ).as('bytes'), + constant(doc(firestore, 'foo', 'bar')).as('documentReference'), + constantVector(vector([1, 2, 3])).as('vectorValue'), + constantVector([1, 2, 3]).as('vectorValue2'), + map({ + 'number': 1, + 'string': 'a string', + 'boolean': true, + 'null': null, + 'geoPoint': new GeoPoint(0.1, 0.2), + 'timestamp': refTimestamp, + 'date': refDate, + 'uint8Array': Bytes.fromUint8Array( + new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0]) + ), + 'documentReference': doc(firestore, 'foo', 'bar'), + 'vectorValue': vector([1, 2, 3]), + 'map': { + 'number': 2, + 'string': 'b string' + }, + 'array': [1, 'c string'] + }).as('map'), + array([ + 1, + 'a string', + true, + null, + new GeoPoint(0.1, 0.2), + refTimestamp, + refDate, + Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), + doc(firestore, 'foo', 'bar'), + vector([1, 2, 3]), + { + 'number': 2, + 'string': 'b string' + } + ]).as('array') + ]; + + const snapshots = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constants[0], ...constants.slice(1)) + ); + + expectResults(snapshots, { + 'number': 1, + 'string': 'a string', + 'boolean': true, + 'null': null, + 'geoPoint': new GeoPoint(0.1, 0.2), + 'timestamp': refTimestamp, + 'date': Timestamp.fromDate(refDate), + 'bytes': Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), + 'documentReference': doc(firestore, 'foo', 'bar'), + 'vectorValue': vector([1, 2, 3]), + 'vectorValue2': vector([1, 2, 3]), + 'map': { + 'number': 1, + 'string': 'a string', + 'boolean': true, + 'null': null, + 'geoPoint': new GeoPoint(0.1, 0.2), + 'timestamp': refTimestamp, + 'date': Timestamp.fromDate(refDate), + 'uint8Array': Bytes.fromUint8Array( + new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0]) + ), + 'documentReference': doc(firestore, 'foo', 'bar'), + 'vectorValue': vector([1, 2, 3]), + 'map': { + 'number': 2, + 'string': 'b string' + }, + 'array': [1, 'c string'] + }, + 'array': [ + 1, + 'a string', + true, + null, + new GeoPoint(0.1, 0.2), + refTimestamp, + Timestamp.fromDate(refDate), + Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])), + doc(firestore, 'foo', 'bar'), + vector([1, 2, 3]), + { + 'number': 2, + 'string': 'b string' + } + ] + }); + }); + + it('throws on undefined in a map', async () => { + expect(() => { + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + map({ + 'number': 1, + 'undefined': array([undefined]) + }).as('foo') + ); + }).to.throw( + 'Function constant() called with invalid data. Unsupported field value: undefined' + ); + }); + + it('throws on undefined in an array', async () => { + expect(() => { + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(array([1, undefined]).as('foo')); + }).to.throw( + 'Function constant() called with invalid data. Unsupported field value: undefined' + ); + }); + + it('converts arrays and plain objects to functionValues if the customer intent is unspecified', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + 'title', + 'author', + 'genre', + 'rating', + 'published', + 'tags', + 'awards' + ) + .addFields( + array([ + 1, + 2, + field('genre'), + multiply('rating', 10), + [field('title')], + { + published: field('published') + } + ]).as('metadataArray'), + map({ + genre: field('genre'), + rating: multiply('rating', 10), + nestedArray: [field('title')], + nestedMap: { + published: field('published') + } + }).as('metadata') + ) + .where( + and( + eq('metadataArray', [ + 1, + 2, + field('genre'), + multiply('rating', 10), + [field('title')], + { + published: field('published') + } + ]), + eq('metadata', { + genre: field('genre'), + rating: multiply('rating', 10), + nestedArray: [field('title')], + nestedMap: { + published: field('published') + } + }) + ) + ) + ); + + expect(snapshot.results.length).to.equal(1); + + expectResults(snapshot, { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + genre: 'Fantasy', + published: 1954, + rating: 4.7, + tags: ['adventure', 'magic', 'epic'], + awards: { hugo: false, nebula: false }, + metadataArray: [ + 1, + 2, + 'Fantasy', + 47, + ['The Lord of the Rings'], + { + published: 1954 + } + ], + metadata: { + genre: 'Fantasy', + rating: 47, + nestedArray: ['The Lord of the Rings'], + nestedMap: { + published: 1954 + } + } + }); + }); + }); + + describe('stages', () => { + describe('aggregate stage', () => { + it('supports aggregate', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .aggregate(countAll().as('count')) + ); + expectResults(snapshot, { count: 10 }); + + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eq('genre', 'Science Fiction')) + .aggregate( + countAll().as('count'), + avg('rating').as('avgRating'), + field('rating').maximum().as('maxRating') + ) + ); + expectResults(snapshot, { count: 2, avgRating: 4.4, maxRating: 4.6 }); + }); + + it('rejects groups without accumulators', async () => { + await expect( + execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(lt('published', 1900)) + .aggregate({ + accumulators: [], + groups: ['genre'] + }) + ) + ).to.be.rejected; + }); + + it('returns group and accumulate results', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(lt(field('published'), 1984)) + .aggregate({ + accumulators: [avg('rating').as('avgRating')], + groups: ['genre'] + }) + .where(gt('avgRating', 4.3)) + .sort(field('avgRating').descending()) + ); + expectResults( + snapshot, + { avgRating: 4.7, genre: 'Fantasy' }, + { avgRating: 4.5, genre: 'Romance' }, + { avgRating: 4.4, genre: 'Science Fiction' } + ); + }); + + it('returns min, max, count, and countAll accumulations', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .aggregate( + count('cost').as('booksWithCost'), + countAll().as('count'), + maximum('rating').as('maxRating'), + minimum('published').as('minPublished') + ) + ); + expectResults(snapshot, { + booksWithCost: 1, + count: 10, + maxRating: 4.7, + minPublished: 1813 + }); + }); + + it('returns countif accumulation', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .aggregate(countIf(field('rating').gt(4.3)).as('count')) + ); + const expectedResults = { + count: 3 + }; + expectResults(snapshot, expectedResults); + + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .aggregate(field('rating').gt(4.3).countIf().as('count')) + ); + expectResults(snapshot, expectedResults); + }); + }); + + describe('distinct stage', () => { + it('returns distinct values as expected', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .distinct('genre', 'author') + .sort(field('genre').ascending(), field('author').ascending()) + ); + expectResults( + snapshot, + { genre: 'Dystopian', author: 'George Orwell' }, + { genre: 'Dystopian', author: 'Margaret Atwood' }, + { genre: 'Fantasy', author: 'J.R.R. Tolkien' }, + { genre: 'Magical Realism', author: 'Gabriel García Márquez' }, + { genre: 'Modernist', author: 'F. Scott Fitzgerald' }, + { genre: 'Psychological Thriller', author: 'Fyodor Dostoevsky' }, + { genre: 'Romance', author: 'Jane Austen' }, + { genre: 'Science Fiction', author: 'Douglas Adams' }, + { genre: 'Science Fiction', author: 'Frank Herbert' }, + { genre: 'Southern Gothic', author: 'Harper Lee' } + ); + }); + }); + + describe('select stage', () => { + it('can select fields', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .sort(field('author').ascending()) + ); + expectResults( + snapshot, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams' + }, + { title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' }, + { title: 'Dune', author: 'Frank Herbert' }, + { title: 'Crime and Punishment', author: 'Fyodor Dostoevsky' }, + { + title: 'One Hundred Years of Solitude', + author: 'Gabriel García Márquez' + }, + { title: '1984', author: 'George Orwell' }, + { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, + { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' }, + { title: 'Pride and Prejudice', author: 'Jane Austen' }, + { title: "The Handmaid's Tale", author: 'Margaret Atwood' } + ); + }); + }); + + describe('addField stage', () => { + it('can add fields', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .addFields(constant('bar').as('foo')) + .sort(field('author').ascending()) + ); + expectResults( + snapshot, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + foo: 'bar' + }, + { + title: 'The Great Gatsby', + author: 'F. Scott Fitzgerald', + foo: 'bar' + }, + { title: 'Dune', author: 'Frank Herbert', foo: 'bar' }, + { + title: 'Crime and Punishment', + author: 'Fyodor Dostoevsky', + foo: 'bar' + }, + { + title: 'One Hundred Years of Solitude', + author: 'Gabriel García Márquez', + foo: 'bar' + }, + { title: '1984', author: 'George Orwell', foo: 'bar' }, + { + title: 'To Kill a Mockingbird', + author: 'Harper Lee', + foo: 'bar' + }, + { + title: 'The Lord of the Rings', + author: 'J.R.R. Tolkien', + foo: 'bar' + }, + { title: 'Pride and Prejudice', author: 'Jane Austen', foo: 'bar' }, + { + title: "The Handmaid's Tale", + author: 'Margaret Atwood', + foo: 'bar' + } + ); + }); + }); + + describe('removeFields stage', () => { + it('can remove fields', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .sort(field('author').ascending()) + .removeFields(field('author')) + .sort(field('author').ascending()) + ); + expectResults( + snapshot, + { + title: "The Hitchhiker's Guide to the Galaxy" + }, + { + title: 'The Great Gatsby' + }, + { title: 'Dune' }, + { + title: 'Crime and Punishment' + }, + { + title: 'One Hundred Years of Solitude' + }, + { title: '1984' }, + { + title: 'To Kill a Mockingbird' + }, + { + title: 'The Lord of the Rings' + }, + { title: 'Pride and Prejudice' }, + { + title: "The Handmaid's Tale" + } + ); + }); + }); + + describe('where stage', () => { + it('where with and (2 conditions)', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where( + and( + gt('rating', 4.5), + eqAny('genre', ['Science Fiction', 'Romance', 'Fantasy']) + ) + ) + ); + expectResults(snapshot, 'book10', 'book4'); + }); + it('where with and (3 conditions)', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where( + and( + gt('rating', 4.5), + eqAny('genre', ['Science Fiction', 'Romance', 'Fantasy']), + lt('published', 1965) + ) + ) + ); + expectResults(snapshot, 'book4'); + }); + it('where with or', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where( + or( + eq('genre', 'Romance'), + eq('genre', 'Dystopian'), + eq('genre', 'Fantasy') + ) + ) + .select('title') + ); + expectResults( + snapshot, + { title: 'Pride and Prejudice' }, + { title: 'The Lord of the Rings' }, + { title: "The Handmaid's Tale" }, + { title: '1984' } + ); + }); + + it('where with xor', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where( + xor( + eq('genre', 'Romance'), + eq('genre', 'Dystopian'), + eq('genre', 'Fantasy'), + eq('published', 1949) + ) + ) + .select('title') + ); + expectResults( + snapshot, + { title: 'Pride and Prejudice' }, + { title: 'The Lord of the Rings' }, + { title: "The Handmaid's Tale" } + ); + }); + }); + + describe('sort, offset, and limit stages', () => { + it('supports sort, offset, and limits', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('author').ascending()) + .offset(5) + .limit(3) + .select('title', 'author') + ); + expectResults( + snapshot, + { title: '1984', author: 'George Orwell' }, + { title: 'To Kill a Mockingbird', author: 'Harper Lee' }, + { title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' } + ); + }); + }); + + describe('generic stage', () => { + it('can select fields', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .genericStage('select', [ + { + title: field('title'), + metadata: { + 'author': field('author') + } + } + ]) + .sort(field('author').ascending()) + .limit(1) + ); + expectResults(snapshot, { + title: "The Hitchhiker's Guide to the Galaxy", + metadata: { + author: 'Douglas Adams' + } + }); + }); + + it('can add fields', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('author').ascending()) + .limit(1) + .select('title', 'author') + .genericStage('add_fields', [ + { + display: field('title').strConcat(' - ', field('author')) + } + ]) + ); + expectResults(snapshot, { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + display: "The Hitchhiker's Guide to the Galaxy - Douglas Adams" + }); + }); + + it('can filter with where', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .genericStage('where', [field('author').eq('Douglas Adams')]) + ); + expectResults(snapshot, { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams' + }); + }); + + it('can limit, offset, and sort', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author') + .genericStage('sort', [ + { + direction: 'ascending', + expression: field('author') + } + ]) + .genericStage('offset', [3]) + .genericStage('limit', [1]) + ); + expectResults(snapshot, { + author: 'Fyodor Dostoevsky', + title: 'Crime and Punishment' + }); + }); + + it('can perform aggregate query', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author', 'rating') + .genericStage('aggregate', [ + { averageRating: field('rating').avg() }, + {} + ]) + ); + expectResults(snapshot, { + averageRating: 4.3100000000000005 + }); + }); + + it('can perform distinct query', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'author', 'rating') + .genericStage('distinct', [{ rating: field('rating') }]) + .sort(field('rating').descending()) + ); + expectResults( + snapshot, + { + rating: 4.7 + }, + { + rating: 4.6 + }, + { + rating: 4.5 + }, + { + rating: 4.3 + }, + { + rating: 4.2 + }, + { + rating: 4.1 + }, + { + rating: 4.0 + } + ); + }); + }); + + describe('replace stage', () => { + it('run pipleine with replace', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) + .replaceWith('awards') + ); + expectResults(snapshot, { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }); + }); + }); + + describe('sample stage', () => { + it('run pipeline with sample limit of 3', async () => { + const snapshot = await execute( + firestore.pipeline().collection(randomCol.path).sample(3) + ); + expect(snapshot.results.length).to.equal(3); + }); + + it('run pipeline with sample limit of {documents: 3}', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sample({ documents: 3 }) + ); + expect(snapshot.results.length).to.equal(3); + }); + + it('run pipeline with sample limit of {percentage: 0.6}', async () => { + let avgSize = 0; + const numIterations = 20; + for (let i = 0; i < numIterations; i++) { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sample({ percentage: 0.6 }) + ); + + avgSize += snapshot.results.length; + } + avgSize /= numIterations; + expect(avgSize).to.be.closeTo(6, 1); + }); + }); + + describe('union stage', () => { + it('run pipeline with union', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .union(firestore.pipeline().collection(randomCol.path)) + .sort(field(documentIdFieldPath()).ascending()) + ); + expectResults( + snapshot, + 'book1', + 'book1', + 'book10', + 'book10', + 'book2', + 'book2', + 'book3', + 'book3', + 'book4', + 'book4', + 'book5', + 'book5', + 'book6', + 'book6', + 'book7', + 'book7', + 'book8', + 'book8', + 'book9', + 'book9' + ); + }); + }); + + describe('unnest stage', () => { + it('run pipeline with unnest', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) + .unnest(field('tags').as('tag')) + .select( + 'title', + 'author', + 'genre', + 'published', + 'rating', + 'tags', + 'tag', + 'awards', + 'nestedField' + ) + ); + expectResults( + snapshot, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + tag: 'comedy', + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + }, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + tag: 'space', + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + }, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + tag: 'adventure', + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + } + ); + }); + it('unnest an expr', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) + .unnest(array([1, 2, 3]).as('copy')) + .select( + 'title', + 'author', + 'genre', + 'published', + 'rating', + 'tags', + 'copy', + 'awards', + 'nestedField' + ) + ); + expectResults( + snapshot, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + copy: 1, + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + }, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + copy: 2, + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + }, + { + title: "The Hitchhiker's Guide to the Galaxy", + author: 'Douglas Adams', + genre: 'Science Fiction', + published: 1979, + rating: 4.2, + tags: ['comedy', 'space', 'adventure'], + copy: 3, + awards: { + hugo: true, + nebula: false, + others: { unknown: { year: 1980 } } + }, + nestedField: { 'level.1': { 'level.2': true } } + } + ); + }); + }); + + describe('findNearest stage', () => { + it('run pipeline with findNearest', async () => { + const measures: Array = [ + 'euclidean', + 'dot_product', + 'cosine' + ]; + for (const measure of measures) { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol) + .findNearest({ + field: 'embedding', + vectorValue: vector([10, 1, 3, 1, 2, 1, 1, 1, 1, 1]), + limit: 3, + distanceMeasure: measure + }) + .select('title') + ); + expectResults( + snapshot, + { + title: "The Hitchhiker's Guide to the Galaxy" + }, + { + title: 'One Hundred Years of Solitude' + }, + { + title: "The Handmaid's Tale" + } + ); + } + }); + + it('optionally returns the computed distance', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol) + .findNearest({ + field: 'embedding', + vectorValue: vector([10, 1, 2, 1, 1, 1, 1, 1, 1, 1]), + limit: 2, + distanceMeasure: 'euclidean', + distanceField: 'computedDistance' + }) + .select('title', 'computedDistance') + ); + expectResults( + snapshot, + { + title: "The Hitchhiker's Guide to the Galaxy", + computedDistance: 1 + }, + { + title: 'One Hundred Years of Solitude', + computedDistance: 12.041594578792296 + } + ); + }); + }); + }); + + describe('function expressions', () => { + it('logical max works', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select( + 'title', + logicalMaximum(constant(1960), field('published'), 1961).as( + 'published-safe' + ) + ) + .sort(field('title').ascending()) + .limit(3) + ); + expectResults( + snapshot, + { title: '1984', 'published-safe': 1961 }, + { title: 'Crime and Punishment', 'published-safe': 1961 }, + { title: 'Dune', 'published-safe': 1965 } + ); + }); + + it('logical min works', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select( + 'title', + logicalMinimum(constant(1960), field('published'), 1961).as( + 'published-safe' + ) + ) + .sort(field('title').ascending()) + .limit(3) + ); + expectResults( + snapshot, + { title: '1984', 'published-safe': 1949 }, + { title: 'Crime and Punishment', 'published-safe': 1866 }, + { title: 'Dune', 'published-safe': 1960 } + ); + }); + + it('cond works', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select( + 'title', + cond( + lt(field('published'), 1960), + constant(1960), + field('published') + ).as('published-safe') + ) + .sort(field('title').ascending()) + .limit(3) + ); + expectResults( + snapshot, + { title: '1984', 'published-safe': 1960 }, + { title: 'Crime and Punishment', 'published-safe': 1960 }, + { title: 'Dune', 'published-safe': 1965 } + ); + }); + + it('eqAny works', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eqAny('published', [1979, 1999, 1967])) + .select('title') + ); + expectResults( + snapshot, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'One Hundred Years of Solitude' } + ); + }); + + it('notEqAny works', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where( + notEqAny( + 'published', + [1965, 1925, 1949, 1960, 1866, 1985, 1954, 1967, 1979] + ) + ) + .select('title') + ); + expectResults(snapshot, { title: 'Pride and Prejudice' }); + }); + + it('arrayContains works', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(arrayContains('tags', 'comedy')) + .select('title') + ); + expectResults(snapshot, { + title: "The Hitchhiker's Guide to the Galaxy" + }); + }); + + it('arrayContainsAny works', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(arrayContainsAny('tags', ['comedy', 'classic'])) + .select('title') + ); + expectResults( + snapshot, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'Pride and Prejudice' } + ); + }); + + it('arrayContainsAll works', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(field('tags').arrayContainsAll(['adventure', 'magic'])) + .select('title') + ); + expectResults(snapshot, { title: 'The Lord of the Rings' }); + }); + + it('arrayLength works', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select(field('tags').arrayLength().as('tagsCount')) + .where(eq('tagsCount', 3)) + ); + expect(snapshot.results.length).to.equal(10); + }); + + it('testStrConcat', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select( + field('author').strConcat(' - ', field('title')).as('bookInfo') + ) + .limit(1) + ); + expectResults(snapshot, { + bookInfo: "Douglas Adams - The Hitchhiker's Guide to the Galaxy" + }); + }); + + it('testStartsWith', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(startsWith('title', 'The')) + .select('title') + .sort(field('title').ascending()) + ); + expectResults( + snapshot, + { title: 'The Great Gatsby' }, + { title: "The Handmaid's Tale" }, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'The Lord of the Rings' } + ); + }); + + it('testEndsWith', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(endsWith('title', 'y')) + .select('title') + .sort(field('title').descending()) + ); + expectResults( + snapshot, + { title: "The Hitchhiker's Guide to the Galaxy" }, + { title: 'The Great Gatsby' } + ); + }); + + it('testStrContains', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(strContains('title', "'s")) + .select('title') + .sort(field('title').ascending()) + ); + expectResults( + snapshot, + { title: "The Handmaid's Tale" }, + { title: "The Hitchhiker's Guide to the Galaxy" } + ); + }); + + it('testLength', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select(field('title').charLength().as('titleLength'), field('title')) + .where(gt('titleLength', 20)) + .sort(field('title').ascending()) + ); + + expectResults( + snapshot, + + { + titleLength: 29, + title: 'One Hundred Years of Solitude' + }, + { + titleLength: 36, + title: "The Hitchhiker's Guide to the Galaxy" + }, + { + titleLength: 21, + title: 'The Lord of the Rings' + }, + { + titleLength: 21, + title: 'To Kill a Mockingbird' + } + ); + }); + + it('testLike', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(like('title', '%Guide%')) + .select('title') + ); + expectResults(snapshot, { + title: "The Hitchhiker's Guide to the Galaxy" + }); + }); + + it('testRegexContains', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(regexContains('title', '(?i)(the|of)')) + ); + expect(snapshot.results.length).to.equal(5); + }); + + it('testRegexMatches', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(regexMatch('title', '.*(?i)(the|of).*')) + ); + expect(snapshot.results.length).to.equal(5); + }); + + it('testArithmeticOperations', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select( + add(field('rating'), 1).as('ratingPlusOne'), + subtract(field('published'), 1900).as('yearsSince1900'), + field('rating').multiply(10).as('ratingTimesTen'), + field('rating').divide(2).as('ratingDividedByTwo'), + multiply('rating', 10, 2).as('ratingTimes20'), + add('rating', 1, 2).as('ratingPlus3'), + mod('rating', 2).as('ratingMod2') + ) + .limit(1) + ); + expectResults(snapshot, { + ratingPlusOne: 5.2, + yearsSince1900: 79, + ratingTimesTen: 42, + ratingDividedByTwo: 2.1, + ratingTimes20: 84, + ratingPlus3: 7.2, + ratingMod2: 0.2 + }); + }); + + it('testComparisonOperators', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where( + and( + gt('rating', 4.2), + lte(field('rating'), 4.5), + neq('genre', 'Science Fiction') + ) + ) + .select('rating', 'title') + .sort(field('title').ascending()) + ); + expectResults( + snapshot, + { rating: 4.3, title: 'Crime and Punishment' }, + { + rating: 4.3, + title: 'One Hundred Years of Solitude' + }, + { rating: 4.5, title: 'Pride and Prejudice' } + ); + }); + + it('testLogicalOperators', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where( + or( + and(gt('rating', 4.5), eq('genre', 'Science Fiction')), + lt('published', 1900) + ) + ) + .select('title') + .sort(field('title').ascending()) + ); + expectResults( + snapshot, + { title: 'Crime and Punishment' }, + { title: 'Dune' }, + { title: 'Pride and Prejudice' } + ); + }); + + it('testChecks', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + isNull('rating').as('ratingIsNull'), + isNan('rating').as('ratingIsNaN'), + isError(arrayOffset('title', 0)).as('isError'), + ifError(arrayOffset('title', 0), constant('was error')).as( + 'ifError' + ), + isAbsent('foo').as('isAbsent'), + isNotNull('title').as('titleIsNotNull'), + isNotNan('cost').as('costIsNotNan'), + exists('fooBarBaz').as('fooBarBazExists'), + field('title').as('titleExists') + ) + ); + expectResults(snapshot, { + ratingIsNull: false, + ratingIsNaN: false, + isError: true, + ifError: 'was error', + isAbsent: true, + titleIsNotNull: true, + costIsNotNan: false, + fooBarBazExists: false, + titleExists: true + }); + + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + field('rating').isNull().as('ratingIsNull'), + field('rating').isNan().as('ratingIsNaN'), + arrayOffset('title', 0).isError().as('isError'), + arrayOffset('title', 0) + .ifError(constant('was error')) + .as('ifError'), + field('foo').isAbsent().as('isAbsent'), + field('title').isNotNull().as('titleIsNotNull'), + field('cost').isNotNan().as('costIsNotNan') + ) + ); + expectResults(snapshot, { + ratingIsNull: false, + ratingIsNaN: false, + isError: true, + ifError: 'was error', + isAbsent: true, + titleIsNotNull: true, + costIsNotNan: false + }); + }); + + it('testMapGet', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('published').descending()) + .select( + field('awards').mapGet('hugo').as('hugoAward'), + field('awards').mapGet('others').as('others'), + field('title') + ) + .where(eq('hugoAward', true)) + ); + expectResults( + snapshot, + { + hugoAward: true, + title: "The Hitchhiker's Guide to the Galaxy", + others: { unknown: { year: 1980 } } + }, + { hugoAward: true, title: 'Dune', others: null } + ); + }); + + it('testDistanceFunctions', async () => { + const sourceVector = [0.1, 0.1]; + const targetVector = [0.5, 0.8]; + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select( + cosineDistance(constantVector(sourceVector), targetVector).as( + 'cosineDistance' + ), + dotProduct(constantVector(sourceVector), targetVector).as( + 'dotProductDistance' + ), + euclideanDistance(constantVector(sourceVector), targetVector).as( + 'euclideanDistance' + ), + manhattanDistance(constantVector(sourceVector), targetVector).as( + 'manhattanDistance' + ) + ) + .limit(1) + ); + + expectResults(snapshot, { + cosineDistance: 0.02560880430538015, + dotProductDistance: 0.13, + euclideanDistance: 0.806225774829855, + manhattanDistance: 1.1 + }); + + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select( + constantVector(sourceVector) + .cosineDistance(targetVector) + .as('cosineDistance'), + constantVector(sourceVector) + .dotProduct(targetVector) + .as('dotProductDistance'), + constantVector(sourceVector) + .euclideanDistance(targetVector) + .as('euclideanDistance'), + constantVector(sourceVector) + .manhattanDistance(targetVector) + .as('manhattanDistance') + ) + .limit(1) + ); + + expectResults(snapshot, { + cosineDistance: 0.02560880430538015, + dotProductDistance: 0.13, + euclideanDistance: 0.806225774829855, + manhattanDistance: 1.1 + }); + }); + + it('testVectorLength', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(vectorLength(constantVector([1, 2, 3])).as('vectorLength')) + ); + expectResults(snapshot, { + vectorLength: 3 + }); + }); + + it('testNestedFields', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eq('awards.hugo', true)) + .select('title', 'awards.hugo') + ); + expectResults( + snapshot, + { + title: "The Hitchhiker's Guide to the Galaxy", + 'awards.hugo': true + }, + { title: 'Dune', 'awards.hugo': true } + ); + }); + + it('test mapGet with field name including . notation', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eq('awards.hugo', true)) + .select( + 'title', + field('nestedField.level.1'), + mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') + ) + ); + expectResults( + snapshot, + { + title: "The Hitchhiker's Guide to the Galaxy", + 'nestedField.level.`1`': null, + nested: true + }, + { title: 'Dune', 'nestedField.level.`1`': null, nested: null } + ); + }); + + describe('genericFunction', () => { + it('add selectable', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(descending('rating')) + .limit(1) + .select( + new FunctionExpr('add', [field('rating'), constant(1)]).as( + 'rating' + ) + ) + ); + expectResults(snapshot, { + rating: 5.7 + }); + }); + + it('and (variadic) selectable', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where( + new BooleanExpr('and', [ + field('rating').gt(0), + field('title').charLength().lt(5), + field('tags').arrayContains('propaganda') + ]) + ) + .select('title') + ); + expectResults(snapshot, { + title: '1984' + }); + }); + + it('array contains any', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where( + new BooleanExpr('array_contains_any', [ + field('tags'), + array(['politics']) + ]) + ) + .select('title') + ); + expectResults(snapshot, { + title: 'Dune' + }); + }); + + it('countif aggregate', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .aggregate( + new AggregateFunction('count_if', [field('rating').gte(4.5)]).as( + 'countOfBest' + ) + ) + ); + expectResults(snapshot, { + countOfBest: 3 + }); + }); + + it('sort by char_len', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort( + new FunctionExpr('char_length', [field('title')]).ascending(), + descending('__name__') + ) + .limit(3) + .select('title') + ); + expectResults( + snapshot, + { + title: '1984' + }, + { + title: 'Dune' + }, + { + title: 'The Great Gatsby' + } + ); + }); + }); + + describe('not implemented in backend', () => { + it('supports Bit_and', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(bitAnd(constant(5), 12).as('result')) + ); + expectResults(snapshot, { + result: 4 + }); + }); + + it('supports Bit_and', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constant(5).bitAnd(12).as('result')) + ); + expectResults(snapshot, { + result: 4 + }); + }); + + it('supports Bit_or', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(bitOr(constant(5), 12).as('result')) + ); + expectResults(snapshot, { + result: 13 + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constant(5).bitOr(12).as('result')) + ); + expectResults(snapshot, { + result: 13 + }); + }); + + it('supports Bit_xor', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(bitXor(constant(5), 12).as('result')) + ); + expectResults(snapshot, { + result: 9 + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constant(5).bitXor(12).as('result')) + ); + expectResults(snapshot, { + result: 9 + }); + }); + + it('supports Bit_not', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + bitNot(constant(Bytes.fromUint8Array(Uint8Array.of(0xfd)))).as( + 'result' + ) + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x02)) + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + constant(Bytes.fromUint8Array(Uint8Array.of(0xfd))) + .bitNot() + .as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x02)) + }); + }); + + it('supports Bit_left_shift', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + bitLeftShift( + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x04)) + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) + .bitLeftShift(2) + .as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x04)) + }); + }); + + it('supports Bit_right_shift', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + bitRightShift( + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x01)) + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) + .bitRightShift(2) + .as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x01)) + }); + }); + + it('supports Document_id', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(documentId(field('__path__')).as('docId')) + ); + expectResults(snapshot, { + docId: 'book4' + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('__path__').documentId().as('docId')) + ); + expectResults(snapshot, { + docId: 'book4' + }); + }); + + it('supports Substr', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(substr('title', 9, 2).as('of')) + ); + expectResults(snapshot, { + of: 'of' + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('title').substr(9, 2).as('of')) + ); + expectResults(snapshot, { + of: 'of' + }); + }); + + it('supports Substr without length', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(substr('title', 9).as('of')) + ); + expectResults(snapshot, { + of: 'of the Rings' + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('title').substr(9).as('of')) + ); + expectResults(snapshot, { + of: 'of the Rings' + }); + }); + + it('arrayConcat works', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select( + arrayConcat('tags', ['newTag1', 'newTag2'], field('tags'), [ + null + ]).as('modifiedTags') + ) + .limit(1) + ); + expectResults(snapshot, { + modifiedTags: [ + 'comedy', + 'space', + 'adventure', + 'newTag1', + 'newTag2', + 'comedy', + 'space', + 'adventure', + null + ] + }); + }); + + it('testToLowercase', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select(field('title').toLower().as('lowercaseTitle')) + .limit(1) + ); + expectResults(snapshot, { + lowercaseTitle: "the hitchhiker's guide to the galaxy" + }); + }); + + it('testToUppercase', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select(field('author').toUpper().as('uppercaseAuthor')) + .limit(1) + ); + expectResults(snapshot, { uppercaseAuthor: 'DOUGLAS ADAMS' }); + }); + + it('testTrim', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .addFields( + constant(" The Hitchhiker's Guide to the Galaxy ").as( + 'spacedTitle' + ) + ) + .select( + field('spacedTitle').trim().as('trimmedTitle'), + field('spacedTitle') + ) + .limit(1) + ); + expectResults(snapshot, { + spacedTitle: " The Hitchhiker's Guide to the Galaxy ", + trimmedTitle: "The Hitchhiker's Guide to the Galaxy" + }); + }); + + it('test reverse', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eq('title', '1984')) + .limit(1) + .select(reverse('title').as('reverseTitle')) + ); + expectResults(snapshot, { title: '4891' }); + }); + }); + + it('supports Rand', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(10) + .select(rand().as('result')) + ); + expect(snapshot.results.length).to.equal(10); + snapshot.results.forEach(d => { + expect(d.get('result')).to.be.lt(1); + expect(d.get('result')).to.be.gte(0); + }); + }); + + it('supports array', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(array([1, 2, 3, 4]).as('metadata')) + ); + expect(snapshot.results.length).to.equal(1); + expectResults(snapshot, { + metadata: [1, 2, 3, 4] + }); + }); + + it('evaluates expression in array', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + array([1, 2, field('genre'), multiply('rating', 10)]).as('metadata') + ) + ); + expect(snapshot.results.length).to.equal(1); + expectResults(snapshot, { + metadata: [1, 2, 'Fantasy', 47] + }); + }); + + it('supports arrayOffset', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(arrayOffset('tags', 0).as('firstTag')) + ); + const expectedResults = [ + { + firstTag: 'adventure' + }, + { + firstTag: 'politics' + }, + { + firstTag: 'classic' + } + ]; + expectResults(snapshot, ...expectedResults); + + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(field('tags').arrayOffset(0).as('firstTag')) + ); + expectResults(snapshot, ...expectedResults); + }); + + // TODO: current_context tests with are failing because of b/395937453 + it('supports currentContext', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(currentContext().as('currentContext')) + ); + expectResults(snapshot, { + currentContext: 'TODO' + }); + }); + + it('supports map', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + map({ + foo: 'bar' + }).as('metadata') + ) + ); + + expect(snapshot.results.length).to.equal(1); + expectResults(snapshot, { + metadata: { + foo: 'bar' + } + }); + }); + + it('evaluates expression in map', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + map({ + genre: field('genre'), + rating: field('rating').multiply(10) + }).as('metadata') + ) + ); + + expect(snapshot.results.length).to.equal(1); + expectResults(snapshot, { + metadata: { + genre: 'Fantasy', + rating: 47 + } + }); + }); + + it('supports mapRemove', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(mapRemove('awards', 'hugo').as('awards')) + ); + expectResults(snapshot, { + awards: { nebula: false } + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('awards').mapRemove('hugo').as('awards')) + ); + expectResults(snapshot, { + awards: { nebula: false } + }); + }); + + it('supports mapMerge', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(mapMerge('awards', { fakeAward: true }).as('awards')) + ); + expectResults(snapshot, { + awards: { nebula: false, hugo: false, fakeAward: true } + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('awards').mapMerge({ fakeAward: true }).as('awards')) + ); + expectResults(snapshot, { + awards: { nebula: false, hugo: false, fakeAward: true } + }); + }); + + it('supports timestamp conversions', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + unixSecondsToTimestamp(constant(1741380235)).as( + 'unixSecondsToTimestamp' + ), + unixMillisToTimestamp(constant(1741380235123)).as( + 'unixMillisToTimestamp' + ), + unixMicrosToTimestamp(constant(1741380235123456)).as( + 'unixMicrosToTimestamp' + ), + timestampToUnixSeconds( + constant(new Timestamp(1741380235, 123456789)) + ).as('timestampToUnixSeconds'), + timestampToUnixMicros( + constant(new Timestamp(1741380235, 123456789)) + ).as('timestampToUnixMicros'), + timestampToUnixMillis( + constant(new Timestamp(1741380235, 123456789)) + ).as('timestampToUnixMillis') + ) + ); + expectResults(snapshot, { + unixMicrosToTimestamp: new Timestamp(1741380235, 123456000), + unixMillisToTimestamp: new Timestamp(1741380235, 123000000), + unixSecondsToTimestamp: new Timestamp(1741380235, 0), + timestampToUnixSeconds: 1741380235, + timestampToUnixMicros: 1741380235123456, + timestampToUnixMillis: 1741380235123 + }); + }); + + it('supports timestamp math', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constant(new Timestamp(1741380235, 0)).as('timestamp')) + .select( + timestampAdd('timestamp', 'day', 10).as('plus10days'), + timestampAdd('timestamp', 'hour', 10).as('plus10hours'), + timestampAdd('timestamp', 'minute', 10).as('plus10minutes'), + timestampAdd('timestamp', 'second', 10).as('plus10seconds'), + timestampAdd('timestamp', 'microsecond', 10).as('plus10micros'), + timestampAdd('timestamp', 'millisecond', 10).as('plus10millis'), + timestampSub('timestamp', 'day', 10).as('minus10days'), + timestampSub('timestamp', 'hour', 10).as('minus10hours'), + timestampSub('timestamp', 'minute', 10).as('minus10minutes'), + timestampSub('timestamp', 'second', 10).as('minus10seconds'), + timestampSub('timestamp', 'microsecond', 10).as('minus10micros'), + timestampSub('timestamp', 'millisecond', 10).as('minus10millis') + ) + ); + expectResults(snapshot, { + plus10days: new Timestamp(1742244235, 0), + plus10hours: new Timestamp(1741416235, 0), + plus10minutes: new Timestamp(1741380835, 0), + plus10seconds: new Timestamp(1741380245, 0), + plus10micros: new Timestamp(1741380235, 10000), + plus10millis: new Timestamp(1741380235, 10000000), + minus10days: new Timestamp(1740516235, 0), + minus10hours: new Timestamp(1741344235, 0), + minus10minutes: new Timestamp(1741379635, 0), + minus10seconds: new Timestamp(1741380225, 0), + minus10micros: new Timestamp(1741380234, 999990000), + minus10millis: new Timestamp(1741380234, 990000000) + }); + }); + }); + + describe('pagination', () => { + /** + * Adds several books to the test collection. These + * additional books support pagination test scenarios + * that would otherwise not be possible with the original + * set of books. + * @param collectionReference + */ + async function addBooks( + collectionReference: CollectionReference + ): Promise { + await setDoc(doc(collectionReference, 'book11'), { + title: 'Jonathan Strange & Mr Norrell', + author: 'Susanna Clarke', + genre: 'Fantasy', + published: 2004, + rating: 4.6, + tags: ['historical fantasy', 'magic', 'alternate history', 'england'], + awards: { hugo: false, nebula: false } + }); + await setDoc(doc(collectionReference, 'book12'), { + title: 'The Master and Margarita', + author: 'Mikhail Bulgakov', + genre: 'Satire', + published: 1967, // Though written much earlier + rating: 4.6, + tags: [ + 'russian literature', + 'supernatural', + 'philosophy', + 'dark comedy' + ], + awards: {} + }); + await setDoc(doc(collectionReference, 'book13'), { + title: 'A Long Way to a Small, Angry Planet', + author: 'Becky Chambers', + genre: 'Science Fiction', + published: 2014, + rating: 4.6, + tags: ['space opera', 'found family', 'character-driven', 'optimistic'], + awards: { hugo: false, nebula: false, kitschies: true } + }); + } + + it('supports pagination with filters', async () => { + await addBooks(randomCol); + const pageSize = 2; + const pipeline = firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'rating', '__name__') + .sort(field('rating').descending(), field('__name__').ascending()); + + let snapshot = await execute(pipeline.limit(pageSize)); + expectResults( + snapshot, + { title: 'The Lord of the Rings', rating: 4.7 }, + { title: 'Jonathan Strange & Mr Norrell', rating: 4.6 } + ); + + const lastDoc = snapshot.results[snapshot.results.length - 1]; + + snapshot = await execute( + pipeline + .where( + or( + and( + field('rating').eq(lastDoc.get('rating')), + field('__path__').gt(lastDoc.ref?.id) + ), + field('rating').lt(lastDoc.get('rating')) + ) + ) + .limit(pageSize) + ); + expectResults( + snapshot, + { title: 'Pride and Prejudice', rating: 4.5 }, + { title: 'Crime and Punishment', rating: 4.3 } + ); + }); + + it('supports pagination with offsets', async () => { + await addBooks(randomCol); + + const secondFilterField = '__path__'; + + const pipeline = firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'rating', secondFilterField) + .sort( + field('rating').descending(), + field(secondFilterField).ascending() + ); + + const pageSize = 2; + let currPage = 0; + + let snapshot = await execute( + pipeline.offset(currPage++ * pageSize).limit(pageSize) + ); + + expectResults( + snapshot, + { + title: 'The Lord of the Rings', + rating: 4.7 + }, + { title: 'Dune', rating: 4.6 } + ); + + snapshot = await execute( + pipeline.offset(currPage++ * pageSize).limit(pageSize) + ); + expectResults( + snapshot, + { + title: 'Jonathan Strange & Mr Norrell', + rating: 4.6 + }, + { title: 'The Master and Margarita', rating: 4.6 } + ); + + snapshot = await execute( + pipeline.offset(currPage++ * pageSize).limit(pageSize) + ); + expectResults( + snapshot, + { + title: 'A Long Way to a Small, Angry Planet', + rating: 4.6 + }, + { + title: 'Pride and Prejudice', + rating: 4.5 + } + ); + }); + }); +}); From 68b8a76c2136452e2aa4f1a1af093d0ec342a098 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:40:07 -0600 Subject: [PATCH 67/75] Fixed a build issue with the lite SDK --- packages/firestore/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/firestore/package.json b/packages/firestore/package.json index 9f894de073e..02c93e54e65 100644 --- a/packages/firestore/package.json +++ b/packages/firestore/package.json @@ -50,7 +50,7 @@ "api-report:main": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore --packageRoot . --typescriptDts ./dist/firestore/src/index.d.ts --rollupDts ./dist/private.d.ts --untrimmedRollupDts ./dist/internal.d.ts --publicDts ./dist/index.d.ts", "api-report:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-pipelines --packageRoot . --typescriptDts ./dist/firestore/pipelines/pipelines.d.ts --rollupDts ./dist/private.pipelines.d.ts --untrimmedRollupDts ./dist/internal.pipelines.d.ts --publicDts ./dist/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", "api-report:lite": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite --packageRoot . --typescriptDts ./dist/firestore/lite/index.d.ts --rollupDts ./dist/lite/private.d.ts --untrimmedRollupDts ./dist/lite/internal.d.ts --publicDts ./dist/lite/index.d.ts", - "api-report:lite:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite-pipelines --packageRoot . --typescriptDts ./dist/firestore/lite/pipelines/pipelines.d.ts --rollupDts ./dist/lite/private.pipelines.d.ts --untrimmedRollupDts ./dist/lite/internal.pipelines.d.ts --publicDts ./dist/lite/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/index.d.ts", + "api-report:lite:pipelines": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package firestore-lite-pipelines --packageRoot . --typescriptDts ./dist/firestore/lite/pipelines/pipelines.d.ts --rollupDts ./dist/lite/private.pipelines.d.ts --untrimmedRollupDts ./dist/lite/internal.pipelines.d.ts --publicDts ./dist/lite/pipelines.d.ts --otherExportsPublicDtsFiles ./dist/lite/index.d.ts", "api-report:api-json": "rm -rf temp && api-extractor run --local --verbose", "api-report": "run-s --npm-path npm api-report:main api-report:pipelines api-report:lite api-report:lite:pipelines && yarn api-report:api-json", "doc": "api-documenter markdown --input temp --output docs", From 225edeb5092696ec5466703b09db7d220efde06c Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:42:41 -0600 Subject: [PATCH 68/75] Improved error message context when invalid user data is passed to a pipeline without being wrapped in a call to constant(...) --- packages/firestore/src/api/parse_context.ts | 45 +++++++ .../firestore/src/lite-api/expressions.ts | 121 ++++++++++++++---- .../src/lite-api/user_data_reader.ts | 43 ++----- packages/firestore/src/remote/serializer.ts | 3 +- 4 files changed, 154 insertions(+), 58 deletions(-) diff --git a/packages/firestore/src/api/parse_context.ts b/packages/firestore/src/api/parse_context.ts index ce3c221f66e..2381bcff4cd 100644 --- a/packages/firestore/src/api/parse_context.ts +++ b/packages/firestore/src/api/parse_context.ts @@ -16,8 +16,53 @@ */ import { DatabaseId } from '../core/database_info'; +import { UserDataSource } from '../lite-api/user_data_reader'; +import { DocumentKey } from '../model/document_key'; +import { FieldTransform } from '../model/mutation'; +import { FieldPath as InternalFieldPath } from '../model/path'; +import { JsonProtoSerializer } from '../remote/serializer'; +import { FirestoreError } from '../util/error'; + +/** Contains the settings that are mutated as we parse user data. */ +export interface ContextSettings { + /** Indicates what kind of API method this data came from. */ + readonly dataSource: UserDataSource; + /** The name of the method the user called to create the ParseContext. */ + readonly methodName: string; + /** The document the user is attempting to modify, if that applies. */ + readonly targetDoc?: DocumentKey; + /** + * A path within the object being parsed. This could be an empty path (in + * which case the context represents the root of the data being parsed), or a + * nonempty path (indicating the context represents a nested location within + * the data). + */ + readonly path?: InternalFieldPath; + /** + * Whether or not this context corresponds to an element of an array. + * If not set, elements are treated as if they were outside of arrays. + */ + readonly arrayElement?: boolean; + /** + * Whether or not a converter was specified in this context. If true, error + * messages will reference the converter when invalid data is provided. + */ + readonly hasConverter?: boolean; +} export interface ParseContext { + readonly settings: ContextSettings; readonly databaseId: DatabaseId; + readonly serializer: JsonProtoSerializer; readonly ignoreUndefinedProperties: boolean; + fieldTransforms: FieldTransform[]; + fieldMask: InternalFieldPath[]; + get path(): InternalFieldPath | undefined; + get dataSource(): UserDataSource; + contextWith(configuration: Partial): ParseContext; + childContextForField(field: string): ParseContext; + childContextForFieldPath(field: InternalFieldPath): ParseContext; + childContextForArray(index: number): ParseContext; + createError(reason: string): FirestoreError; + contains(fieldPath: InternalFieldPath): boolean; } diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 646d29714ff..8c97cc62a9a 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -15,6 +15,7 @@ * limitations under the License. */ +import { ParseContext } from '../api/parse_context'; import { DOCUMENT_KEY_NAME, FieldPath as InternalFieldPath @@ -67,15 +68,19 @@ export type ExprType = * @param value */ function valueToDefaultExpr(value: unknown): Expr { + let result: Expr | undefined; if (value instanceof Expr) { return value; } else if (isPlainObject(value)) { - return map(value as Record); + result = map(value as Record); } else if (value instanceof Array) { - return array(value); + result = array(value); } else { - return new Constant(value); + result = new Constant(value); } + + result._createdFromLiteral = true; + return result; } /** @@ -90,7 +95,9 @@ function vectorToExpr(value: VectorValue | number[] | Expr): Expr { if (value instanceof Expr) { return value; } else { - return constantVector(value); + const result = constantVector(value); + result._createdFromLiteral = true; + return result; } } @@ -106,7 +113,9 @@ function vectorToExpr(value: VectorValue | number[] | Expr): Expr { */ function fieldOfOrExpr(value: unknown): Expr { if (isString(value)) { - return field(value); + const result = field(value); + result._createdFromLiteral = true; + return result; } else { return valueToDefaultExpr(value); } @@ -131,6 +140,14 @@ function fieldOfOrExpr(value: unknown): Expr { export abstract class Expr implements ProtoValueSerializable, UserData { abstract readonly exprType: ExprType; + /** + * @internal + * @private + * Indicates if this expression was created from a literal value passed + * by the caller. + */ + _createdFromLiteral: boolean = false; + /** * @private * @internal @@ -142,7 +159,10 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @private * @internal */ - abstract _readUserData(dataReader: UserDataReader): void; + abstract _readUserData( + dataReader: UserDataReader, + context?: ParseContext + ): void; /** * Creates an expression that adds this expression to another expression. @@ -2027,6 +2047,14 @@ export interface Selectable { export class AggregateFunction implements ProtoValueSerializable, UserData { exprType: ExprType = 'AggregateFunction'; + /** + * @internal + * @private + * Indicates if this expression was created from a literal value passed + * by the caller. + */ + _createdFromLiteral: boolean = false; + constructor(private name: string, private params: Expr[]) {} /** @@ -2066,9 +2094,13 @@ export class AggregateFunction implements ProtoValueSerializable, UserData { * @private * @internal */ - _readUserData(dataReader: UserDataReader): void { + _readUserData(dataReader: UserDataReader, context?: ParseContext): void { + context = + this._createdFromLiteral && context + ? context + : dataReader.createContext(UserDataSource.Argument, this.name); this.params.forEach(expr => { - return expr._readUserData(dataReader); + return expr._readUserData(dataReader, context); }); } } @@ -2081,12 +2113,24 @@ export class AggregateFunction implements ProtoValueSerializable, UserData { export class AggregateWithAlias implements UserData { constructor(readonly aggregate: AggregateFunction, readonly alias: string) {} + /** + * @internal + * @private + * Indicates if this expression was created from a literal value passed + * by the caller. + */ + _createdFromLiteral: boolean = false; + /** * @private * @internal */ - _readUserData(dataReader: UserDataReader): void { - this.aggregate._readUserData(dataReader); + _readUserData(dataReader: UserDataReader, context?: ParseContext): void { + context = + this._createdFromLiteral && context + ? context + : dataReader.createContext(UserDataSource.Argument, 'as'); + this.aggregate._readUserData(dataReader, context); } } @@ -2097,14 +2141,26 @@ export class ExprWithAlias implements Selectable, UserData { exprType: ExprType = 'ExprWithAlias'; selectable = true as const; + /** + * @internal + * @private + * Indicates if this expression was created from a literal value passed + * by the caller. + */ + _createdFromLiteral: boolean = false; + constructor(readonly expr: Expr, readonly alias: string) {} /** * @private * @internal */ - _readUserData(dataReader: UserDataReader): void { - this.expr._readUserData(dataReader); + _readUserData(dataReader: UserDataReader, context?: ParseContext): void { + context = + this._createdFromLiteral && context + ? context + : dataReader.createContext(UserDataSource.Argument, 'as'); + this.expr._readUserData(dataReader, context); } } @@ -2288,11 +2344,11 @@ export class Constant extends Expr { * @private * @internal */ - _readUserData(dataReader: UserDataReader): void { - const context = dataReader.createContext( - UserDataSource.Argument, - 'constant' - ); + _readUserData(dataReader: UserDataReader, context?: ParseContext): void { + context = + this._createdFromLiteral && context + ? context + : dataReader.createContext(UserDataSource.Argument, 'constant'); if (isFirestoreValue(this._protoValue)) { return; @@ -2427,9 +2483,14 @@ export class MapValue extends Expr { exprType: ExprType = 'Constant'; - _readUserData(dataReader: UserDataReader): void { + _readUserData(dataReader: UserDataReader, context?: ParseContext): void { + context = + this._createdFromLiteral && context + ? context + : dataReader.createContext(UserDataSource.Argument, '_map'); + this.plainObject.forEach(expr => { - expr._readUserData(dataReader); + expr._readUserData(dataReader, context); }); } @@ -2471,9 +2532,13 @@ export class FunctionExpr extends Expr { * @private * @internal */ - _readUserData(dataReader: UserDataReader): void { + _readUserData(dataReader: UserDataReader, context?: ParseContext): void { + context = + this._createdFromLiteral && context + ? context + : dataReader.createContext(UserDataSource.Argument, this.name); this.params.forEach(expr => { - return expr._readUserData(dataReader); + return expr._readUserData(dataReader, context); }); } } @@ -6918,6 +6983,14 @@ export class Ordering implements ProtoValueSerializable, UserData { readonly direction: 'ascending' | 'descending' ) {} + /** + * @internal + * @private + * Indicates if this expression was created from a literal value passed + * by the caller. + */ + _createdFromLiteral: boolean = false; + /** * @private * @internal @@ -6937,7 +7010,11 @@ export class Ordering implements ProtoValueSerializable, UserData { * @private * @internal */ - _readUserData(dataReader: UserDataReader): void { + _readUserData(dataReader: UserDataReader, context?: ParseContext): void { + context = + this._createdFromLiteral && context + ? context + : dataReader.createContext(UserDataSource.Argument, 'constant'); this.expr._readUserData(dataReader); } diff --git a/packages/firestore/src/lite-api/user_data_reader.ts b/packages/firestore/src/lite-api/user_data_reader.ts index 733fa9050cd..e3e0deaa479 100644 --- a/packages/firestore/src/lite-api/user_data_reader.ts +++ b/packages/firestore/src/lite-api/user_data_reader.ts @@ -22,7 +22,7 @@ import { } from '@firebase/firestore-types'; import { Compat, deepEqual, getModularInstance } from '@firebase/util'; -import { ParseContext } from '../api/parse_context'; +import { ContextSettings, ParseContext } from '../api/parse_context'; import { DatabaseId } from '../core/database_info'; import { DocumentKey } from '../model/document_key'; import { FieldMask } from '../model/field_mask'; @@ -180,33 +180,6 @@ function isWrite(dataSource: UserDataSource): boolean { } } -/** Contains the settings that are mutated as we parse user data. */ -interface ContextSettings { - /** Indicates what kind of API method this data came from. */ - readonly dataSource: UserDataSource; - /** The name of the method the user called to create the ParseContext. */ - readonly methodName: string; - /** The document the user is attempting to modify, if that applies. */ - readonly targetDoc?: DocumentKey; - /** - * A path within the object being parsed. This could be an empty path (in - * which case the context represents the root of the data being parsed), or a - * nonempty path (indicating the context represents a nested location within - * the data). - */ - readonly path?: InternalFieldPath; - /** - * Whether or not this context corresponds to an element of an array. - * If not set, elements are treated as if they were outside of arrays. - */ - readonly arrayElement?: boolean; - /** - * Whether or not a converter was specified in this context. If true, error - * messages will reference the converter when invalid data is provided. - */ - readonly hasConverter?: boolean; -} - /** A "context" object passed around while parsing user data. */ class ParseContextImpl implements ParseContext { readonly fieldTransforms: FieldTransform[]; @@ -730,7 +703,7 @@ export function parseQueryValue( */ export function parseData( input: unknown, - context: ParseContextImpl + context: ParseContext ): ProtoValue | null { // Unwrap the API type from the Compat SDK. This will return the API type // from firestore-exp. @@ -781,7 +754,7 @@ export function parseData( function parseObject( obj: Dict, - context: ParseContextImpl + context: ParseContext ): { mapValue: ProtoMapValue } { const fields: Dict = {}; @@ -803,7 +776,7 @@ function parseObject( return { mapValue: { fields } }; } -function parseArray(array: unknown[], context: ParseContextImpl): ProtoValue { +function parseArray(array: unknown[], context: ParseContext): ProtoValue { const values: ProtoValue[] = []; let entryIndex = 0; for (const entry of array) { @@ -828,7 +801,7 @@ function parseArray(array: unknown[], context: ParseContextImpl): ProtoValue { */ function parseSentinelFieldValue( value: FieldValue, - context: ParseContextImpl + context: ParseContext ): void { // Sentinels are only supported with writes, and not within arrays. if (!isWrite(context.dataSource)) { @@ -855,7 +828,7 @@ function parseSentinelFieldValue( */ export function parseScalarValue( value: unknown, - context: ParseContextImpl + context: ParseContext ): ProtoValue | null { value = getModularInstance(value); @@ -924,7 +897,7 @@ export function parseScalarValue( */ export function parseVectorValue( value: VectorValue | number[], - context: ParseContextImpl + context: ParseContext ): { mapValue: ProtoMapValue } { const values = value instanceof VectorValue ? value.toArray() : value; const mapValue: ProtoMapValue = { @@ -976,7 +949,7 @@ export function looksLikeJsonObject(input: unknown): boolean { function validatePlainObject( message: string, - context: ParseContextImpl, + context: ParseContext, input: unknown ): asserts input is Dict { if (!looksLikeJsonObject(input) || !isPlainObject(input)) { diff --git a/packages/firestore/src/remote/serializer.ts b/packages/firestore/src/remote/serializer.ts index 45e771f1371..1ed2c7cd381 100644 --- a/packages/firestore/src/remote/serializer.ts +++ b/packages/firestore/src/remote/serializer.ts @@ -15,6 +15,7 @@ * limitations under the License. */ +import { ParseContext } from '../api/parse_context'; import { Aggregate } from '../core/aggregate'; import { Bound } from '../core/bound'; import { DatabaseId } from '../core/database_info'; @@ -1451,7 +1452,7 @@ export function isProtoValueSerializable( } export interface UserData { - _readUserData(dataReader: UserDataReader): void; + _readUserData(dataReader: UserDataReader, context?: ParseContext): void; } export function toMapValue( From 8f819f8d914bf2239c90ffd062318f9e05d892af Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:42:56 -0600 Subject: [PATCH 69/75] Fix typo in old error message --- packages/firestore/src/lite-api/reference.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/firestore/src/lite-api/reference.ts b/packages/firestore/src/lite-api/reference.ts index 26ae2fbd433..e9f5685e2b1 100644 --- a/packages/firestore/src/lite-api/reference.ts +++ b/packages/firestore/src/lite-api/reference.ts @@ -581,7 +581,7 @@ export function doc( ) { throw new FirestoreError( Code.INVALID_ARGUMENT, - 'Expected first argument to collection() to be a CollectionReference, ' + + 'Expected first argument to doc() to be a CollectionReference, ' + 'a DocumentReference or FirebaseFirestore' ); } From df746b409a6e94609132a7d339f926b8f62de9d2 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:43:26 -0600 Subject: [PATCH 70/75] Fix lite pipeline exports --- .../firestore/lite/pipelines/package.json | 2 +- .../firestore/lite/pipelines/pipelines.d.ts | 2 +- .../firestore/lite/pipelines/pipelines.ts | 29 +++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/packages/firestore/lite/pipelines/package.json b/packages/firestore/lite/pipelines/package.json index 349e25e3ac3..e7989c2ea97 100644 --- a/packages/firestore/lite/pipelines/package.json +++ b/packages/firestore/lite/pipelines/package.json @@ -6,7 +6,7 @@ "module": "../../dist/lite/pipelines.browser.esm2017.js", "browser": "../../dist/lite/pipelines.browser.esm2017.js", "react-native": "../../dist/lite/pipelines.rn.esm2017.js", - "typings": "../../dist/lite/pipelines.d.ts", + "typings": "./pipelines.d.ts", "private": true, "engines": { "node": ">=18.0.0" diff --git a/packages/firestore/lite/pipelines/pipelines.d.ts b/packages/firestore/lite/pipelines/pipelines.d.ts index e1243ebe907..81336456656 100644 --- a/packages/firestore/lite/pipelines/pipelines.d.ts +++ b/packages/firestore/lite/pipelines/pipelines.d.ts @@ -19,7 +19,7 @@ import { PipelineSource, Pipeline } from '../../dist/lite/pipelines'; // Augument the Firestore class with the pipeline() method. // This is stripped from dist/lite/pipelines.d.ts during the build // so it needs to be re-added here. -declare module '@firebase/firestore' { +declare module '@firebase/firestore/lite' { interface Firestore { pipeline(): PipelineSource; } diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index b8fca507e59..02c2748c308 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -79,16 +79,45 @@ export { } from '../../src/lite-api/stage'; export { + Expr, field, + and, + array, + arrayOffset, constant, add, subtract, multiply, + avg, + bitAnd, + substr, + constantVector, + bitLeftShift, + bitNot, + count, + mapMerge, + mapRemove, + bitOr, + ifError, + isAbsent, + isError, + or, + rand, + bitRightShift, + bitXor, divide, + isNotNan, + manhattanDistance, + map, + isNotNull, + isNull, mod, + documentId, eq, neq, lt, + countIf, + currentContext, lte, gt, gte, From 898ea703beb0537f3b7e646bdb47d9d0771277ea Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:50:08 -0600 Subject: [PATCH 71/75] api-review files --- .../firestore-lite-pipelines.api.md | 2147 ++++++----------- common/api-review/firestore-pipelines.api.md | 1435 ++++++----- common/api-review/firestore.api.md | 1343 +---------- 3 files changed, 1419 insertions(+), 3506 deletions(-) diff --git a/common/api-review/firestore-lite-pipelines.api.md b/common/api-review/firestore-lite-pipelines.api.md index d1536c8a626..28746295ae5 100644 --- a/common/api-review/firestore-lite-pipelines.api.md +++ b/common/api-review/firestore-lite-pipelines.api.md @@ -7,276 +7,204 @@ import { FirebaseApp } from '@firebase/app'; // @beta -export interface Accumulator { - // (undocumented) - accumulator: true; - add(other: Accumulator): Add; - add(other: any): Add; - arrayConcat(...arrays: Accumulator[]): ArrayConcat; - arrayConcat(...arrays: any[][]): ArrayConcat; - arrayContains(element: Accumulator): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Accumulator): CosineDistance; - // Warning: (ae-forgotten-export) The symbol "VectorValue" needs to be exported by the entry point pipelines.d.ts - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Accumulator): Divide; - divide(other: any): Divide; - dotProduct(other: Accumulator): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Accumulator): EndsWith; - eq(other: Accumulator): Eq; - eq(other: any): Eq; - eqAny(...others: Accumulator[]): EqAny; +export function add(first: Expr, second: Expr | unknown, ...others: Array): FunctionExpr; + +// @beta +export function add(fieldName: string, second: Expr | unknown, ...others: Array): FunctionExpr; + +// @beta (undocumented) +export class AddFields implements Stage { + constructor(fields: Map); // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Accumulator): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; + name: string; +} + +// @beta (undocumented) +export class Aggregate implements Stage { + constructor(accumulators: Map, groups: Map); // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; + name: string; +} + +// @beta +export class AggregateFunction { + constructor(name: string, params: Expr[]); + as(name: string): AggregateWithAlias; // (undocumented) exprType: ExprType; - gt(other: Accumulator): Gt; - gt(other: any): Gt; - gte(other: Accumulator): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; + } + +// @beta +export class AggregateWithAlias { + constructor(aggregate: AggregateFunction, alias: string); // (undocumented) - like(pattern: Accumulator): Like; - logicalMaximum(other: Accumulator): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Accumulator): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Accumulator): Lt; - lt(other: any): Lt; - lte(other: Accumulator): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Accumulator): Mod; - mod(other: any): Mod; - multiply(other: Accumulator): Multiply; - multiply(other: any): Multiply; - neq(other: Accumulator): Neq; - neq(other: any): Neq; - notEqAny(...others: Accumulator[]): FirestoreFunction; + readonly aggregate: AggregateFunction; // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Accumulator): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Accumulator): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; - reverse(): Reverse; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Accumulator): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Accumulator): StrContains; - subtract(other: Accumulator): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; + readonly alias: string; } // @beta -export type AccumulatorTarget = ExprWithAlias; +export function and(first: BooleanExpr, second: BooleanExpr, ...more: BooleanExpr[]): BooleanExpr; -// @beta (undocumented) -export class Add extends FirestoreFunction { - constructor(left: Accumulator, right: Accumulator); - } +// @beta +export function array(elements: unknown[]): FunctionExpr; // @beta -export function add(left: Accumulator, right: Accumulator): Add; +export function arrayConcat(firstArray: Expr, secondArray: Expr | unknown[], ...otherArrays: Array): FunctionExpr; // @beta -export function add(left: Accumulator, right: any): Add; +export function arrayConcat(firstArrayField: string, secondArray: Expr | unknown[], ...otherArrays: Array): FunctionExpr; // @beta -export function add(left: string, right: Accumulator): Add; +export function arrayContains(array: Expr, element: Expr): FunctionExpr; // @beta -export function add(left: string, right: any): Add; +export function arrayContains(array: Expr, element: unknown): FunctionExpr; -// @beta (undocumented) -export class AddFields implements Stage { - constructor(fields: Map); - // (undocumented) - name: string; -} +// @beta +export function arrayContains(fieldName: string, element: Expr): FunctionExpr; -// @beta (undocumented) -export class Aggregate implements Stage { - constructor(accumulators: Map, groups: Map); - // (undocumented) - name: string; -} +// @beta +export function arrayContains(fieldName: string, element: unknown): BooleanExpr; -// @beta (undocumented) -export class And extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterCondition[]); - // (undocumented) - filterable: true; -} +// @beta +export function arrayContainsAll(array: Expr, values: Array): BooleanExpr; -// @beta (undocumented) -export class ArrayConcat extends FirestoreFunction { - constructor(array: Accumulator, elements: Accumulator[]); - } +// @beta +export function arrayContainsAll(fieldName: string, values: Array): BooleanExpr; // @beta -export function arrayConcat(array: Accumulator, elements: Accumulator[]): ArrayConcat; +export function arrayContainsAll(array: Expr, arrayExpression: Expr): BooleanExpr; // @beta -export function arrayConcat(array: Accumulator, elements: any[]): ArrayConcat; +export function arrayContainsAll(fieldName: string, arrayExpression: Expr): BooleanExpr; // @beta -export function arrayConcat(array: string, elements: Accumulator[]): ArrayConcat; +export function arrayContainsAny(array: Expr, values: Array): BooleanExpr; // @beta -export function arrayConcat(array: string, elements: any[]): ArrayConcat; +export function arrayContainsAny(fieldName: string, values: Array): BooleanExpr; -// @beta (undocumented) -export class ArrayContains extends FirestoreFunction implements FilterCondition { - constructor(array: Accumulator, element: Accumulator); - // (undocumented) - filterable: true; -} +// @beta +export function arrayContainsAny(array: Expr, values: Expr): BooleanExpr; // @beta -export function arrayContains(array: Accumulator, element: Accumulator): ArrayContains; +export function arrayContainsAny(fieldName: string, values: Expr): BooleanExpr; // @beta -export function arrayContains(array: Accumulator, element: any): ArrayContains; +export function arrayLength(array: Expr): FunctionExpr; // @beta -export function arrayContains(array: string, element: Accumulator): ArrayContains; +export function arrayOffset(arrayField: string, offset: number): FunctionExpr; // @beta -export function arrayContains(array: string, element: any): ArrayContains; +export function arrayOffset(arrayField: string, offsetExpr: Expr): FunctionExpr; -// @beta (undocumented) -export class ArrayContainsAll extends FirestoreFunction implements FilterCondition { - constructor(array: Accumulator, values: Accumulator[]); - // (undocumented) - filterable: true; - } +// @beta +export function arrayOffset(arrayExpression: Expr, offset: number): FunctionExpr; // @beta -export function arrayContainsAll(array: Accumulator, values: Accumulator[]): ArrayContainsAll; +export function arrayOffset(arrayExpression: Expr, offsetExpr: Expr): FunctionExpr; // @beta -export function arrayContainsAll(array: Accumulator, values: any[]): ArrayContainsAll; +export function ascending(expr: Expr): Ordering; // @beta -export function arrayContainsAll(array: string, values: Accumulator[]): ArrayContainsAll; +export function ascending(fieldName: string): Ordering; // @beta -export function arrayContainsAll(array: string, values: any[]): ArrayContainsAll; +export function avg(expression: Expr): AggregateFunction; -// @beta (undocumented) -export class ArrayContainsAny extends FirestoreFunction implements FilterCondition { - constructor(array: Accumulator, values: Accumulator[]); - // (undocumented) - filterable: true; - } +// @beta +export function avg(fieldName: string): AggregateFunction; +// Warning: (ae-forgotten-export) The symbol "Bytes" needs to be exported by the entry point pipelines.d.ts +// // @beta -export function arrayContainsAny(array: Accumulator, values: Accumulator[]): ArrayContainsAny; +export function bitAnd(field: string, otherBits: number | Bytes): FunctionExpr; // @beta -export function arrayContainsAny(array: Accumulator, values: any[]): ArrayContainsAny; +export function bitAnd(field: string, bitsExpression: Expr): FunctionExpr; // @beta -export function arrayContainsAny(array: string, values: Accumulator[]): ArrayContainsAny; +export function bitAnd(bitsExpression: Expr, otherBits: number | Bytes): FunctionExpr; // @beta -export function arrayContainsAny(array: string, values: any[]): ArrayContainsAny; +export function bitAnd(bitsExpression: Expr, otherBitsExpression: Expr): FunctionExpr; -// @beta (undocumented) -export class ArrayElement extends FirestoreFunction { - constructor(); -} +// @beta +export function bitLeftShift(field: string, y: number): FunctionExpr; -// @beta (undocumented) -export class ArrayLength extends FirestoreFunction { - constructor(array: Accumulator); - } +// @beta +export function bitLeftShift(field: string, numberExpr: Expr): FunctionExpr; // @beta -export function arrayLength(array: Accumulator): ArrayLength; +export function bitLeftShift(xValue: Expr, y: number): FunctionExpr; -// @beta (undocumented) -export class ArrayReverse extends FirestoreFunction { - constructor(array: Accumulator); - } +// @beta +export function bitLeftShift(xValue: Expr, numberExpr: Expr): FunctionExpr; // @beta -export function ascending(expr: Accumulator): Ordering; +export function bitNot(field: string): FunctionExpr; -// @beta (undocumented) -export class Avg extends FirestoreFunction implements Accumulator { - constructor(value: Accumulator, distinct: boolean); - // (undocumented) - accumulator: true; - } +// @beta +export function bitNot(bitsValueExpression: Expr): FunctionExpr; -// @beta (undocumented) -export class ByteLength extends FirestoreFunction { - constructor(value: Accumulator); - } +// @beta +export function bitOr(field: string, otherBits: number | Bytes): FunctionExpr; // @beta -export function byteLength(expr: Accumulator): ByteLength; +export function bitOr(field: string, bitsExpression: Expr): FunctionExpr; // @beta -export function byteLength(field: string): ByteLength; +export function bitOr(bitsExpression: Expr, otherBits: number | Bytes): FunctionExpr; -// @beta (undocumented) -export class CharLength extends FirestoreFunction { - constructor(value: Accumulator); - } +// @beta +export function bitOr(bitsExpression: Expr, otherBitsExpression: Expr): FunctionExpr; + +// @beta +export function bitRightShift(field: string, y: number): FunctionExpr; + +// @beta +export function bitRightShift(field: string, numberExpr: Expr): FunctionExpr; + +// @beta +export function bitRightShift(xValue: Expr, y: number): FunctionExpr; + +// @beta +export function bitRightShift(xValue: Expr, numberExpr: Expr): FunctionExpr; + +// @beta +export function bitXor(field: string, otherBits: number | Bytes): FunctionExpr; // @beta -export function charLength(field: string): CharLength; +export function bitXor(field: string, bitsExpression: Expr): FunctionExpr; // @beta -export function charLength(expr: Accumulator): CharLength; +export function bitXor(bitsExpression: Expr, otherBits: number | Bytes): FunctionExpr; + +// @beta +export function bitXor(bitsExpression: Expr, otherBitsExpression: Expr): FunctionExpr; + +// @beta +export class BooleanExpr extends FunctionExpr { + countIf(): AggregateFunction; + // (undocumented) + filterable: true; + not(): BooleanExpr; +} + +// @beta +export function byteLength(expr: Expr): FunctionExpr; + +// @beta +export function byteLength(fieldName: string): FunctionExpr; + +// @beta +export function charLength(fieldName: string): FunctionExpr; + +// @beta +export function charLength(stringExpression: Expr): FunctionExpr; // @beta (undocumented) export class CollectionGroupSource implements Stage { @@ -292,169 +220,102 @@ export class CollectionSource implements Stage { name: string; } -// @beta (undocumented) -export class Cond extends FirestoreFunction { - constructor(condition: FilterCondition, thenExpr: Accumulator, elseExpr: Accumulator); - // (undocumented) - filterable: true; - } - // @beta -export function cond(condition: FilterCondition, thenExpr: Accumulator, elseExpr: Accumulator): Cond; +export function cond(condition: BooleanExpr, thenExpr: Expr, elseExpr: Expr): FunctionExpr; // @beta -export class Constant { - add(other: Accumulator): Add; - add(other: any): Add; - arrayConcat(...arrays: Accumulator[]): ArrayConcat; - arrayConcat(...arrays: any[][]): ArrayConcat; - arrayContains(element: Accumulator): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Accumulator): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Accumulator): Divide; - divide(other: any): Divide; - dotProduct(other: Accumulator): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Accumulator): EndsWith; - eq(other: Accumulator): Eq; - eq(other: any): Eq; - eqAny(...others: Accumulator[]): EqAny; +export class Constant extends Expr { // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Accumulator): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; - gt(other: Accumulator): Gt; - gt(other: any): Gt; - gte(other: Accumulator): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Accumulator): Like; - logicalMaximum(other: Accumulator): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Accumulator): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Accumulator): Lt; - lt(other: any): Lt; - lte(other: Accumulator): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Accumulator): Mod; - mod(other: any): Mod; - multiply(other: Accumulator): Multiply; - multiply(other: any): Multiply; - neq(other: Accumulator): Neq; - neq(other: any): Neq; - notEqAny(...others: Accumulator[]): FirestoreFunction; - // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - static of(value: number): Constant; - static of(value: string): Constant; - static of(value: boolean): Constant; - static of(value: null): Constant; - static of(value: undefined): Constant; - // Warning: (ae-forgotten-export) The symbol "GeoPoint" needs to be exported by the entry point pipelines.d.ts - static of(value: GeoPoint): Constant; - // Warning: (ae-forgotten-export) The symbol "Timestamp" needs to be exported by the entry point pipelines.d.ts - static of(value: Timestamp): Constant; - static of(value: Date): Constant; - static of(value: Uint8Array): Constant; - // Warning: (ae-forgotten-export) The symbol "DocumentReference" needs to be exported by the entry point pipelines.d.ts - static of(value: DocumentReference): Constant; - static of(value: any[]): Constant; - static of(value: Map): Constant; - static of(value: VectorValue): Constant; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Accumulator): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Accumulator): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; - reverse(): Reverse; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Accumulator): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Accumulator): StrContains; - subtract(other: Accumulator): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - static vector(value: number[] | VectorValue): Constant; - vectorLength(): VectorLength; -} - -// @beta (undocumented) -export class CosineDistance extends FirestoreFunction { - constructor(vector1: Accumulator, vector2: Accumulator); + readonly exprType: ExprType; } +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: number): Constant; + +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: string): Constant; + +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: boolean): Constant; + +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: null): Constant; + +// Warning: (ae-forgotten-export) The symbol "GeoPoint" needs to be exported by the entry point pipelines.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: GeoPoint): Constant; + +// Warning: (ae-forgotten-export) The symbol "Timestamp" needs to be exported by the entry point pipelines.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: Timestamp): Constant; + +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: Date): Constant; + +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: Bytes): Constant; + +// Warning: (ae-forgotten-export) The symbol "DocumentReference" needs to be exported by the entry point pipelines.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: DocumentReference): Constant; + +// Warning: (ae-forgotten-export) The symbol "VectorValue" needs to be exported by the entry point pipelines.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: VectorValue): Constant; + +// Warning: (ae-incompatible-release-tags) The symbol "constantVector" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constantVector(value: number[] | VectorValue): Constant; + // @beta -export function cosineDistance(expr: string, other: number[]): CosineDistance; +export function cosineDistance(fieldName: string, vector: number[] | VectorValue): FunctionExpr; // @beta -export function cosineDistance(expr: string, other: VectorValue): CosineDistance; +export function cosineDistance(fieldName: string, vectorExpression: Expr): FunctionExpr; // @beta -export function cosineDistance(expr: string, other: Accumulator): CosineDistance; +export function cosineDistance(vectorExpression: Expr, vector: number[] | Expr): FunctionExpr; // @beta -export function cosineDistance(expr: Accumulator, other: number[]): CosineDistance; +export function cosineDistance(vectorExpression: Expr, otherVectorExpression: Expr): FunctionExpr; // @beta -export function cosineDistance(expr: Accumulator, other: VectorValue): CosineDistance; +export function count(expression: Expr): AggregateFunction; + +// Warning: (ae-incompatible-release-tags) The symbol "count" is marked as @public, but its signature references "AggregateFunction" which is marked as @beta +// +// @public +export function count(fieldName: string): AggregateFunction; // @beta -export function cosineDistance(expr: Accumulator, other: Accumulator): CosineDistance; +export function countAll(): AggregateFunction; -// @beta (undocumented) -export class Count extends FirestoreFunction implements Accumulator { - constructor(value: Accumulator | undefined, distinct: boolean); - // (undocumented) - accumulator: true; - } +// @beta +export function countIf(booleanExpr: BooleanExpr): AggregateFunction; // @beta -export function countAll(): Count; +export function currentContext(): FunctionExpr; // @beta (undocumented) export class DatabaseSource implements Stage { @@ -463,31 +324,35 @@ export class DatabaseSource implements Stage { } // @beta -export function descending(expr: Accumulator): Ordering; +export function descending(expr: Expr): Ordering; + +// @beta +export function descending(fieldName: string): Ordering; // @beta (undocumented) export class Distinct implements Stage { - constructor(groups: Map); + constructor(groups: Map); // (undocumented) name: string; } -// @beta (undocumented) -export class Divide extends FirestoreFunction { - constructor(left: Accumulator, right: Accumulator); - } +// @beta +export function divide(left: Expr, right: Expr): FunctionExpr; + +// @beta +export function divide(expression: Expr, value: unknown): FunctionExpr; // @beta -export function divide(left: Accumulator, right: Accumulator): Divide; +export function divide(fieldName: string, expressions: Expr): FunctionExpr; // @beta -export function divide(left: Accumulator, right: any): Divide; +export function divide(fieldName: string, value: unknown): FunctionExpr; // @beta -export function divide(left: string, right: Accumulator): Divide; +export function documentId(documentPath: string | DocumentReference): FunctionExpr; // @beta -export function divide(left: string, right: any): Divide; +export function documentId(documentPathExpr: Expr): FunctionExpr; // @beta (undocumented) export class DocumentsSource implements Stage { @@ -495,574 +360,350 @@ export class DocumentsSource implements Stage { // (undocumented) name: string; // (undocumented) - static of(refs: DocumentReference[]): DocumentsSource; + static of(refs: Array): DocumentsSource; } -// @beta (undocumented) -export class DotProduct extends FirestoreFunction { - constructor(vector1: Accumulator, vector2: Accumulator); - } - // @beta -export function dotProduct(expr: string, other: number[]): DotProduct; +export function dotProduct(fieldName: string, vector: number[] | VectorValue): FunctionExpr; // @beta -export function dotProduct(expr: string, other: VectorValue): DotProduct; +export function dotProduct(fieldName: string, vectorExpression: Expr): FunctionExpr; // @beta -export function dotProduct(expr: string, other: Accumulator): DotProduct; +export function dotProduct(vectorExpression: Expr, vector: number[] | VectorValue): FunctionExpr; // @beta -export function dotProduct(expr: Accumulator, other: number[]): DotProduct; +export function dotProduct(vectorExpression: Expr, otherVectorExpression: Expr): FunctionExpr; // @beta -export function dotProduct(expr: Accumulator, other: VectorValue): DotProduct; +export function endsWith(fieldName: string, suffix: string): BooleanExpr; // @beta -export function dotProduct(expr: Accumulator, other: Accumulator): DotProduct; - -// @beta (undocumented) -export class EndsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Accumulator, suffix: Accumulator); - // (undocumented) - filterable: true; - } +export function endsWith(fieldName: string, suffix: Expr): BooleanExpr; // @beta -export function endsWith(expr: string, suffix: string): EndsWith; +export function endsWith(stringExpression: Expr, suffix: string): BooleanExpr; // @beta -export function endsWith(expr: string, suffix: Accumulator): EndsWith; +export function endsWith(stringExpression: Expr, suffix: Expr): BooleanExpr; // @beta -export function endsWith(expr: Accumulator, suffix: string): EndsWith; +export function eq(left: Expr, right: Expr): BooleanExpr; // @beta -export function endsWith(expr: Accumulator, suffix: Accumulator): EndsWith; - -// @beta (undocumented) -export class Eq extends FirestoreFunction implements FilterCondition { - constructor(left: Accumulator, right: Accumulator); - // (undocumented) - filterable: true; - } - -// @beta -export function eq(left: Accumulator, right: Accumulator): Eq; - -// @beta -export function eq(left: Accumulator, right: any): Eq; - -// @beta -export function eq(left: string, right: Accumulator): Eq; - -// @beta -export function eq(left: string, right: any): Eq; - -// @beta (undocumented) -export class EqAny extends FirestoreFunction implements FilterCondition { - constructor(left: Accumulator, others: Accumulator[]); - // (undocumented) - filterable: true; - } - -// @beta -export function eqAny(element: Accumulator, others: Accumulator[]): EqAny; +export function eq(expression: Expr, value: unknown): BooleanExpr; // @beta -export function eqAny(element: Accumulator, others: any[]): EqAny; +export function eq(fieldName: string, expression: Expr): BooleanExpr; // @beta -export function eqAny(element: string, others: Accumulator[]): EqAny; +export function eq(fieldName: string, value: unknown): BooleanExpr; // @beta -export function eqAny(element: string, others: any[]): EqAny; - -// @beta (undocumented) -export class EuclideanDistance extends FirestoreFunction { - constructor(vector1: Accumulator, vector2: Accumulator); - } +export function eqAny(expression: Expr, values: Array): BooleanExpr; // @beta -export function euclideanDistance(expr: string, other: number[]): EuclideanDistance; +export function eqAny(expression: Expr, arrayExpression: Expr): BooleanExpr; // @beta -export function euclideanDistance(expr: string, other: VectorValue): EuclideanDistance; +export function eqAny(fieldName: string, values: Array): BooleanExpr; // @beta -export function euclideanDistance(expr: string, other: Accumulator): EuclideanDistance; +export function eqAny(fieldName: string, arrayExpression: Expr): BooleanExpr; // @beta -export function euclideanDistance(expr: Accumulator, other: number[]): EuclideanDistance; +export function euclideanDistance(fieldName: string, vector: number[] | VectorValue): FunctionExpr; // @beta -export function euclideanDistance(expr: Accumulator, other: VectorValue): EuclideanDistance; +export function euclideanDistance(fieldName: string, vectorExpression: Expr): FunctionExpr; // @beta -export function euclideanDistance(expr: Accumulator, other: Accumulator): EuclideanDistance; +export function euclideanDistance(vectorExpression: Expr, vector: number[] | VectorValue): FunctionExpr; // @beta -export function execute(pipeline: Pipeline): Promise; +export function euclideanDistance(vectorExpression: Expr, otherVectorExpression: Expr): FunctionExpr; -// @beta (undocumented) -export class Exists extends FirestoreFunction implements FilterCondition { - constructor(expr: Accumulator); - // (undocumented) - filterable: true; +// @public +export function execute(pipeline: Pipeline): Promise; + +// @beta +export function exists(value: Expr): BooleanExpr; + +// @beta +export function exists(fieldName: string): BooleanExpr; + +// @beta +export abstract class Expr { + add(second: Expr | unknown, ...others: Array): FunctionExpr; + /* Excluded from this release type: _readUserData */ + arrayConcat(secondArray: Expr | unknown[], ...otherArrays: Array): FunctionExpr; + /* Excluded from this release type: _readUserData */ + arrayContains(expression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + arrayContains(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + arrayContainsAll(values: Array): BooleanExpr; + /* Excluded from this release type: _readUserData */ + arrayContainsAll(arrayExpression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + arrayContainsAny(values: Array): BooleanExpr; + /* Excluded from this release type: _readUserData */ + arrayContainsAny(arrayExpression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + arrayLength(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + arrayOffset(offset: number): FunctionExpr; + /* Excluded from this release type: _readUserData */ + arrayOffset(offsetExpr: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + as(name: string): ExprWithAlias; + /* Excluded from this release type: _readUserData */ + ascending(): Ordering; + /* Excluded from this release type: _readUserData */ + avg(): AggregateFunction; + /* Excluded from this release type: _readUserData */ + bitAnd(otherBits: number | Bytes): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitAnd(bitsExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitLeftShift(y: number): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitLeftShift(numberExpr: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitNot(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitOr(otherBits: number | Bytes): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitOr(bitsExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitRightShift(y: number): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitRightShift(numberExpr: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitXor(otherBits: number | Bytes): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitXor(bitsExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + byteLength(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + charLength(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + cosineDistance(vectorExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + cosineDistance(vector: VectorValue | number[]): FunctionExpr; + /* Excluded from this release type: _readUserData */ + count(): AggregateFunction; + /* Excluded from this release type: _readUserData */ + descending(): Ordering; + /* Excluded from this release type: _readUserData */ + divide(other: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + divide(other: unknown): FunctionExpr; + /* Excluded from this release type: _readUserData */ + documentId(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + dotProduct(vectorExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + dotProduct(vector: VectorValue | number[]): FunctionExpr; + /* Excluded from this release type: _readUserData */ + endsWith(suffix: string): BooleanExpr; + /* Excluded from this release type: _readUserData */ + endsWith(suffix: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + eq(expression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + eq(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + eqAny(values: Array): BooleanExpr; + /* Excluded from this release type: _readUserData */ + eqAny(arrayExpression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + euclideanDistance(vectorExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + euclideanDistance(vector: VectorValue | number[]): FunctionExpr; + /* Excluded from this release type: _readUserData */ + exists(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + // (undocumented) + abstract readonly exprType: ExprType; + /* Excluded from this release type: _readUserData */ + gt(expression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + gt(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + gte(expression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + gte(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + ifError(catchExpr: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + ifError(catchValue: unknown): FunctionExpr; + /* Excluded from this release type: _readUserData */ + isAbsent(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + isError(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + isNan(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + isNotNan(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + isNotNull(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + isNull(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + like(pattern: string): FunctionExpr; + /* Excluded from this release type: _readUserData */ + like(pattern: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + logicalMaximum(second: Expr | unknown, ...others: Array): FunctionExpr; + /* Excluded from this release type: _readUserData */ + logicalMinimum(second: Expr | unknown, ...others: Array): FunctionExpr; + /* Excluded from this release type: _readUserData */ + lt(experession: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + lt(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + lte(expression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + lte(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + manhattanDistance(vector: VectorValue | number[]): FunctionExpr; + /* Excluded from this release type: _readUserData */ + manhattanDistance(vectorExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + mapGet(subfield: string): FunctionExpr; + /* Excluded from this release type: _readUserData */ + mapMerge(secondMap: Record | Expr, ...otherMaps: Array | Expr>): FunctionExpr; + /* Excluded from this release type: _readUserData */ + mapRemove(key: string): FunctionExpr; + /* Excluded from this release type: _readUserData */ + mapRemove(keyExpr: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + maximum(): AggregateFunction; + /* Excluded from this release type: _readUserData */ + minimum(): AggregateFunction; + /* Excluded from this release type: _readUserData */ + mod(expression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + mod(value: unknown): FunctionExpr; + /* Excluded from this release type: _readUserData */ + multiply(second: Expr | unknown, ...others: Array): FunctionExpr; + /* Excluded from this release type: _readUserData */ + neq(expression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + neq(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + notEqAny(values: Array): BooleanExpr; + /* Excluded from this release type: _readUserData */ + notEqAny(arrayExpression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + regexContains(pattern: string): BooleanExpr; + /* Excluded from this release type: _readUserData */ + regexContains(pattern: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + regexMatch(pattern: string): BooleanExpr; + /* Excluded from this release type: _readUserData */ + regexMatch(pattern: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + replaceAll(find: string, replace: string): FunctionExpr; + /* Excluded from this release type: _readUserData */ + replaceAll(find: Expr, replace: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + replaceFirst(find: string, replace: string): FunctionExpr; + /* Excluded from this release type: _readUserData */ + replaceFirst(find: Expr, replace: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + reverse(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + startsWith(prefix: string): BooleanExpr; + /* Excluded from this release type: _readUserData */ + startsWith(prefix: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + strConcat(secondString: Expr | string, ...otherStrings: Array): FunctionExpr; + /* Excluded from this release type: _readUserData */ + strContains(substring: string): BooleanExpr; + /* Excluded from this release type: _readUserData */ + strContains(expr: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + substr(position: number, length?: number): FunctionExpr; + /* Excluded from this release type: _readUserData */ + substr(position: Expr, length?: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + subtract(other: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + subtract(other: unknown): FunctionExpr; + /* Excluded from this release type: _readUserData */ + sum(): AggregateFunction; + /* Excluded from this release type: _readUserData */ + timestampAdd(unit: Expr, amount: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): FunctionExpr; + /* Excluded from this release type: _readUserData */ + timestampSub(unit: Expr, amount: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): FunctionExpr; + /* Excluded from this release type: _readUserData */ + timestampToUnixMicros(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + timestampToUnixMillis(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + timestampToUnixSeconds(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + toLower(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + toUpper(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + trim(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + unixMicrosToTimestamp(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + unixMillisToTimestamp(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + unixSecondsToTimestamp(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + vectorLength(): FunctionExpr; } // @beta -export function exists(value: Accumulator): Exists; - -// @beta -export function exists(field: string): Exists; - -// @beta -export type ExprType = 'Field' | 'Constant' | 'Function' | 'ListOfExprs' | 'ExprWithAlias'; +export type ExprType = 'Field' | 'Constant' | 'Function' | 'AggregateFunction' | 'ListOfExprs' | 'ExprWithAlias'; // @beta (undocumented) -export class ExprWithAlias implements Selectable { - constructor(expr: T, alias: string); - add(other: Accumulator): Add; - add(other: any): Add; +export class ExprWithAlias implements Selectable { + constructor(expr: Expr, alias: string); // (undocumented) readonly alias: string; - arrayConcat(...arrays: Accumulator[]): ArrayConcat; - arrayConcat(...arrays: any[][]): ArrayConcat; - arrayContains(element: Accumulator): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Accumulator): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Accumulator): Divide; - divide(other: any): Divide; - dotProduct(other: Accumulator): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Accumulator): EndsWith; - eq(other: Accumulator): Eq; - eq(other: any): Eq; - eqAny(...others: Accumulator[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Accumulator): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; // (undocumented) - readonly expr: T; + readonly expr: Expr; // (undocumented) exprType: ExprType; - gt(other: Accumulator): Gt; - gt(other: any): Gt; - gte(other: Accumulator): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Accumulator): Like; - logicalMaximum(other: Accumulator): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Accumulator): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Accumulator): Lt; - lt(other: any): Lt; - lte(other: Accumulator): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Accumulator): Mod; - mod(other: any): Mod; - multiply(other: Accumulator): Multiply; - multiply(other: any): Multiply; - neq(other: Accumulator): Neq; - neq(other: any): Neq; - notEqAny(...others: Accumulator[]): FirestoreFunction; - // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Accumulator): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Accumulator): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; - reverse(): Reverse; // (undocumented) selectable: true; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Accumulator): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Accumulator): StrContains; - subtract(other: Accumulator): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; } // @beta -export class Field implements Selectable { - add(other: Accumulator): Add; - add(other: any): Add; - arrayConcat(...arrays: Accumulator[]): ArrayConcat; - arrayConcat(...arrays: any[][]): ArrayConcat; - arrayContains(element: Accumulator): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Accumulator): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Accumulator): Divide; - divide(other: any): Divide; - dotProduct(other: Accumulator): DotProduct; - dotProduct(other: VectorValue): DotProduct; +export class Field extends Expr implements Selectable { // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Accumulator): EndsWith; - eq(other: Accumulator): Eq; - eq(other: any): Eq; - eqAny(...others: Accumulator[]): EqAny; + get alias(): string; // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Accumulator): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; + get expr(): Expr; // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; + readonly exprType: ExprType; // (undocumented) fieldName(): string; - gt(other: Accumulator): Gt; - gt(other: any): Gt; - gte(other: Accumulator): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Accumulator): Like; - logicalMaximum(other: Accumulator): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Accumulator): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Accumulator): Lt; - lt(other: any): Lt; - lte(other: Accumulator): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Accumulator): Mod; - mod(other: any): Mod; - multiply(other: Accumulator): Multiply; - multiply(other: any): Multiply; - neq(other: Accumulator): Neq; - neq(other: any): Neq; - notEqAny(...others: Accumulator[]): FirestoreFunction; - // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - static of(name: string): Field; - // Warning: (ae-forgotten-export) The symbol "FieldPath" needs to be exported by the entry point pipelines.d.ts - // - // (undocumented) - static of(path: FieldPath): Field; - // (undocumented) - static of(pipeline: Pipeline, name: string): Field; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Accumulator): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Accumulator): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; - reverse(): Reverse; // (undocumented) selectable: true; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Accumulator): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Accumulator): StrContains; - subtract(other: Accumulator): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; } -// @beta (undocumented) -export class Fields implements Selectable { - add(other: Accumulator): Add; - add(other: any): Add; - arrayConcat(...arrays: Accumulator[]): ArrayConcat; - arrayConcat(...arrays: any[][]): ArrayConcat; - arrayContains(element: Accumulator): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Accumulator): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Accumulator): Divide; - divide(other: any): Divide; - dotProduct(other: Accumulator): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Accumulator): EndsWith; - eq(other: Accumulator): Eq; - eq(other: any): Eq; - eqAny(...others: Accumulator[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Accumulator): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; - // (undocumented) - fieldList(): Field[]; - gt(other: Accumulator): Gt; - gt(other: any): Gt; - gte(other: Accumulator): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Accumulator): Like; - logicalMaximum(other: Accumulator): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Accumulator): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Accumulator): Lt; - lt(other: any): Lt; - lte(other: Accumulator): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Accumulator): Mod; - mod(other: any): Mod; - multiply(other: Accumulator): Multiply; - multiply(other: any): Multiply; - neq(other: Accumulator): Neq; - neq(other: any): Neq; - notEqAny(...others: Accumulator[]): FirestoreFunction; - // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - // (undocumented) - static of(name: string, ...others: string[]): Fields; - // (undocumented) - static ofAll(): Fields; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Accumulator): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Accumulator): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; - reverse(): Reverse; - // (undocumented) - selectable: true; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Accumulator): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Accumulator): StrContains; - subtract(other: Accumulator): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} +// Warning: (ae-incompatible-release-tags) The symbol "field" is marked as @public, but its signature references "Field" which is marked as @beta +// +// @public +export function field(name: string): Field; -// @beta -export interface FilterCondition { - add(other: Accumulator): Add; - add(other: any): Add; - arrayConcat(...arrays: Accumulator[]): ArrayConcat; - arrayConcat(...arrays: any[][]): ArrayConcat; - arrayContains(element: Accumulator): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Accumulator): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Accumulator): Divide; - divide(other: any): Divide; - dotProduct(other: Accumulator): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Accumulator): EndsWith; - eq(other: Accumulator): Eq; - eq(other: any): Eq; - eqAny(...others: Accumulator[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Accumulator): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; - // (undocumented) - filterable: true; - gt(other: Accumulator): Gt; - gt(other: any): Gt; - gte(other: Accumulator): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Accumulator): Like; - logicalMaximum(other: Accumulator): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Accumulator): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Accumulator): Lt; - lt(other: any): Lt; - lte(other: Accumulator): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Accumulator): Mod; - mod(other: any): Mod; - multiply(other: Accumulator): Multiply; - multiply(other: any): Multiply; - neq(other: Accumulator): Neq; - neq(other: any): Neq; - notEqAny(...others: Accumulator[]): FirestoreFunction; - // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Accumulator): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Accumulator): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; - reverse(): Reverse; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Accumulator): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Accumulator): StrContains; - subtract(other: Accumulator): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} +// Warning: (ae-forgotten-export) The symbol "FieldPath" needs to be exported by the entry point pipelines.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "field" is marked as @public, but its signature references "Field" which is marked as @beta +// +// @public (undocumented) +export function field(path: FieldPath): Field; // @beta (undocumented) export class FindNearest implements Stage { @@ -1077,7 +718,7 @@ export interface FindNearestOptions { // (undocumented) distanceMeasure: 'euclidean' | 'cosine' | 'dot_product'; // (undocumented) - field: Field; + field: Field | string; // (undocumented) limit?: number; // (undocumented) @@ -1085,189 +726,92 @@ export interface FindNearestOptions { } // @beta -export class FirestoreFunction { - constructor(name: string, params: Accumulator[]); - add(other: Accumulator): Add; - add(other: any): Add; - arrayConcat(...arrays: Accumulator[]): ArrayConcat; - arrayConcat(...arrays: any[][]): ArrayConcat; - arrayContains(element: Accumulator): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Accumulator): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Accumulator): Divide; - divide(other: any): Divide; - dotProduct(other: Accumulator): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Accumulator): EndsWith; - eq(other: Accumulator): Eq; - eq(other: any): Eq; - eqAny(...others: Accumulator[]): EqAny; - // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Accumulator): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; +export class FunctionExpr extends Expr { + constructor(name: string, params: Expr[]); // (undocumented) - exprType: ExprType; - gt(other: Accumulator): Gt; - gt(other: any): Gt; - gte(other: Accumulator): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Accumulator): Like; - logicalMaximum(other: Accumulator): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Accumulator): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Accumulator): Lt; - lt(other: any): Lt; - lte(other: Accumulator): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Accumulator): Mod; - mod(other: any): Mod; - multiply(other: Accumulator): Multiply; - multiply(other: any): Multiply; - neq(other: Accumulator): Neq; - neq(other: any): Neq; - notEqAny(...others: Accumulator[]): FirestoreFunction; - // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Accumulator): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Accumulator): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; - reverse(): Reverse; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Accumulator): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Accumulator): StrContains; - subtract(other: Accumulator): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} - -// @beta -export function genericFunction(name: string, params: Accumulator[]): FirestoreFunction; + readonly exprType: ExprType; + } // @beta (undocumented) export class GenericStage implements Stage { - constructor(name: string, params: unknown[]); // (undocumented) name: string; -} - -// @beta (undocumented) -export class Gt extends FirestoreFunction implements FilterCondition { - constructor(left: Accumulator, right: Accumulator); - // (undocumented) - filterable: true; } // @beta -export function gt(left: Accumulator, right: Accumulator): Gt; +export function gt(left: Expr, right: Expr): BooleanExpr; // @beta -export function gt(left: Accumulator, right: any): Gt; +export function gt(expression: Expr, value: unknown): BooleanExpr; // @beta -export function gt(left: string, right: Accumulator): Gt; +export function gt(fieldName: string, expression: Expr): BooleanExpr; // @beta -export function gt(left: string, right: any): Gt; +export function gt(fieldName: string, value: unknown): BooleanExpr; -// @beta (undocumented) -export class Gte extends FirestoreFunction implements FilterCondition { - constructor(left: Accumulator, right: Accumulator); - // (undocumented) - filterable: true; - } +// @beta +export function gte(left: Expr, right: Expr): BooleanExpr; // @beta -export function gte(left: Accumulator, right: Accumulator): Gte; +export function gte(expression: Expr, value: unknown): BooleanExpr; // @beta -export function gte(left: Accumulator, right: any): Gte; +export function gte(fieldName: string, value: Expr): BooleanExpr; // @beta -export function gte(left: string, right: Accumulator): Gte; +export function gte(fieldName: string, value: unknown): BooleanExpr; // @beta -export function gte(left: string, right: any): Gte; +export function ifError(tryExpr: Expr, catchExpr: Expr): FunctionExpr; -// @beta (undocumented) -export class IsNan extends FirestoreFunction implements FilterCondition { - constructor(expr: Accumulator); - // (undocumented) - filterable: true; -} +// @beta +export function ifError(tryExpr: Expr, catchValue: unknown): FunctionExpr; // @beta -export function isNan(value: Accumulator): IsNan; +export function isAbsent(value: Expr): BooleanExpr; // @beta -export function isNan(value: string): IsNan; +export function isAbsent(field: string): BooleanExpr; -// @beta (undocumented) -export class Like extends FirestoreFunction implements FilterCondition { - constructor(expr: Accumulator, pattern: Accumulator); - // (undocumented) - filterable: true; - } +// @beta +export function isError(value: Expr): BooleanExpr; + +// @beta +export function isNan(value: Expr): BooleanExpr; + +// @beta +export function isNan(fieldName: string): BooleanExpr; + +// @beta +export function isNotNan(value: Expr): BooleanExpr; + +// @beta +export function isNotNan(value: string): BooleanExpr; + +// @beta +export function isNotNull(value: Expr): BooleanExpr; // @beta -export function like(left: string, pattern: string): Like; +export function isNotNull(value: string): BooleanExpr; // @beta -export function like(left: string, pattern: Accumulator): Like; +export function isNull(value: Expr): BooleanExpr; // @beta -export function like(left: Accumulator, pattern: string): Like; +export function isNull(value: string): BooleanExpr; // @beta -export function like(left: Accumulator, pattern: Accumulator): Like; +export function like(fieldName: string, pattern: string): BooleanExpr; + +// @beta +export function like(fieldName: string, pattern: Expr): BooleanExpr; + +// @beta +export function like(stringExpression: Expr, pattern: string): BooleanExpr; + +// @beta +export function like(stringExpression: Expr, pattern: Expr): BooleanExpr; // @beta (undocumented) export class Limit implements Stage { @@ -1280,192 +824,140 @@ export class Limit implements Stage { name: string; } -// @beta (undocumented) -export class LogicalMaximum extends FirestoreFunction { - constructor(left: Accumulator, right: Accumulator); - } +// @beta +export function logicalMaximum(first: Expr, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function logicalMaximum(left: Accumulator, right: Accumulator): LogicalMaximum; +export function logicalMaximum(fieldName: string, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function logicalMaximum(left: Accumulator, right: any): LogicalMaximum; +export function logicalMinimum(first: Expr, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function logicalMaximum(left: string, right: Accumulator): LogicalMaximum; +export function logicalMinimum(fieldName: string, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function logicalMaximum(left: string, right: any): LogicalMaximum; +export function lt(left: Expr, right: Expr): BooleanExpr; -// @beta (undocumented) -export class LogicalMinimum extends FirestoreFunction { - constructor(left: Accumulator, right: Accumulator); - } +// @beta +export function lt(expression: Expr, value: unknown): BooleanExpr; // @beta -export function logicalMinimum(left: Accumulator, right: Accumulator): LogicalMinimum; +export function lt(fieldName: string, expression: Expr): BooleanExpr; // @beta -export function logicalMinimum(left: Accumulator, right: any): LogicalMinimum; +export function lt(fieldName: string, value: unknown): BooleanExpr; // @beta -export function logicalMinimum(left: string, right: Accumulator): LogicalMinimum; +export function lte(left: Expr, right: Expr): BooleanExpr; // @beta -export function logicalMinimum(left: string, right: any): LogicalMinimum; +export function lte(expression: Expr, value: unknown): BooleanExpr; -// @beta (undocumented) -export class Lt extends FirestoreFunction implements FilterCondition { - constructor(left: Accumulator, right: Accumulator); - // (undocumented) - filterable: true; - } +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Expr" which is marked as @beta +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "BooleanExpr" which is marked as @beta +// +// @public +export function lte(fieldName: string, expression: Expr): BooleanExpr; // @beta -export function lt(left: Accumulator, right: Accumulator): Lt; +export function lte(fieldName: string, value: unknown): BooleanExpr; // @beta -export function lt(left: Accumulator, right: any): Lt; +export function manhattanDistance(fieldName: string, vector: number[] | VectorValue): FunctionExpr; // @beta -export function lt(left: string, right: Accumulator): Lt; +export function manhattanDistance(fieldName: string, vectorExpression: Expr): FunctionExpr; // @beta -export function lt(left: string, right: any): Lt; - -// @beta (undocumented) -export class Lte extends FirestoreFunction implements FilterCondition { - constructor(left: Accumulator, right: Accumulator); - // (undocumented) - filterable: true; - } +export function manhattanDistance(vectorExpression: Expr, vector: number[] | VectorValue): FunctionExpr; // @beta -export function lte(left: Accumulator, right: Accumulator): Lte; +export function manhattanDistance(vectorExpression: Expr, otherVectorExpression: Expr): FunctionExpr; // @beta -export function lte(left: Accumulator, right: any): Lte; - -// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Accumulator" which is marked as @beta -// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Lte" which is marked as @beta -// -// @public -export function lte(left: string, right: Accumulator): Lte; +export function map(elements: Record): FunctionExpr; // @beta -export function lte(left: string, right: any): Lte; - -// @beta (undocumented) -export class MapGet extends FirestoreFunction { - constructor(map: Accumulator, name: string); -} +export function mapGet(fieldName: string, subField: string): FunctionExpr; // @beta -export function mapGet(mapField: string, subField: string): MapGet; +export function mapGet(mapExpression: Expr, subField: string): FunctionExpr; // @beta -export function mapGet(mapExpr: Accumulator, subField: string): MapGet; - -// @beta (undocumented) -export class Maximum extends FirestoreFunction implements Accumulator { - constructor(value: Accumulator, distinct: boolean); - // (undocumented) - accumulator: true; - } +export function mapMerge(mapField: string, secondMap: Record | Expr, ...otherMaps: Array | Expr>): FunctionExpr; // @beta -export function maximum(value: Accumulator): Maximum; +export function mapMerge(firstMap: Record | Expr, secondMap: Record | Expr, ...otherMaps: Array | Expr>): FunctionExpr; // @beta -export function maximum(value: string): Maximum; - -// @beta (undocumented) -export class Minimum extends FirestoreFunction implements Accumulator { - constructor(value: Accumulator, distinct: boolean); - // (undocumented) - accumulator: true; - } +export function mapRemove(mapField: string, key: string): FunctionExpr; // @beta -export function minimum(value: Accumulator): Minimum; +export function mapRemove(mapExpr: Expr, key: string): FunctionExpr; // @beta -export function minimum(value: string): Minimum; - -// @beta (undocumented) -export class Mod extends FirestoreFunction { - constructor(left: Accumulator, right: Accumulator); - } +export function mapRemove(mapField: string, keyExpr: Expr): FunctionExpr; // @beta -export function mod(left: Accumulator, right: Accumulator): Mod; +export function mapRemove(mapExpr: Expr, keyExpr: Expr): FunctionExpr; // @beta -export function mod(left: Accumulator, right: any): Mod; +export function maximum(expression: Expr): AggregateFunction; // @beta -export function mod(left: string, right: Accumulator): Mod; +export function maximum(fieldName: string): AggregateFunction; // @beta -export function mod(left: string, right: any): Mod; +export function minimum(expression: Expr): AggregateFunction; -// @beta (undocumented) -export class Multiply extends FirestoreFunction { - constructor(left: Accumulator, right: Accumulator); - } +// @beta +export function minimum(fieldName: string): AggregateFunction; // @beta -export function multiply(left: Accumulator, right: Accumulator): Multiply; +export function mod(left: Expr, right: Expr): FunctionExpr; // @beta -export function multiply(left: Accumulator, right: any): Multiply; +export function mod(expression: Expr, value: unknown): FunctionExpr; // @beta -export function multiply(left: string, right: Accumulator): Multiply; +export function mod(fieldName: string, expression: Expr): FunctionExpr; // @beta -export function multiply(left: string, right: any): Multiply; +export function mod(fieldName: string, value: unknown): FunctionExpr; -// @beta (undocumented) -export class Neq extends FirestoreFunction implements FilterCondition { - constructor(left: Accumulator, right: Accumulator); - // (undocumented) - filterable: true; - } +// @beta +export function multiply(first: Expr, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function neq(left: Accumulator, right: Accumulator): Neq; +export function multiply(fieldName: string, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function neq(left: Accumulator, right: any): Neq; +export function neq(left: Expr, right: Expr): BooleanExpr; // @beta -export function neq(left: string, right: Accumulator): Neq; +export function neq(expression: Expr, value: unknown): BooleanExpr; // @beta -export function neq(left: string, right: any): Neq; +export function neq(fieldName: string, expression: Expr): BooleanExpr; -// @beta (undocumented) -export class Not extends FirestoreFunction implements FilterCondition { - constructor(expr: Accumulator); - // (undocumented) - filterable: true; -} +// @beta +export function neq(fieldName: string, value: unknown): BooleanExpr; // @beta -export function not(filter: FilterCondition): Not; +export function not(booleanExpr: BooleanExpr): BooleanExpr; // @beta -export function notEqAny(element: Accumulator, others: Accumulator[]): FirestoreFunction; +export function notEqAny(element: Expr, values: Array): BooleanExpr; // @beta -export function notEqAny(element: Accumulator, others: any[]): FirestoreFunction; +export function notEqAny(fieldName: string, values: Array): BooleanExpr; // @beta -export function notEqAny(element: string, others: Accumulator[]): FirestoreFunction; +export function notEqAny(element: Expr, arrayExpression: Expr): BooleanExpr; // @beta -export function notEqAny(element: string, others: any[]): FirestoreFunction; +export function notEqAny(fieldName: string, arrayExpression: Expr): BooleanExpr; // @beta (undocumented) export class Offset implements Stage { @@ -1474,79 +966,75 @@ export class Offset implements Stage { name: string; } -// @beta (undocumented) -export class Or extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterCondition[]); - // (undocumented) - filterable: true; -} +// @beta +export function or(first: BooleanExpr, second: BooleanExpr, ...more: BooleanExpr[]): BooleanExpr; // @beta export class Ordering { - constructor(expr: Accumulator, direction: 'ascending' | 'descending'); + constructor(expr: Expr, direction: 'ascending' | 'descending'); // (undocumented) readonly direction: 'ascending' | 'descending'; // (undocumented) - readonly expr: Accumulator; + readonly expr: Expr; } // @public export class Pipeline { /* Excluded from this release type: _db */ // Warning: (ae-incompatible-release-tags) The symbol "addFields" is marked as @public, but its signature references "Selectable" which is marked as @beta - addFields(...fields: Selectable[]): Pipeline; + addFields(field: Selectable, ...additionalFields: Selectable[]): Pipeline; /* Excluded from this release type: _userDataWriter */ - // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta - aggregate(...accumulators: AccumulatorTarget[]): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AggregateWithAlias" which is marked as @beta + aggregate(accumulator: AggregateWithAlias, ...additionalAccumulators: AggregateWithAlias[]): Pipeline; /* Excluded from this release type: _userDataWriter */ aggregate(options: { - accumulators: AccumulatorTarget[]; + accumulators: AggregateWithAlias[]; groups?: Array; }): Pipeline; /* Excluded from this release type: _userDataWriter */ // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta - distinct(...groups: Array): Pipeline; - /* Excluded from this release type: _userDataWriter */ - // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta - execute(): Promise; + distinct(group: string | Selectable, ...additionalGroups: Array): Pipeline; /* Excluded from this release type: _userDataWriter */ // Warning: (ae-incompatible-release-tags) The symbol "findNearest" is marked as @public, but its signature references "FindNearestOptions" which is marked as @beta // // (undocumented) findNearest(options: FindNearestOptions): Pipeline; /* Excluded from this release type: _userDataWriter */ - genericStage(name: string, params: any[]): Pipeline; + genericStage(name: string, params: unknown[]): Pipeline; /* Excluded from this release type: _userDataWriter */ limit(limit: number): Pipeline; /* Excluded from this release type: _userDataWriter */ offset(offset: number): Pipeline; /* Excluded from this release type: _userDataWriter */ + // Warning: (ae-incompatible-release-tags) The symbol "removeFields" is marked as @public, but its signature references "Field" which is marked as @beta + removeFields(fieldValue: Field | string, ...additionalFields: Array): Pipeline; + /* Excluded from this release type: _userDataWriter */ + // Warning: (ae-incompatible-release-tags) The symbol "replaceWith" is marked as @public, but its signature references "Field" which is marked as @beta + replaceWith(fieldValue: Field | string): Pipeline; + /* Excluded from this release type: _userDataWriter */ + sample(documents: number): Pipeline; + /* Excluded from this release type: _userDataWriter */ + sample(options: { + percentage: number; + } | { + documents: number; + }): Pipeline; + /* Excluded from this release type: _userDataWriter */ // Warning: (ae-incompatible-release-tags) The symbol "select" is marked as @public, but its signature references "Selectable" which is marked as @beta - select(...selections: Array): Pipeline; + select(selection: Selectable | string, ...additionalSelections: Array): Pipeline; /* Excluded from this release type: _userDataWriter */ // Warning: (ae-incompatible-release-tags) The symbol "sort" is marked as @public, but its signature references "Ordering" which is marked as @beta - sort(...orderings: Ordering[]): Pipeline; + sort(ordering: Ordering, ...additionalOrderings: Ordering[]): Pipeline; /* Excluded from this release type: _userDataWriter */ - // (undocumented) - sort(options: { - orderings: Ordering[]; - }): Pipeline; + union(other: Pipeline): Pipeline; /* Excluded from this release type: _userDataWriter */ - // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "FilterCondition" which is marked as @beta - where(condition: FilterCondition): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "unnest" is marked as @public, but its signature references "Selectable" which is marked as @beta + unnest(selectable: Selectable, indexField?: string): Pipeline; + /* Excluded from this release type: _userDataWriter */ + // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "BooleanExpr" which is marked as @beta + where(condition: BooleanExpr): Pipeline; } -// Warning: (ae-forgotten-export) The symbol "Firestore" needs to be exported by the entry point pipelines.d.ts -// Warning: (ae-incompatible-release-tags) The symbol "pipeline" is marked as @public, but its signature references "PipelineSource" which is marked as @beta -// -// @public -export function pipeline(firestore: Firestore): PipelineSource; - -// Warning: (ae-forgotten-export) The symbol "Query" needs to be exported by the entry point pipelines.d.ts -// -// @public -export function pipeline(query: Query): Pipeline; - // Warning: (ae-forgotten-export) The symbol "DocumentData" needs to be exported by the entry point pipelines.d.ts // // @beta @@ -1556,215 +1044,109 @@ export class PipelineResult { /* Excluded from this release type: __constructor */ get createTime(): Timestamp | undefined; data(): AppModelType | undefined; - get executionTime(): Timestamp; - get(fieldPath: string | FieldPath): any; + get(fieldPath: string | FieldPath | Field): any; get id(): string | undefined; get ref(): DocumentReference | undefined; get updateTime(): Timestamp | undefined; } +// @public (undocumented) +export class PipelineSnapshot { + // Warning: (ae-incompatible-release-tags) The symbol "__constructor" is marked as @public, but its signature references "PipelineResult" which is marked as @beta + constructor(pipeline: Pipeline, results: PipelineResult[], executionTime?: Timestamp); + get executionTime(): Timestamp; + get pipeline(): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "results" is marked as @public, but its signature references "PipelineResult" which is marked as @beta + get results(): PipelineResult[]; +} + // @beta export class PipelineSource { + collection(collectionPath: string): PipelineType; + /* Excluded from this release type: _createPipeline */ + /* Excluded from this release type: __constructor */ + // Warning: (ae-forgotten-export) The symbol "Query" needs to be exported by the entry point pipelines.d.ts + collection(collectionReference: Query): PipelineType; /* Excluded from this release type: _createPipeline */ /* Excluded from this release type: __constructor */ - // (undocumented) - collection(collectionPath: string): PipelineType; - // (undocumented) collectionGroup(collectionId: string): PipelineType; - // (undocumented) + /* Excluded from this release type: _createPipeline */ + /* Excluded from this release type: __constructor */ + createFrom(query: Query): Pipeline; + /* Excluded from this release type: _createPipeline */ + /* Excluded from this release type: __constructor */ database(): PipelineType; - // (undocumented) - documents(docs: DocumentReference[]): PipelineType; + /* Excluded from this release type: _createPipeline */ + /* Excluded from this release type: __constructor */ + documents(docs: Array): PipelineType; } -// @beta (undocumented) -export class RegexContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Accumulator, pattern: Accumulator); - // (undocumented) - filterable: true; - } - // @beta -export function regexContains(left: string, pattern: string): RegexContains; +export function rand(): FunctionExpr; // @beta -export function regexContains(left: string, pattern: Accumulator): RegexContains; +export function regexContains(fieldName: string, pattern: string): BooleanExpr; // @beta -export function regexContains(left: Accumulator, pattern: string): RegexContains; +export function regexContains(fieldName: string, pattern: Expr): BooleanExpr; // @beta -export function regexContains(left: Accumulator, pattern: Accumulator): RegexContains; - -// @beta (undocumented) -export class RegexMatch extends FirestoreFunction implements FilterCondition { - constructor(expr: Accumulator, pattern: Accumulator); - // (undocumented) - filterable: true; - } +export function regexContains(stringExpression: Expr, pattern: string): BooleanExpr; // @beta -export function regexMatch(left: string, pattern: string): RegexMatch; +export function regexContains(stringExpression: Expr, pattern: Expr): BooleanExpr; // @beta -export function regexMatch(left: string, pattern: Accumulator): RegexMatch; +export function regexMatch(fieldName: string, pattern: string): BooleanExpr; // @beta -export function regexMatch(left: Accumulator, pattern: string): RegexMatch; +export function regexMatch(fieldName: string, pattern: Expr): BooleanExpr; // @beta -export function regexMatch(left: Accumulator, pattern: Accumulator): RegexMatch; - -// @beta (undocumented) -export class ReplaceAll extends FirestoreFunction { - constructor(value: Accumulator, find: Accumulator, replace: Accumulator); - } +export function regexMatch(stringExpression: Expr, pattern: string): BooleanExpr; // @beta -export function replaceAll(value: Accumulator, find: string, replace: string): ReplaceAll; +export function regexMatch(stringExpression: Expr, pattern: Expr): BooleanExpr; // @beta -export function replaceAll(value: Accumulator, find: Accumulator, replace: Accumulator): ReplaceAll; +export function replaceAll(value: Expr, find: string, replace: string): FunctionExpr; // @beta -export function replaceAll(field: string, find: string, replace: string): ReplaceAll; - -// @beta (undocumented) -export class ReplaceFirst extends FirestoreFunction { - constructor(value: Accumulator, find: Accumulator, replace: Accumulator); - } +export function replaceAll(value: Expr, find: Expr, replace: Expr): FunctionExpr; // @beta -export function replaceFirst(value: Accumulator, find: string, replace: string): ReplaceFirst; +export function replaceAll(fieldName: string, find: string, replace: string): FunctionExpr; // @beta -export function replaceFirst(value: Accumulator, find: Accumulator, replace: Accumulator): ReplaceFirst; +export function replaceFirst(value: Expr, find: string, replace: string): FunctionExpr; // @beta -export function replaceFirst(field: string, find: string, replace: string): ReplaceFirst; +export function replaceFirst(value: Expr, find: Expr, replace: Expr): FunctionExpr; -// @beta (undocumented) -export class Reverse extends FirestoreFunction { - constructor(value: Accumulator); - } +// @beta +export function replaceFirst(fieldName: string, find: string, replace: string): FunctionExpr; // @beta -export function reverse(expr: Accumulator): Reverse; +export function reverse(stringExpression: Expr): FunctionExpr; // @beta -export function reverse(field: string): Reverse; +export function reverse(field: string): FunctionExpr; // @beta (undocumented) export class Select implements Stage { - constructor(projections: Map); + constructor(projections: Map); // (undocumented) name: string; } // @beta export interface Selectable { - add(other: Accumulator): Add; - add(other: any): Add; - arrayConcat(...arrays: Accumulator[]): ArrayConcat; - arrayConcat(...arrays: any[][]): ArrayConcat; - arrayContains(element: Accumulator): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Accumulator[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Accumulator[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Accumulator): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Accumulator): Divide; - divide(other: any): Divide; - dotProduct(other: Accumulator): DotProduct; - dotProduct(other: VectorValue): DotProduct; - // (undocumented) - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Accumulator): EndsWith; - eq(other: Accumulator): Eq; - eq(other: any): Eq; - eqAny(...others: Accumulator[]): EqAny; // (undocumented) - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Accumulator): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - // (undocumented) - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - exprType: ExprType; - gt(other: Accumulator): Gt; - gt(other: any): Gt; - gte(other: Accumulator): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - // (undocumented) - like(pattern: Accumulator): Like; - logicalMaximum(other: Accumulator): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Accumulator): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Accumulator): Lt; - lt(other: any): Lt; - lte(other: Accumulator): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Accumulator): Mod; - mod(other: any): Mod; - multiply(other: Accumulator): Multiply; - multiply(other: any): Multiply; - neq(other: Accumulator): Neq; - neq(other: any): Neq; - notEqAny(...others: Accumulator[]): FirestoreFunction; + readonly alias: string; // (undocumented) - notEqAny(...others: any[]): FirestoreFunction; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Accumulator): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Accumulator): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Accumulator, replace: Accumulator): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Accumulator, replace: Accumulator): ReplaceFirst; - reverse(): Reverse; + readonly expr: Expr; // (undocumented) selectable: true; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Accumulator): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Accumulator): StrContains; - subtract(other: Accumulator): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Accumulator, amount: Accumulator): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Accumulator, amount: Accumulator): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; } // @beta (undocumented) @@ -1780,240 +1162,153 @@ export interface Stage { name: string; } -// @beta (undocumented) -export class StartsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Accumulator, prefix: Accumulator); - // (undocumented) - filterable: true; - } - // @beta -export function startsWith(expr: string, prefix: string): StartsWith; +export function startsWith(fieldName: string, prefix: string): BooleanExpr; // @beta -export function startsWith(expr: string, prefix: Accumulator): StartsWith; +export function startsWith(fieldName: string, prefix: Expr): BooleanExpr; // @beta -export function startsWith(expr: Accumulator, prefix: string): StartsWith; +export function startsWith(stringExpression: Expr, prefix: string): BooleanExpr; // @beta -export function startsWith(expr: Accumulator, prefix: Accumulator): StartsWith; - -// @beta (undocumented) -export class StrConcat extends FirestoreFunction { - constructor(first: Accumulator, rest: Accumulator[]); - } +export function startsWith(stringExpression: Expr, prefix: Expr): BooleanExpr; // @beta -export function strConcat(first: string, ...elements: Array): StrConcat; +export function strConcat(fieldName: string, secondString: Expr | string, ...otherStrings: Array): FunctionExpr; // @beta -export function strConcat(first: Accumulator, ...elements: Array): StrConcat; - -// @beta (undocumented) -export class StrContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Accumulator, substring: Accumulator); - // (undocumented) - filterable: true; - } +export function strConcat(firstString: Expr, secondString: Expr | string, ...otherStrings: Array): FunctionExpr; // @beta -export function strContains(left: string, substring: string): StrContains; +export function strContains(fieldName: string, substring: string): BooleanExpr; // @beta -export function strContains(left: string, substring: Accumulator): StrContains; +export function strContains(fieldName: string, substring: Expr): BooleanExpr; // @beta -export function strContains(left: Accumulator, substring: string): StrContains; +export function strContains(stringExpression: Expr, substring: string): BooleanExpr; // @beta -export function strContains(left: Accumulator, substring: Accumulator): StrContains; - -// @beta (undocumented) -export class Subtract extends FirestoreFunction { - constructor(left: Accumulator, right: Accumulator); - } +export function strContains(stringExpression: Expr, substring: Expr): BooleanExpr; // @beta -export function subtract(left: Accumulator, right: Accumulator): Subtract; +export function substr(field: string, position: number, length?: number): FunctionExpr; // @beta -export function subtract(left: Accumulator, right: any): Subtract; +export function substr(input: Expr, position: number, length?: number): FunctionExpr; // @beta -export function subtract(left: string, right: Accumulator): Subtract; +export function substr(field: string, position: Expr, length?: Expr): FunctionExpr; // @beta -export function subtract(left: string, right: any): Subtract; - -// @beta (undocumented) -export class Sum extends FirestoreFunction implements Accumulator { - constructor(value: Accumulator, distinct: boolean); - // (undocumented) - accumulator: true; - } - -// @beta (undocumented) -export class TimestampAdd extends FirestoreFunction { - constructor(timestamp: Accumulator, unit: Accumulator, amount: Accumulator); - } +export function substr(input: Expr, position: Expr, length?: Expr): FunctionExpr; // @beta -export function timestampAdd(timestamp: Accumulator, unit: Accumulator, amount: Accumulator): TimestampAdd; +export function subtract(left: Expr, right: Expr): FunctionExpr; // @beta -export function timestampAdd(timestamp: Accumulator, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; +export function subtract(expression: Expr, value: unknown): FunctionExpr; // @beta -export function timestampAdd(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - -// @beta (undocumented) -export class TimestampSub extends FirestoreFunction { - constructor(timestamp: Accumulator, unit: Accumulator, amount: Accumulator); - } +export function subtract(fieldName: string, expression: Expr): FunctionExpr; // @beta -export function timestampSub(timestamp: Accumulator, unit: Accumulator, amount: Accumulator): TimestampSub; +export function subtract(fieldName: string, value: unknown): FunctionExpr; // @beta -export function timestampSub(timestamp: Accumulator, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; +export function timestampAdd(timestamp: Expr, unit: Expr, amount: Expr): FunctionExpr; // @beta -export function timestampSub(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - -// @beta (undocumented) -export class TimestampToUnixMicros extends FirestoreFunction { - constructor(input: Accumulator); - } +export function timestampAdd(timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): FunctionExpr; // @beta -export function timestampToUnixMicros(expr: Accumulator): TimestampToUnixMicros; +export function timestampAdd(fieldName: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): FunctionExpr; // @beta -export function timestampToUnixMicros(field: string): TimestampToUnixMicros; - -// @beta (undocumented) -export class TimestampToUnixMillis extends FirestoreFunction { - constructor(input: Accumulator); - } +export function timestampSub(timestamp: Expr, unit: Expr, amount: Expr): FunctionExpr; // @beta -export function timestampToUnixMillis(expr: Accumulator): TimestampToUnixMillis; +export function timestampSub(timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): FunctionExpr; // @beta -export function timestampToUnixMillis(field: string): TimestampToUnixMillis; - -// @beta (undocumented) -export class TimestampToUnixSeconds extends FirestoreFunction { - constructor(input: Accumulator); - } +export function timestampSub(fieldName: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): FunctionExpr; // @beta -export function timestampToUnixSeconds(expr: Accumulator): TimestampToUnixSeconds; +export function timestampToUnixMicros(expr: Expr): FunctionExpr; // @beta -export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; - -// @beta (undocumented) -export class ToLower extends FirestoreFunction { - constructor(expr: Accumulator); - } +export function timestampToUnixMicros(fieldName: string): FunctionExpr; // @beta -export function toLower(expr: string): ToLower; +export function timestampToUnixMillis(expr: Expr): FunctionExpr; // @beta -export function toLower(expr: Accumulator): ToLower; - -// @beta (undocumented) -export class ToUpper extends FirestoreFunction { - constructor(expr: Accumulator); - } +export function timestampToUnixMillis(fieldName: string): FunctionExpr; // @beta -export function toUpper(expr: string): ToUpper; +export function timestampToUnixSeconds(expr: Expr): FunctionExpr; // @beta -export function toUpper(expr: Accumulator): ToUpper; - -// @beta (undocumented) -export class Trim extends FirestoreFunction { - constructor(expr: Accumulator); - } +export function timestampToUnixSeconds(fieldName: string): FunctionExpr; // @beta -export function trim(expr: string): Trim; +export function toLower(fieldName: string): FunctionExpr; // @beta -export function trim(expr: Accumulator): Trim; +export function toLower(stringExpression: Expr): FunctionExpr; -// @beta (undocumented) -export class UnixMicrosToTimestamp extends FirestoreFunction { - constructor(input: Accumulator); - } +// @beta +export function toUpper(fieldName: string): FunctionExpr; // @beta -export function unixMicrosToTimestamp(expr: Accumulator): UnixMicrosToTimestamp; +export function toUpper(stringExpression: Expr): FunctionExpr; // @beta -export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; +export function trim(fieldName: string): FunctionExpr; -// @beta (undocumented) -export class UnixMillisToTimestamp extends FirestoreFunction { - constructor(input: Accumulator); - } +// @beta +export function trim(stringExpression: Expr): FunctionExpr; // @beta -export function unixMillisToTimestamp(expr: Accumulator): UnixMillisToTimestamp; +export function unixMicrosToTimestamp(expr: Expr): FunctionExpr; // @beta -export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; +export function unixMicrosToTimestamp(fieldName: string): FunctionExpr; -// @beta (undocumented) -export class UnixSecondsToTimestamp extends FirestoreFunction { - constructor(input: Accumulator); - } +// @beta +export function unixMillisToTimestamp(expr: Expr): FunctionExpr; // @beta -export function unixSecondsToTimestamp(expr: Accumulator): UnixSecondsToTimestamp; +export function unixMillisToTimestamp(fieldName: string): FunctionExpr; // @beta -export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; +export function unixSecondsToTimestamp(expr: Expr): FunctionExpr; -// @beta (undocumented) -export class VectorLength extends FirestoreFunction { - constructor(value: Accumulator); - } +// @beta +export function unixSecondsToTimestamp(fieldName: string): FunctionExpr; // @beta -export function vectorLength(expr: Accumulator): VectorLength; +export function vectorLength(vectorExpression: Expr): FunctionExpr; // @beta -export function vectorLength(field: string): VectorLength; +export function vectorLength(fieldName: string): FunctionExpr; // @beta (undocumented) export class Where implements Stage { - constructor(condition: FilterCondition); + constructor(condition: BooleanExpr); // (undocumented) name: string; } -// @beta (undocumented) -export class Xor extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterCondition[]); - // (undocumented) - filterable: true; -} - // @beta -export function xor(left: FilterCondition, ...right: FilterCondition[]): Xor; +export function xor(first: BooleanExpr, second: BooleanExpr, ...additionalConditions: BooleanExpr[]): BooleanExpr; // Warnings were encountered during analysis: // -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:10253:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:10254:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:10283:9 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:4613:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AggregateWithAlias" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/lite/pipelines.d.ts:4614:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta // (No @packageDocumentation comment for this package) diff --git a/common/api-review/firestore-pipelines.api.md b/common/api-review/firestore-pipelines.api.md index 375f5dfd976..baedbf6b08a 100644 --- a/common/api-review/firestore-pipelines.api.md +++ b/common/api-review/firestore-pipelines.api.md @@ -7,30 +7,10 @@ import { FirebaseApp } from '@firebase/app'; // @beta -export interface Accumulator extends Expr { - // (undocumented) - accumulator: true; -} - -// @beta -export type AccumulatorTarget = ExprWithAlias; - -// @beta (undocumented) -export class Add extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } +export function add(first: Expr, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function add(left: Expr, right: Expr): Add; - -// @beta -export function add(left: Expr, right: any): Add; - -// @beta -export function add(left: string, right: Expr): Add; - -// @beta -export function add(left: string, right: any): Add; +export function add(fieldName: string, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta (undocumented) export class AddFields implements Stage { @@ -41,150 +21,190 @@ export class AddFields implements Stage { // @beta (undocumented) export class Aggregate implements Stage { - constructor(accumulators: Map, groups: Map); + constructor(accumulators: Map, groups: Map); // (undocumented) name: string; } -// @beta (undocumented) -export class And extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterCondition[]); +// @beta +export class AggregateFunction { + constructor(name: string, params: Expr[]); + as(name: string): AggregateWithAlias; // (undocumented) - filterable: true; + exprType: ExprType; + } + +// @beta +export class AggregateWithAlias { + constructor(aggregate: AggregateFunction, alias: string); + // (undocumented) + readonly aggregate: AggregateFunction; + // (undocumented) + readonly alias: string; } // @beta -export function andFunction(left: FilterCondition, ...right: FilterCondition[]): And; +export function and(first: BooleanExpr, second: BooleanExpr, ...more: BooleanExpr[]): BooleanExpr; -// @beta (undocumented) -export class ArrayConcat extends FirestoreFunction { - constructor(array: Expr, elements: Expr[]); - } +// @beta +export function array(elements: unknown[]): FunctionExpr; // @beta -export function arrayConcat(array: Expr, elements: Expr[]): ArrayConcat; +export function arrayConcat(firstArray: Expr, secondArray: Expr | unknown[], ...otherArrays: Array): FunctionExpr; // @beta -export function arrayConcat(array: Expr, elements: any[]): ArrayConcat; +export function arrayConcat(firstArrayField: string, secondArray: Expr | unknown[], ...otherArrays: Array): FunctionExpr; // @beta -export function arrayConcat(array: string, elements: Expr[]): ArrayConcat; +export function arrayContains(array: Expr, element: Expr): FunctionExpr; // @beta -export function arrayConcat(array: string, elements: any[]): ArrayConcat; +export function arrayContains(array: Expr, element: unknown): FunctionExpr; -// @beta (undocumented) -export class ArrayContains extends FirestoreFunction implements FilterCondition { - constructor(array: Expr, element: Expr); - // (undocumented) - filterable: true; -} +// @beta +export function arrayContains(fieldName: string, element: Expr): FunctionExpr; // @beta -export function arrayContains(array: Expr, element: Expr): ArrayContains; +export function arrayContains(fieldName: string, element: unknown): BooleanExpr; // @beta -export function arrayContains(array: Expr, element: any): ArrayContains; +export function arrayContainsAll(array: Expr, values: Array): BooleanExpr; // @beta -export function arrayContains(array: string, element: Expr): ArrayContains; +export function arrayContainsAll(fieldName: string, values: Array): BooleanExpr; // @beta -export function arrayContains(array: string, element: any): ArrayContains; +export function arrayContainsAll(array: Expr, arrayExpression: Expr): BooleanExpr; -// @beta (undocumented) -export class ArrayContainsAll extends FirestoreFunction implements FilterCondition { - constructor(array: Expr, values: Expr[]); - // (undocumented) - filterable: true; - } +// @beta +export function arrayContainsAll(fieldName: string, arrayExpression: Expr): BooleanExpr; // @beta -export function arrayContainsAll(array: Expr, values: Expr[]): ArrayContainsAll; +export function arrayContainsAny(array: Expr, values: Array): BooleanExpr; // @beta -export function arrayContainsAll(array: Expr, values: any[]): ArrayContainsAll; +export function arrayContainsAny(fieldName: string, values: Array): BooleanExpr; // @beta -export function arrayContainsAll(array: string, values: Expr[]): ArrayContainsAll; +export function arrayContainsAny(array: Expr, values: Expr): BooleanExpr; // @beta -export function arrayContainsAll(array: string, values: any[]): ArrayContainsAll; +export function arrayContainsAny(fieldName: string, values: Expr): BooleanExpr; -// @beta (undocumented) -export class ArrayContainsAny extends FirestoreFunction implements FilterCondition { - constructor(array: Expr, values: Expr[]); - // (undocumented) - filterable: true; - } +// @beta +export function arrayLength(array: Expr): FunctionExpr; // @beta -export function arrayContainsAny(array: Expr, values: Expr[]): ArrayContainsAny; +export function arrayOffset(arrayField: string, offset: number): FunctionExpr; // @beta -export function arrayContainsAny(array: Expr, values: any[]): ArrayContainsAny; +export function arrayOffset(arrayField: string, offsetExpr: Expr): FunctionExpr; // @beta -export function arrayContainsAny(array: string, values: Expr[]): ArrayContainsAny; +export function arrayOffset(arrayExpression: Expr, offset: number): FunctionExpr; // @beta -export function arrayContainsAny(array: string, values: any[]): ArrayContainsAny; +export function arrayOffset(arrayExpression: Expr, offsetExpr: Expr): FunctionExpr; -// @beta (undocumented) -export class ArrayElement extends FirestoreFunction { - constructor(); -} +// @beta +export function ascending(expr: Expr): Ordering; -// @beta (undocumented) -export class ArrayLength extends FirestoreFunction { - constructor(array: Expr); - } +// @beta +export function ascending(fieldName: string): Ordering; // @beta -export function arrayLength(array: Expr): ArrayLength; +export function avg(expression: Expr): AggregateFunction; -// @beta (undocumented) -export class ArrayReverse extends FirestoreFunction { - constructor(array: Expr); - } +// @beta +export function avg(fieldName: string): AggregateFunction; +// Warning: (ae-forgotten-export) The symbol "Bytes" needs to be exported by the entry point pipelines.d.ts +// // @beta -export function ascending(expr: Expr): Ordering; +export function bitAnd(field: string, otherBits: number | Bytes): FunctionExpr; -// @beta (undocumented) -export class Avg extends FirestoreFunction implements Accumulator { - constructor(value: Expr, distinct: boolean); - // (undocumented) - accumulator: true; - } +// @beta +export function bitAnd(field: string, bitsExpression: Expr): FunctionExpr; // @beta -export function avgFunction(value: Expr): Avg; +export function bitAnd(bitsExpression: Expr, otherBits: number | Bytes): FunctionExpr; // @beta -export function avgFunction(value: string): Avg; +export function bitAnd(bitsExpression: Expr, otherBitsExpression: Expr): FunctionExpr; -// @beta (undocumented) -export class ByteLength extends FirestoreFunction { - constructor(value: Expr); - } +// @beta +export function bitLeftShift(field: string, y: number): FunctionExpr; // @beta -export function byteLength(expr: Expr): ByteLength; +export function bitLeftShift(field: string, numberExpr: Expr): FunctionExpr; // @beta -export function byteLength(field: string): ByteLength; +export function bitLeftShift(xValue: Expr, y: number): FunctionExpr; -// @beta (undocumented) -export class CharLength extends FirestoreFunction { - constructor(value: Expr); - } +// @beta +export function bitLeftShift(xValue: Expr, numberExpr: Expr): FunctionExpr; + +// @beta +export function bitNot(field: string): FunctionExpr; + +// @beta +export function bitNot(bitsValueExpression: Expr): FunctionExpr; // @beta -export function charLength(field: string): CharLength; +export function bitOr(field: string, otherBits: number | Bytes): FunctionExpr; // @beta -export function charLength(expr: Expr): CharLength; +export function bitOr(field: string, bitsExpression: Expr): FunctionExpr; + +// @beta +export function bitOr(bitsExpression: Expr, otherBits: number | Bytes): FunctionExpr; + +// @beta +export function bitOr(bitsExpression: Expr, otherBitsExpression: Expr): FunctionExpr; + +// @beta +export function bitRightShift(field: string, y: number): FunctionExpr; + +// @beta +export function bitRightShift(field: string, numberExpr: Expr): FunctionExpr; + +// @beta +export function bitRightShift(xValue: Expr, y: number): FunctionExpr; + +// @beta +export function bitRightShift(xValue: Expr, numberExpr: Expr): FunctionExpr; + +// @beta +export function bitXor(field: string, otherBits: number | Bytes): FunctionExpr; + +// @beta +export function bitXor(field: string, bitsExpression: Expr): FunctionExpr; + +// @beta +export function bitXor(bitsExpression: Expr, otherBits: number | Bytes): FunctionExpr; + +// @beta +export function bitXor(bitsExpression: Expr, otherBitsExpression: Expr): FunctionExpr; + +// @beta +export class BooleanExpr extends FunctionExpr { + countIf(): AggregateFunction; + // (undocumented) + filterable: true; + not(): BooleanExpr; +} + +// @beta +export function byteLength(expr: Expr): FunctionExpr; + +// @beta +export function byteLength(fieldName: string): FunctionExpr; + +// @beta +export function charLength(fieldName: string): FunctionExpr; + +// @beta +export function charLength(stringExpression: Expr): FunctionExpr; // @beta (undocumented) export class CollectionGroupSource implements Stage { @@ -200,80 +220,97 @@ export class CollectionSource implements Stage { name: string; } -// @beta (undocumented) -export class Cond extends FirestoreFunction { - constructor(condition: FilterCondition, thenExpr: Expr, elseExpr: Expr); - // (undocumented) - filterable: true; - } - // @beta -export function cond(condition: FilterCondition, thenExpr: Expr, elseExpr: Expr): Cond; +export function cond(condition: BooleanExpr, thenExpr: Expr, elseExpr: Expr): FunctionExpr; // @beta export class Constant extends Expr { // (undocumented) - exprType: ExprType; - static of(value: number): Constant; - static of(value: string): Constant; - static of(value: boolean): Constant; - static of(value: null): Constant; - static of(value: undefined): Constant; - // Warning: (ae-forgotten-export) The symbol "GeoPoint" needs to be exported by the entry point pipelines.d.ts - static of(value: GeoPoint): Constant; - // Warning: (ae-forgotten-export) The symbol "Timestamp" needs to be exported by the entry point pipelines.d.ts - static of(value: Timestamp): Constant; - static of(value: Date): Constant; - static of(value: Uint8Array): Constant; - // Warning: (ae-forgotten-export) The symbol "DocumentReference" needs to be exported by the entry point pipelines.d.ts - static of(value: DocumentReference): Constant; - static of(value: any[]): Constant; - static of(value: Map): Constant; - // Warning: (ae-forgotten-export) The symbol "VectorValue" needs to be exported by the entry point pipelines.d.ts - static of(value: VectorValue): Constant; - static vector(value: number[] | VectorValue): Constant; -} - -// @beta (undocumented) -export class CosineDistance extends FirestoreFunction { - constructor(vector1: Expr, vector2: Expr); + readonly exprType: ExprType; } -// @beta -export function cosineDistance(expr: string, other: number[]): CosineDistance; +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: number): Constant; + +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: string): Constant; + +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: boolean): Constant; + +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: null): Constant; + +// Warning: (ae-forgotten-export) The symbol "GeoPoint" needs to be exported by the entry point pipelines.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: GeoPoint): Constant; + +// Warning: (ae-forgotten-export) The symbol "Timestamp" needs to be exported by the entry point pipelines.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: Timestamp): Constant; + +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: Date): Constant; + +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: Bytes): Constant; + +// Warning: (ae-forgotten-export) The symbol "DocumentReference" needs to be exported by the entry point pipelines.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: DocumentReference): Constant; + +// Warning: (ae-forgotten-export) The symbol "VectorValue" needs to be exported by the entry point pipelines.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "constant" is marked as @public, but its signature references "Constant" which is marked as @beta +// +// @public +export function constant(value: VectorValue): Constant; // @beta -export function cosineDistance(expr: string, other: VectorValue): CosineDistance; +export function cosineDistance(fieldName: string, vector: number[] | VectorValue): FunctionExpr; // @beta -export function cosineDistance(expr: string, other: Expr): CosineDistance; +export function cosineDistance(fieldName: string, vectorExpression: Expr): FunctionExpr; // @beta -export function cosineDistance(expr: Expr, other: number[]): CosineDistance; +export function cosineDistance(vectorExpression: Expr, vector: number[] | Expr): FunctionExpr; // @beta -export function cosineDistance(expr: Expr, other: VectorValue): CosineDistance; +export function cosineDistance(vectorExpression: Expr, otherVectorExpression: Expr): FunctionExpr; // @beta -export function cosineDistance(expr: Expr, other: Expr): CosineDistance; +export function count(expression: Expr): AggregateFunction; -// @beta (undocumented) -export class Count extends FirestoreFunction implements Accumulator { - constructor(value: Expr | undefined, distinct: boolean); - // (undocumented) - accumulator: true; - } +// Warning: (ae-incompatible-release-tags) The symbol "count" is marked as @public, but its signature references "AggregateFunction" which is marked as @beta +// +// @public +export function count(fieldName: string): AggregateFunction; // @beta -export function countAll(): Count; +export function countAll(): AggregateFunction; // @beta -export function countFunction(value: Expr): Count; +export function countIf(booleanExpr: BooleanExpr): AggregateFunction; -// Warning: (ae-incompatible-release-tags) The symbol "countFunction" is marked as @public, but its signature references "Count" which is marked as @beta -// -// @public -export function countFunction(value: string): Count; +// @beta +export function currentContext(): FunctionExpr; // @beta (undocumented) export class DatabaseSource implements Stage { @@ -284,6 +321,9 @@ export class DatabaseSource implements Stage { // @beta export function descending(expr: Expr): Ordering; +// @beta +export function descending(fieldName: string): Ordering; + // @beta (undocumented) export class Distinct implements Stage { constructor(groups: Map); @@ -291,22 +331,23 @@ export class Distinct implements Stage { name: string; } -// @beta (undocumented) -export class Divide extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } +// @beta +export function divide(left: Expr, right: Expr): FunctionExpr; // @beta -export function divide(left: Expr, right: Expr): Divide; +export function divide(expression: Expr, value: unknown): FunctionExpr; // @beta -export function divide(left: Expr, right: any): Divide; +export function divide(fieldName: string, expressions: Expr): FunctionExpr; // @beta -export function divide(left: string, right: Expr): Divide; +export function divide(fieldName: string, value: unknown): FunctionExpr; // @beta -export function divide(left: string, right: any): Divide; +export function documentId(documentPath: string | DocumentReference): FunctionExpr; + +// @beta +export function documentId(documentPathExpr: Expr): FunctionExpr; // @beta (undocumented) export class DocumentsSource implements Stage { @@ -314,239 +355,320 @@ export class DocumentsSource implements Stage { // (undocumented) name: string; // (undocumented) - static of(refs: DocumentReference[]): DocumentsSource; + static of(refs: Array): DocumentsSource; } -// @beta (undocumented) -export class DotProduct extends FirestoreFunction { - constructor(vector1: Expr, vector2: Expr); - } - -// @beta -export function dotProduct(expr: string, other: number[]): DotProduct; - // @beta -export function dotProduct(expr: string, other: VectorValue): DotProduct; +export function dotProduct(fieldName: string, vector: number[] | VectorValue): FunctionExpr; // @beta -export function dotProduct(expr: string, other: Expr): DotProduct; +export function dotProduct(fieldName: string, vectorExpression: Expr): FunctionExpr; // @beta -export function dotProduct(expr: Expr, other: number[]): DotProduct; +export function dotProduct(vectorExpression: Expr, vector: number[] | VectorValue): FunctionExpr; // @beta -export function dotProduct(expr: Expr, other: VectorValue): DotProduct; +export function dotProduct(vectorExpression: Expr, otherVectorExpression: Expr): FunctionExpr; // @beta -export function dotProduct(expr: Expr, other: Expr): DotProduct; - -// @beta (undocumented) -export class EndsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr, suffix: Expr); - // (undocumented) - filterable: true; - } +export function endsWith(fieldName: string, suffix: string): BooleanExpr; // @beta -export function endsWith(expr: string, suffix: string): EndsWith; +export function endsWith(fieldName: string, suffix: Expr): BooleanExpr; // @beta -export function endsWith(expr: string, suffix: Expr): EndsWith; +export function endsWith(stringExpression: Expr, suffix: string): BooleanExpr; // @beta -export function endsWith(expr: Expr, suffix: string): EndsWith; +export function endsWith(stringExpression: Expr, suffix: Expr): BooleanExpr; // @beta -export function endsWith(expr: Expr, suffix: Expr): EndsWith; - -// @beta (undocumented) -export class Eq extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, right: Expr); - // (undocumented) - filterable: true; - } +export function eq(left: Expr, right: Expr): BooleanExpr; // @beta -export function eq(left: Expr, right: Expr): Eq; +export function eq(expression: Expr, value: unknown): BooleanExpr; // @beta -export function eq(left: Expr, right: any): Eq; +export function eq(fieldName: string, expression: Expr): BooleanExpr; // @beta -export function eq(left: string, right: Expr): Eq; +export function eq(fieldName: string, value: unknown): BooleanExpr; // @beta -export function eq(left: string, right: any): Eq; - -// @beta (undocumented) -export class EqAny extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, others: Expr[]); - // (undocumented) - filterable: true; - } +export function eqAny(expression: Expr, values: Array): BooleanExpr; // @beta -export function eqAny(element: Expr, others: Expr[]): EqAny; +export function eqAny(expression: Expr, arrayExpression: Expr): BooleanExpr; // @beta -export function eqAny(element: Expr, others: any[]): EqAny; +export function eqAny(fieldName: string, values: Array): BooleanExpr; // @beta -export function eqAny(element: string, others: Expr[]): EqAny; +export function eqAny(fieldName: string, arrayExpression: Expr): BooleanExpr; // @beta -export function eqAny(element: string, others: any[]): EqAny; - -// @beta (undocumented) -export class EuclideanDistance extends FirestoreFunction { - constructor(vector1: Expr, vector2: Expr); - } +export function euclideanDistance(fieldName: string, vector: number[] | VectorValue): FunctionExpr; // @beta -export function euclideanDistance(expr: string, other: number[]): EuclideanDistance; +export function euclideanDistance(fieldName: string, vectorExpression: Expr): FunctionExpr; // @beta -export function euclideanDistance(expr: string, other: VectorValue): EuclideanDistance; +export function euclideanDistance(vectorExpression: Expr, vector: number[] | VectorValue): FunctionExpr; // @beta -export function euclideanDistance(expr: string, other: Expr): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: Expr, other: number[]): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: Expr, other: VectorValue): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: Expr, other: Expr): EuclideanDistance; - -// Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta -// -// @public (undocumented) -export function execute(pipeline: Pipeline): Promise; +export function euclideanDistance(vectorExpression: Expr, otherVectorExpression: Expr): FunctionExpr; -// @beta (undocumented) -export class Exists extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr); - // (undocumented) - filterable: true; -} +// @public +export function execute(pipeline: Pipeline): Promise; // @beta -export function exists(value: Expr): Exists; +export function exists(value: Expr): BooleanExpr; // @beta -export function exists(field: string): Exists; +export function exists(fieldName: string): BooleanExpr; // @beta export abstract class Expr { - add(other: Expr): Add; - add(other: any): Add; - arrayConcat(...arrays: Expr[]): ArrayConcat; - arrayConcat(...arrays: any[][]): ArrayConcat; - arrayContains(element: Expr): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Expr[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Expr[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; + add(second: Expr | unknown, ...others: Array): FunctionExpr; + /* Excluded from this release type: _readUserData */ + arrayConcat(secondArray: Expr | unknown[], ...otherArrays: Array): FunctionExpr; + /* Excluded from this release type: _readUserData */ + arrayContains(expression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + arrayContains(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + arrayContainsAll(values: Array): BooleanExpr; + /* Excluded from this release type: _readUserData */ + arrayContainsAll(arrayExpression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + arrayContainsAny(values: Array): BooleanExpr; + /* Excluded from this release type: _readUserData */ + arrayContainsAny(arrayExpression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + arrayLength(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + arrayOffset(offset: number): FunctionExpr; + /* Excluded from this release type: _readUserData */ + arrayOffset(offsetExpr: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + as(name: string): ExprWithAlias; + /* Excluded from this release type: _readUserData */ ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Expr): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; + /* Excluded from this release type: _readUserData */ + avg(): AggregateFunction; + /* Excluded from this release type: _readUserData */ + bitAnd(otherBits: number | Bytes): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitAnd(bitsExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitLeftShift(y: number): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitLeftShift(numberExpr: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitNot(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitOr(otherBits: number | Bytes): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitOr(bitsExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitRightShift(y: number): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitRightShift(numberExpr: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitXor(otherBits: number | Bytes): FunctionExpr; + /* Excluded from this release type: _readUserData */ + bitXor(bitsExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + byteLength(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + charLength(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + cosineDistance(vectorExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + cosineDistance(vector: VectorValue | number[]): FunctionExpr; + /* Excluded from this release type: _readUserData */ + count(): AggregateFunction; + /* Excluded from this release type: _readUserData */ descending(): Ordering; - divide(other: Expr): Divide; - divide(other: any): Divide; - dotProduct(other: Expr): DotProduct; - dotProduct(other: VectorValue): DotProduct; - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Expr): EndsWith; - eq(other: Expr): Eq; - eq(other: any): Eq; - eqAny(...others: Expr[]): EqAny; - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Expr): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - abstract exprType: ExprType; - gt(other: Expr): Gt; - gt(other: any): Gt; - gte(other: Expr): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - like(pattern: Expr): Like; - logicalMaximum(other: Expr): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Expr): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Expr): Lt; - lt(other: any): Lt; - lte(other: Expr): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Expr): Mod; - mod(other: any): Mod; - multiply(other: Expr): Multiply; - multiply(other: any): Multiply; - neq(other: Expr): Neq; - neq(other: any): Neq; - notEqAny(...others: Expr[]): NotEqAny; - notEqAny(...others: any[]): NotEqAny; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Expr): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Expr): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Expr, replace: Expr): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Expr, replace: Expr): ReplaceFirst; - reverse(): Reverse; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Expr): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Expr): StrContains; - subtract(other: Expr): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Expr, amount: Expr): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Expr, amount: Expr): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; + /* Excluded from this release type: _readUserData */ + divide(other: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + divide(other: unknown): FunctionExpr; + /* Excluded from this release type: _readUserData */ + documentId(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + dotProduct(vectorExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + dotProduct(vector: VectorValue | number[]): FunctionExpr; + /* Excluded from this release type: _readUserData */ + endsWith(suffix: string): BooleanExpr; + /* Excluded from this release type: _readUserData */ + endsWith(suffix: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + eq(expression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + eq(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + eqAny(values: Array): BooleanExpr; + /* Excluded from this release type: _readUserData */ + eqAny(arrayExpression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + euclideanDistance(vectorExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + euclideanDistance(vector: VectorValue | number[]): FunctionExpr; + /* Excluded from this release type: _readUserData */ + exists(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + // (undocumented) + abstract readonly exprType: ExprType; + /* Excluded from this release type: _readUserData */ + gt(expression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + gt(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + gte(expression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + gte(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + ifError(catchExpr: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + ifError(catchValue: unknown): FunctionExpr; + /* Excluded from this release type: _readUserData */ + isAbsent(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + isError(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + isNan(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + isNotNan(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + isNotNull(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + isNull(): BooleanExpr; + /* Excluded from this release type: _readUserData */ + like(pattern: string): FunctionExpr; + /* Excluded from this release type: _readUserData */ + like(pattern: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + logicalMaximum(second: Expr | unknown, ...others: Array): FunctionExpr; + /* Excluded from this release type: _readUserData */ + logicalMinimum(second: Expr | unknown, ...others: Array): FunctionExpr; + /* Excluded from this release type: _readUserData */ + lt(experession: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + lt(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + lte(expression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + lte(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + manhattanDistance(vector: VectorValue | number[]): FunctionExpr; + /* Excluded from this release type: _readUserData */ + manhattanDistance(vectorExpression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + mapGet(subfield: string): FunctionExpr; + /* Excluded from this release type: _readUserData */ + mapMerge(secondMap: Record | Expr, ...otherMaps: Array | Expr>): FunctionExpr; + /* Excluded from this release type: _readUserData */ + mapRemove(key: string): FunctionExpr; + /* Excluded from this release type: _readUserData */ + mapRemove(keyExpr: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + maximum(): AggregateFunction; + /* Excluded from this release type: _readUserData */ + minimum(): AggregateFunction; + /* Excluded from this release type: _readUserData */ + mod(expression: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + mod(value: unknown): FunctionExpr; + /* Excluded from this release type: _readUserData */ + multiply(second: Expr | unknown, ...others: Array): FunctionExpr; + /* Excluded from this release type: _readUserData */ + neq(expression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + neq(value: unknown): BooleanExpr; + /* Excluded from this release type: _readUserData */ + notEqAny(values: Array): BooleanExpr; + /* Excluded from this release type: _readUserData */ + notEqAny(arrayExpression: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + regexContains(pattern: string): BooleanExpr; + /* Excluded from this release type: _readUserData */ + regexContains(pattern: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + regexMatch(pattern: string): BooleanExpr; + /* Excluded from this release type: _readUserData */ + regexMatch(pattern: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + replaceAll(find: string, replace: string): FunctionExpr; + /* Excluded from this release type: _readUserData */ + replaceAll(find: Expr, replace: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + replaceFirst(find: string, replace: string): FunctionExpr; + /* Excluded from this release type: _readUserData */ + replaceFirst(find: Expr, replace: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + reverse(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + startsWith(prefix: string): BooleanExpr; + /* Excluded from this release type: _readUserData */ + startsWith(prefix: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + strConcat(secondString: Expr | string, ...otherStrings: Array): FunctionExpr; + /* Excluded from this release type: _readUserData */ + strContains(substring: string): BooleanExpr; + /* Excluded from this release type: _readUserData */ + strContains(expr: Expr): BooleanExpr; + /* Excluded from this release type: _readUserData */ + substr(position: number, length?: number): FunctionExpr; + /* Excluded from this release type: _readUserData */ + substr(position: Expr, length?: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + subtract(other: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + subtract(other: unknown): FunctionExpr; + /* Excluded from this release type: _readUserData */ + sum(): AggregateFunction; + /* Excluded from this release type: _readUserData */ + timestampAdd(unit: Expr, amount: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): FunctionExpr; + /* Excluded from this release type: _readUserData */ + timestampSub(unit: Expr, amount: Expr): FunctionExpr; + /* Excluded from this release type: _readUserData */ + timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): FunctionExpr; + /* Excluded from this release type: _readUserData */ + timestampToUnixMicros(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + timestampToUnixMillis(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + timestampToUnixSeconds(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + toLower(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + toUpper(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + trim(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + unixMicrosToTimestamp(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + unixMillisToTimestamp(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + unixSecondsToTimestamp(): FunctionExpr; + /* Excluded from this release type: _readUserData */ + vectorLength(): FunctionExpr; } // @beta -export type ExprType = 'Field' | 'Constant' | 'Function' | 'ListOfExprs' | 'ExprWithAlias'; +export type ExprType = 'Field' | 'Constant' | 'Function' | 'AggregateFunction' | 'ListOfExprs' | 'ExprWithAlias'; // @beta (undocumented) -export class ExprWithAlias extends Expr implements Selectable { - constructor(expr: T, alias: string); +export class ExprWithAlias implements Selectable { + constructor(expr: Expr, alias: string); // (undocumented) readonly alias: string; // (undocumented) - readonly expr: T; + readonly expr: Expr; // (undocumented) exprType: ExprType; // (undocumented) @@ -556,39 +678,27 @@ export class ExprWithAlias extends Expr implements Selectable { // @beta export class Field extends Expr implements Selectable { // (undocumented) - exprType: ExprType; + get alias(): string; // (undocumented) - fieldName(): string; - static of(name: string): Field; - // Warning: (ae-forgotten-export) The symbol "FieldPath" needs to be exported by the entry point pipelines.d.ts - // + get expr(): Expr; // (undocumented) - static of(path: FieldPath): Field; + readonly exprType: ExprType; // (undocumented) - static of(pipeline: Pipeline, name: string): Field; + fieldName(): string; // (undocumented) selectable: true; } -// @beta (undocumented) -export class Fields extends Expr implements Selectable { - // (undocumented) - exprType: ExprType; - // (undocumented) - fieldList(): Field[]; - // (undocumented) - static of(name: string, ...others: string[]): Fields; - // (undocumented) - static ofAll(): Fields; - // (undocumented) - selectable: true; -} +// Warning: (ae-incompatible-release-tags) The symbol "field" is marked as @public, but its signature references "Field" which is marked as @beta +// +// @public +export function field(name: string): Field; -// @beta -export interface FilterCondition extends Expr { - // (undocumented) - filterable: true; -} +// Warning: (ae-forgotten-export) The symbol "FieldPath" needs to be exported by the entry point pipelines.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "field" is marked as @public, but its signature references "Field" which is marked as @beta +// +// @public (undocumented) +export function field(path: FieldPath): Field; // @beta (undocumented) export class FindNearest implements Stage { @@ -603,7 +713,7 @@ export interface FindNearestOptions { // (undocumented) distanceMeasure: 'euclidean' | 'cosine' | 'dot_product'; // (undocumented) - field: Field; + field: Field | string; // (undocumented) limit?: number; // (undocumented) @@ -611,91 +721,92 @@ export interface FindNearestOptions { } // @beta -export class FirestoreFunction extends Expr { +export class FunctionExpr extends Expr { constructor(name: string, params: Expr[]); // (undocumented) - exprType: ExprType; + readonly exprType: ExprType; } -// @beta -export function genericFunction(name: string, params: Expr[]): FirestoreFunction; - // @beta (undocumented) export class GenericStage implements Stage { - constructor(name: string, params: unknown[]); // (undocumented) name: string; -} - -// @beta (undocumented) -export class Gt extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, right: Expr); - // (undocumented) - filterable: true; } // @beta -export function gt(left: Expr, right: Expr): Gt; +export function gt(left: Expr, right: Expr): BooleanExpr; // @beta -export function gt(left: Expr, right: any): Gt; +export function gt(expression: Expr, value: unknown): BooleanExpr; // @beta -export function gt(left: string, right: Expr): Gt; +export function gt(fieldName: string, expression: Expr): BooleanExpr; // @beta -export function gt(left: string, right: any): Gt; +export function gt(fieldName: string, value: unknown): BooleanExpr; -// @beta (undocumented) -export class Gte extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, right: Expr); - // (undocumented) - filterable: true; - } +// @beta +export function gte(left: Expr, right: Expr): BooleanExpr; // @beta -export function gte(left: Expr, right: Expr): Gte; +export function gte(expression: Expr, value: unknown): BooleanExpr; // @beta -export function gte(left: Expr, right: any): Gte; +export function gte(fieldName: string, value: Expr): BooleanExpr; // @beta -export function gte(left: string, right: Expr): Gte; +export function gte(fieldName: string, value: unknown): BooleanExpr; // @beta -export function gte(left: string, right: any): Gte; +export function ifError(tryExpr: Expr, catchExpr: Expr): FunctionExpr; -// @beta (undocumented) -export class IsNan extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr); - // (undocumented) - filterable: true; -} +// @beta +export function ifError(tryExpr: Expr, catchValue: unknown): FunctionExpr; // @beta -export function isNan(value: Expr): IsNan; +export function isAbsent(value: Expr): BooleanExpr; // @beta -export function isNan(value: string): IsNan; +export function isAbsent(field: string): BooleanExpr; -// @beta (undocumented) -export class Like extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr, pattern: Expr); - // (undocumented) - filterable: true; - } +// @beta +export function isError(value: Expr): BooleanExpr; + +// @beta +export function isNan(value: Expr): BooleanExpr; // @beta -export function like(left: string, pattern: string): Like; +export function isNan(fieldName: string): BooleanExpr; // @beta -export function like(left: string, pattern: Expr): Like; +export function isNotNan(value: Expr): BooleanExpr; // @beta -export function like(left: Expr, pattern: string): Like; +export function isNotNan(value: string): BooleanExpr; // @beta -export function like(left: Expr, pattern: Expr): Like; +export function isNotNull(value: Expr): BooleanExpr; + +// @beta +export function isNotNull(value: string): BooleanExpr; + +// @beta +export function isNull(value: Expr): BooleanExpr; + +// @beta +export function isNull(value: string): BooleanExpr; + +// @beta +export function like(fieldName: string, pattern: string): BooleanExpr; + +// @beta +export function like(fieldName: string, pattern: Expr): BooleanExpr; + +// @beta +export function like(stringExpression: Expr, pattern: string): BooleanExpr; + +// @beta +export function like(stringExpression: Expr, pattern: Expr): BooleanExpr; // @beta (undocumented) export class Limit implements Stage { @@ -708,199 +819,140 @@ export class Limit implements Stage { name: string; } -// @beta (undocumented) -export class LogicalMaximum extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } +// @beta +export function logicalMaximum(first: Expr, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function logicalMaximum(left: Expr, right: Expr): LogicalMaximum; +export function logicalMaximum(fieldName: string, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function logicalMaximum(left: Expr, right: any): LogicalMaximum; +export function logicalMinimum(first: Expr, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function logicalMaximum(left: string, right: Expr): LogicalMaximum; +export function logicalMinimum(fieldName: string, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function logicalMaximum(left: string, right: any): LogicalMaximum; +export function lt(left: Expr, right: Expr): BooleanExpr; -// @beta (undocumented) -export class LogicalMinimum extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } +// @beta +export function lt(expression: Expr, value: unknown): BooleanExpr; // @beta -export function logicalMinimum(left: Expr, right: Expr): LogicalMinimum; +export function lt(fieldName: string, expression: Expr): BooleanExpr; // @beta -export function logicalMinimum(left: Expr, right: any): LogicalMinimum; +export function lt(fieldName: string, value: unknown): BooleanExpr; // @beta -export function logicalMinimum(left: string, right: Expr): LogicalMinimum; +export function lte(left: Expr, right: Expr): BooleanExpr; // @beta -export function logicalMinimum(left: string, right: any): LogicalMinimum; +export function lte(expression: Expr, value: unknown): BooleanExpr; -// @beta (undocumented) -export class Lt extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, right: Expr); - // (undocumented) - filterable: true; - } +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Expr" which is marked as @beta +// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "BooleanExpr" which is marked as @beta +// +// @public +export function lte(fieldName: string, expression: Expr): BooleanExpr; // @beta -export function lt(left: Expr, right: Expr): Lt; +export function lte(fieldName: string, value: unknown): BooleanExpr; // @beta -export function lt(left: Expr, right: any): Lt; +export function manhattanDistance(fieldName: string, vector: number[] | VectorValue): FunctionExpr; // @beta -export function lt(left: string, right: Expr): Lt; +export function manhattanDistance(fieldName: string, vectorExpression: Expr): FunctionExpr; // @beta -export function lt(left: string, right: any): Lt; - -// @beta (undocumented) -export class Lte extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, right: Expr); - // (undocumented) - filterable: true; - } +export function manhattanDistance(vectorExpression: Expr, vector: number[] | VectorValue): FunctionExpr; // @beta -export function lte(left: Expr, right: Expr): Lte; +export function manhattanDistance(vectorExpression: Expr, otherVectorExpression: Expr): FunctionExpr; // @beta -export function lte(left: Expr, right: any): Lte; - -// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Expr" which is marked as @beta -// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Lte" which is marked as @beta -// -// @public -export function lte(left: string, right: Expr): Lte; +export function map(elements: Record): FunctionExpr; // @beta -export function lte(left: string, right: any): Lte; - -// @beta (undocumented) -export class MapGet extends FirestoreFunction { - constructor(map: Expr, name: string); -} +export function mapGet(fieldName: string, subField: string): FunctionExpr; // @beta -export function mapGet(mapField: string, subField: string): MapGet; +export function mapGet(mapExpression: Expr, subField: string): FunctionExpr; // @beta -export function mapGet(mapExpr: Expr, subField: string): MapGet; - -// @beta (undocumented) -export class Maximum extends FirestoreFunction implements Accumulator { - constructor(value: Expr, distinct: boolean); - // (undocumented) - accumulator: true; - } +export function mapMerge(mapField: string, secondMap: Record | Expr, ...otherMaps: Array | Expr>): FunctionExpr; // @beta -export function maximum(value: Expr): Maximum; +export function mapMerge(firstMap: Record | Expr, secondMap: Record | Expr, ...otherMaps: Array | Expr>): FunctionExpr; // @beta -export function maximum(value: string): Maximum; - -// @beta (undocumented) -export class Minimum extends FirestoreFunction implements Accumulator { - constructor(value: Expr, distinct: boolean); - // (undocumented) - accumulator: true; - } +export function mapRemove(mapField: string, key: string): FunctionExpr; // @beta -export function minimum(value: Expr): Minimum; +export function mapRemove(mapExpr: Expr, key: string): FunctionExpr; // @beta -export function minimum(value: string): Minimum; - -// @beta (undocumented) -export class Mod extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } +export function mapRemove(mapField: string, keyExpr: Expr): FunctionExpr; // @beta -export function mod(left: Expr, right: Expr): Mod; +export function mapRemove(mapExpr: Expr, keyExpr: Expr): FunctionExpr; // @beta -export function mod(left: Expr, right: any): Mod; +export function maximum(expression: Expr): AggregateFunction; // @beta -export function mod(left: string, right: Expr): Mod; +export function maximum(fieldName: string): AggregateFunction; // @beta -export function mod(left: string, right: any): Mod; - -// @beta (undocumented) -export class Multiply extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } +export function minimum(expression: Expr): AggregateFunction; // @beta -export function multiply(left: Expr, right: Expr): Multiply; +export function minimum(fieldName: string): AggregateFunction; // @beta -export function multiply(left: Expr, right: any): Multiply; +export function mod(left: Expr, right: Expr): FunctionExpr; // @beta -export function multiply(left: string, right: Expr): Multiply; +export function mod(expression: Expr, value: unknown): FunctionExpr; // @beta -export function multiply(left: string, right: any): Multiply; +export function mod(fieldName: string, expression: Expr): FunctionExpr; -// @beta (undocumented) -export class Neq extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, right: Expr); - // (undocumented) - filterable: true; - } +// @beta +export function mod(fieldName: string, value: unknown): FunctionExpr; // @beta -export function neq(left: Expr, right: Expr): Neq; +export function multiply(first: Expr, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function neq(left: Expr, right: any): Neq; +export function multiply(fieldName: string, second: Expr | unknown, ...others: Array): FunctionExpr; // @beta -export function neq(left: string, right: Expr): Neq; +export function neq(left: Expr, right: Expr): BooleanExpr; // @beta -export function neq(left: string, right: any): Neq; +export function neq(expression: Expr, value: unknown): BooleanExpr; -// @beta (undocumented) -export class Not extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr); - // (undocumented) - filterable: true; -} +// @beta +export function neq(fieldName: string, expression: Expr): BooleanExpr; // @beta -export function not(filter: FilterCondition): Not; +export function neq(fieldName: string, value: unknown): BooleanExpr; -// @beta (undocumented) -export class NotEqAny extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, others: Expr[]); - // (undocumented) - filterable: true; - } +// @beta +export function not(booleanExpr: BooleanExpr): BooleanExpr; // @beta -export function notEqAny(element: Expr, others: Expr[]): NotEqAny; +export function notEqAny(element: Expr, values: Array): BooleanExpr; // @beta -export function notEqAny(element: Expr, others: any[]): NotEqAny; +export function notEqAny(fieldName: string, values: Array): BooleanExpr; // @beta -export function notEqAny(element: string, others: Expr[]): NotEqAny; +export function notEqAny(element: Expr, arrayExpression: Expr): BooleanExpr; // @beta -export function notEqAny(element: string, others: any[]): NotEqAny; +export function notEqAny(fieldName: string, arrayExpression: Expr): BooleanExpr; // @beta (undocumented) export class Offset implements Stage { @@ -909,12 +961,8 @@ export class Offset implements Stage { name: string; } -// @beta (undocumented) -export class Or extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterCondition[]); - // (undocumented) - filterable: true; -} +// @beta +export function or(first: BooleanExpr, second: BooleanExpr, ...more: BooleanExpr[]): BooleanExpr; // @beta export class Ordering { @@ -925,56 +973,46 @@ export class Ordering { readonly expr: Expr; } -// @beta -export function orFunction(left: FilterCondition, ...right: FilterCondition[]): Or; - // @public (undocumented) export class Pipeline { - /* Excluded from this release type: newPipeline */ // Warning: (ae-incompatible-release-tags) The symbol "addFields" is marked as @public, but its signature references "Selectable" which is marked as @beta - addFields(...fields: Selectable[]): Pipeline; - // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta - aggregate(...accumulators: AccumulatorTarget[]): Pipeline; - aggregate(options: { accumulators: AccumulatorTarget[]; groups?: Array; }): Pipeline; + addFields(field: Selectable, ...additionalFields: Selectable[]): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AggregateWithAlias" which is marked as @beta + aggregate(accumulator: AggregateWithAlias, ...additionalAccumulators: AggregateWithAlias[]): Pipeline; + aggregate(options: { accumulators: AggregateWithAlias[]; groups?: Array; }): Pipeline; // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta - distinct(...groups: Array): Pipeline; - // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta - execute(): Promise; + distinct(group: string | Selectable, ...additionalGroups: Array): Pipeline; // Warning: (ae-incompatible-release-tags) The symbol "findNearest" is marked as @public, but its signature references "FindNearestOptions" which is marked as @beta // // (undocumented) findNearest(options: FindNearestOptions): Pipeline; - genericStage(name: string, params: any[]): Pipeline; + genericStage(name: string, params: unknown[]): Pipeline; limit(limit: number): Pipeline; offset(offset: number): Pipeline; readUserData: any; + // Warning: (ae-incompatible-release-tags) The symbol "removeFields" is marked as @public, but its signature references "Field" which is marked as @beta + removeFields(fieldValue: Field | string, ...additionalFields: Array): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "replaceWith" is marked as @public, but its signature references "Field" which is marked as @beta + replaceWith(fieldValue: Field | string): Pipeline; + sample(documents: number): Pipeline; + sample(options: { percentage: number; } | { documents: number; }): Pipeline; // Warning: (ae-incompatible-release-tags) The symbol "select" is marked as @public, but its signature references "Selectable" which is marked as @beta - select(...selections: Array): Pipeline; + select(selection: Selectable | string, ...additionalSelections: Array): Pipeline; // (undocumented) selectablesToMap: any; // Warning: (ae-incompatible-release-tags) The symbol "sort" is marked as @public, but its signature references "Ordering" which is marked as @beta - sort(...orderings: Ordering[]): Pipeline; - // (undocumented) - sort(options: { orderings: Ordering[]; }): Pipeline; + sort(ordering: Ordering, ...additionalOrderings: Ordering[]): Pipeline; // (undocumented) stages: any; + union(other: Pipeline): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "unnest" is marked as @public, but its signature references "Selectable" which is marked as @beta + unnest(selectable: Selectable, indexField?: string): Pipeline; // (undocumented) userDataReader: any; - // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "FilterCondition" which is marked as @beta - where(condition: FilterCondition): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "BooleanExpr" which is marked as @beta + where(condition: BooleanExpr): Pipeline; } -// Warning: (ae-forgotten-export) The symbol "Firestore" needs to be exported by the entry point pipelines.d.ts -// Warning: (ae-incompatible-release-tags) The symbol "pipeline" is marked as @public, but its signature references "PipelineSource" which is marked as @beta -// -// @public -export function pipeline(firestore: Firestore): PipelineSource; - -// Warning: (ae-forgotten-export) The symbol "Query" needs to be exported by the entry point pipelines.d.ts -// -// @public -export function pipeline(query: Query): Pipeline; - // Warning: (ae-forgotten-export) The symbol "DocumentData" needs to be exported by the entry point pipelines.d.ts // // @beta @@ -984,103 +1022,93 @@ export class PipelineResult { /* Excluded from this release type: __constructor */ get createTime(): Timestamp | undefined; data(): AppModelType | undefined; - get executionTime(): Timestamp; - get(fieldPath: string | FieldPath): any; + get(fieldPath: string | FieldPath | Field): any; get id(): string | undefined; get ref(): DocumentReference | undefined; get updateTime(): Timestamp | undefined; } +// @public (undocumented) +export class PipelineSnapshot { + // Warning: (ae-incompatible-release-tags) The symbol "__constructor" is marked as @public, but its signature references "PipelineResult" which is marked as @beta + constructor(pipeline: Pipeline, results: PipelineResult[], executionTime?: Timestamp); + get executionTime(): Timestamp; + get pipeline(): Pipeline; + // Warning: (ae-incompatible-release-tags) The symbol "results" is marked as @public, but its signature references "PipelineResult" which is marked as @beta + get results(): PipelineResult[]; +} + // @beta export class PipelineSource { + collection(collectionPath: string): PipelineType; + /* Excluded from this release type: _createPipeline */ + /* Excluded from this release type: __constructor */ + // Warning: (ae-forgotten-export) The symbol "Query" needs to be exported by the entry point pipelines.d.ts + collection(collectionReference: Query): PipelineType; /* Excluded from this release type: _createPipeline */ /* Excluded from this release type: __constructor */ - // (undocumented) - collection(collectionPath: string): PipelineType; - // (undocumented) collectionGroup(collectionId: string): PipelineType; - // (undocumented) + /* Excluded from this release type: _createPipeline */ + /* Excluded from this release type: __constructor */ + createFrom(query: Query): Pipeline; + /* Excluded from this release type: _createPipeline */ + /* Excluded from this release type: __constructor */ database(): PipelineType; - // (undocumented) - documents(docs: DocumentReference[]): PipelineType; + /* Excluded from this release type: _createPipeline */ + /* Excluded from this release type: __constructor */ + documents(docs: Array): PipelineType; } -// @beta (undocumented) -export class RegexContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr, pattern: Expr); - // (undocumented) - filterable: true; - } - // @beta -export function regexContains(left: string, pattern: string): RegexContains; +export function rand(): FunctionExpr; // @beta -export function regexContains(left: string, pattern: Expr): RegexContains; +export function regexContains(fieldName: string, pattern: string): BooleanExpr; // @beta -export function regexContains(left: Expr, pattern: string): RegexContains; +export function regexContains(fieldName: string, pattern: Expr): BooleanExpr; // @beta -export function regexContains(left: Expr, pattern: Expr): RegexContains; - -// @beta (undocumented) -export class RegexMatch extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr, pattern: Expr); - // (undocumented) - filterable: true; - } +export function regexContains(stringExpression: Expr, pattern: string): BooleanExpr; // @beta -export function regexMatch(left: string, pattern: string): RegexMatch; +export function regexContains(stringExpression: Expr, pattern: Expr): BooleanExpr; // @beta -export function regexMatch(left: string, pattern: Expr): RegexMatch; +export function regexMatch(fieldName: string, pattern: string): BooleanExpr; // @beta -export function regexMatch(left: Expr, pattern: string): RegexMatch; +export function regexMatch(fieldName: string, pattern: Expr): BooleanExpr; // @beta -export function regexMatch(left: Expr, pattern: Expr): RegexMatch; - -// @beta (undocumented) -export class ReplaceAll extends FirestoreFunction { - constructor(value: Expr, find: Expr, replace: Expr); - } +export function regexMatch(stringExpression: Expr, pattern: string): BooleanExpr; // @beta -export function replaceAll(value: Expr, find: string, replace: string): ReplaceAll; +export function regexMatch(stringExpression: Expr, pattern: Expr): BooleanExpr; // @beta -export function replaceAll(value: Expr, find: Expr, replace: Expr): ReplaceAll; +export function replaceAll(value: Expr, find: string, replace: string): FunctionExpr; // @beta -export function replaceAll(field: string, find: string, replace: string): ReplaceAll; - -// @beta (undocumented) -export class ReplaceFirst extends FirestoreFunction { - constructor(value: Expr, find: Expr, replace: Expr); - } +export function replaceAll(value: Expr, find: Expr, replace: Expr): FunctionExpr; // @beta -export function replaceFirst(value: Expr, find: string, replace: string): ReplaceFirst; +export function replaceAll(fieldName: string, find: string, replace: string): FunctionExpr; // @beta -export function replaceFirst(value: Expr, find: Expr, replace: Expr): ReplaceFirst; +export function replaceFirst(value: Expr, find: string, replace: string): FunctionExpr; // @beta -export function replaceFirst(field: string, find: string, replace: string): ReplaceFirst; +export function replaceFirst(value: Expr, find: Expr, replace: Expr): FunctionExpr; -// @beta (undocumented) -export class Reverse extends FirestoreFunction { - constructor(value: Expr); - } +// @beta +export function replaceFirst(fieldName: string, find: string, replace: string): FunctionExpr; // @beta -export function reverse(expr: Expr): Reverse; +export function reverse(stringExpression: Expr): FunctionExpr; // @beta -export function reverse(field: string): Reverse; +export function reverse(field: string): FunctionExpr; // @beta (undocumented) export class Select implements Stage { @@ -1090,7 +1118,11 @@ export class Select implements Stage { } // @beta -export interface Selectable extends Expr { +export interface Selectable { + // (undocumented) + readonly alias: string; + // (undocumented) + readonly expr: Expr; // (undocumented) selectable: true; } @@ -1108,246 +1140,159 @@ export interface Stage { name: string; } -// @beta (undocumented) -export class StartsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr, prefix: Expr); - // (undocumented) - filterable: true; - } - // @beta -export function startsWith(expr: string, prefix: string): StartsWith; +export function startsWith(fieldName: string, prefix: string): BooleanExpr; // @beta -export function startsWith(expr: string, prefix: Expr): StartsWith; +export function startsWith(fieldName: string, prefix: Expr): BooleanExpr; // @beta -export function startsWith(expr: Expr, prefix: string): StartsWith; +export function startsWith(stringExpression: Expr, prefix: string): BooleanExpr; // @beta -export function startsWith(expr: Expr, prefix: Expr): StartsWith; - -// @beta (undocumented) -export class StrConcat extends FirestoreFunction { - constructor(first: Expr, rest: Expr[]); - } +export function startsWith(stringExpression: Expr, prefix: Expr): BooleanExpr; // @beta -export function strConcat(first: string, ...elements: Array): StrConcat; +export function strConcat(fieldName: string, secondString: Expr | string, ...otherStrings: Array): FunctionExpr; // @beta -export function strConcat(first: Expr, ...elements: Array): StrConcat; - -// @beta (undocumented) -export class StrContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr, substring: Expr); - // (undocumented) - filterable: true; - } +export function strConcat(firstString: Expr, secondString: Expr | string, ...otherStrings: Array): FunctionExpr; // @beta -export function strContains(left: string, substring: string): StrContains; +export function strContains(fieldName: string, substring: string): BooleanExpr; // @beta -export function strContains(left: string, substring: Expr): StrContains; +export function strContains(fieldName: string, substring: Expr): BooleanExpr; // @beta -export function strContains(left: Expr, substring: string): StrContains; +export function strContains(stringExpression: Expr, substring: string): BooleanExpr; // @beta -export function strContains(left: Expr, substring: Expr): StrContains; - -// @beta (undocumented) -export class Subtract extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } +export function strContains(stringExpression: Expr, substring: Expr): BooleanExpr; // @beta -export function subtract(left: Expr, right: Expr): Subtract; +export function substr(field: string, position: number, length?: number): FunctionExpr; // @beta -export function subtract(left: Expr, right: any): Subtract; +export function substr(input: Expr, position: number, length?: number): FunctionExpr; // @beta -export function subtract(left: string, right: Expr): Subtract; +export function substr(field: string, position: Expr, length?: Expr): FunctionExpr; // @beta -export function subtract(left: string, right: any): Subtract; - -// @beta (undocumented) -export class Sum extends FirestoreFunction implements Accumulator { - constructor(value: Expr, distinct: boolean); - // (undocumented) - accumulator: true; - } +export function substr(input: Expr, position: Expr, length?: Expr): FunctionExpr; // @beta -export function sumFunction(value: Expr): Sum; +export function subtract(left: Expr, right: Expr): FunctionExpr; // @beta -export function sumFunction(value: string): Sum; - -// @beta (undocumented) -export class TimestampAdd extends FirestoreFunction { - constructor(timestamp: Expr, unit: Expr, amount: Expr); - } +export function subtract(expression: Expr, value: unknown): FunctionExpr; // @beta -export function timestampAdd(timestamp: Expr, unit: Expr, amount: Expr): TimestampAdd; +export function subtract(fieldName: string, expression: Expr): FunctionExpr; // @beta -export function timestampAdd(timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; +export function subtract(fieldName: string, value: unknown): FunctionExpr; // @beta -export function timestampAdd(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - -// @beta (undocumented) -export class TimestampSub extends FirestoreFunction { - constructor(timestamp: Expr, unit: Expr, amount: Expr); - } +export function sum(expression: Expr): AggregateFunction; // @beta -export function timestampSub(timestamp: Expr, unit: Expr, amount: Expr): TimestampSub; +export function sum(fieldName: string): AggregateFunction; // @beta -export function timestampSub(timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; +export function timestampAdd(timestamp: Expr, unit: Expr, amount: Expr): FunctionExpr; // @beta -export function timestampSub(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - -// @beta (undocumented) -export class TimestampToUnixMicros extends FirestoreFunction { - constructor(input: Expr); - } +export function timestampAdd(timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): FunctionExpr; // @beta -export function timestampToUnixMicros(expr: Expr): TimestampToUnixMicros; +export function timestampAdd(fieldName: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): FunctionExpr; // @beta -export function timestampToUnixMicros(field: string): TimestampToUnixMicros; - -// @beta (undocumented) -export class TimestampToUnixMillis extends FirestoreFunction { - constructor(input: Expr); - } +export function timestampSub(timestamp: Expr, unit: Expr, amount: Expr): FunctionExpr; // @beta -export function timestampToUnixMillis(expr: Expr): TimestampToUnixMillis; +export function timestampSub(timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): FunctionExpr; // @beta -export function timestampToUnixMillis(field: string): TimestampToUnixMillis; - -// @beta (undocumented) -export class TimestampToUnixSeconds extends FirestoreFunction { - constructor(input: Expr); - } +export function timestampSub(fieldName: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): FunctionExpr; // @beta -export function timestampToUnixSeconds(expr: Expr): TimestampToUnixSeconds; +export function timestampToUnixMicros(expr: Expr): FunctionExpr; // @beta -export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; - -// @beta (undocumented) -export class ToLower extends FirestoreFunction { - constructor(expr: Expr); - } +export function timestampToUnixMicros(fieldName: string): FunctionExpr; // @beta -export function toLower(expr: string): ToLower; +export function timestampToUnixMillis(expr: Expr): FunctionExpr; // @beta -export function toLower(expr: Expr): ToLower; - -// @beta (undocumented) -export class ToUpper extends FirestoreFunction { - constructor(expr: Expr); - } +export function timestampToUnixMillis(fieldName: string): FunctionExpr; // @beta -export function toUpper(expr: string): ToUpper; +export function timestampToUnixSeconds(expr: Expr): FunctionExpr; // @beta -export function toUpper(expr: Expr): ToUpper; - -// @beta (undocumented) -export class Trim extends FirestoreFunction { - constructor(expr: Expr); - } +export function timestampToUnixSeconds(fieldName: string): FunctionExpr; // @beta -export function trim(expr: string): Trim; +export function toLower(fieldName: string): FunctionExpr; // @beta -export function trim(expr: Expr): Trim; +export function toLower(stringExpression: Expr): FunctionExpr; -// @beta (undocumented) -export class UnixMicrosToTimestamp extends FirestoreFunction { - constructor(input: Expr); - } +// @beta +export function toUpper(fieldName: string): FunctionExpr; // @beta -export function unixMicrosToTimestamp(expr: Expr): UnixMicrosToTimestamp; +export function toUpper(stringExpression: Expr): FunctionExpr; // @beta -export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; +export function trim(fieldName: string): FunctionExpr; -// @beta (undocumented) -export class UnixMillisToTimestamp extends FirestoreFunction { - constructor(input: Expr); - } +// @beta +export function trim(stringExpression: Expr): FunctionExpr; // @beta -export function unixMillisToTimestamp(expr: Expr): UnixMillisToTimestamp; +export function unixMicrosToTimestamp(expr: Expr): FunctionExpr; // @beta -export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; +export function unixMicrosToTimestamp(fieldName: string): FunctionExpr; -// @beta (undocumented) -export class UnixSecondsToTimestamp extends FirestoreFunction { - constructor(input: Expr); - } +// @beta +export function unixMillisToTimestamp(expr: Expr): FunctionExpr; // @beta -export function unixSecondsToTimestamp(expr: Expr): UnixSecondsToTimestamp; +export function unixMillisToTimestamp(fieldName: string): FunctionExpr; // @beta -export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; +export function unixSecondsToTimestamp(expr: Expr): FunctionExpr; -// @beta (undocumented) -export class VectorLength extends FirestoreFunction { - constructor(value: Expr); - } +// @beta +export function unixSecondsToTimestamp(fieldName: string): FunctionExpr; // @beta -export function vectorLength(expr: Expr): VectorLength; +export function vectorLength(vectorExpression: Expr): FunctionExpr; // @beta -export function vectorLength(field: string): VectorLength; +export function vectorLength(fieldName: string): FunctionExpr; // @beta (undocumented) export class Where implements Stage { - constructor(condition: FilterCondition); + constructor(condition: BooleanExpr); // (undocumented) name: string; } -// @beta (undocumented) -export class Xor extends FirestoreFunction implements FilterCondition { - constructor(conditions: FilterCondition[]); - // (undocumented) - filterable: true; -} - // @beta -export function xor(left: FilterCondition, ...right: FilterCondition[]): Xor; +export function xor(first: BooleanExpr, second: BooleanExpr, ...additionalConditions: BooleanExpr[]): BooleanExpr; // Warnings were encountered during analysis: // -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:3983:26 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:3983:61 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:4010:21 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:4552:26 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AggregateWithAlias" which is marked as @beta +// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/pipelines.d.ts:4552:62 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta // (No @packageDocumentation comment for this package) diff --git a/common/api-review/firestore.api.md b/common/api-review/firestore.api.md index 6f0e14206c2..34b56b97f21 100644 --- a/common/api-review/firestore.api.md +++ b/common/api-review/firestore.api.md @@ -9,54 +9,14 @@ import { FirebaseApp } from '@firebase/app'; import { FirebaseError } from '@firebase/util'; import { LogLevelString as LogLevel } from '@firebase/logger'; -// @beta -export interface Accumulator extends Expr { - // (undocumented) - accumulator: true; -} - -// @beta -export type AccumulatorTarget = ExprWithAlias; - -// @beta (undocumented) -export class Add extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } - -// @beta -export function add(left: Expr, right: Expr): Add; - -// @beta -export function add(left: Expr, right: any): Add; - -// @beta -export function add(left: string, right: Expr): Add; - -// @beta -export function add(left: string, right: any): Add; - // @public export function addDoc(reference: CollectionReference, data: WithFieldValue): Promise>; -// @beta (undocumented) -export class AddFields implements Stage { - constructor(fields: Map); - // (undocumented) - name: string; -} - // @public export type AddPrefixToKeys> = { [K in keyof T & string as `${Prefix}.${K}`]+?: string extends K ? any : T[K]; }; -// @beta (undocumented) -export class Aggregate implements Stage { - constructor(accumulators: Map, groups: Map); - // (undocumented) - name: string; -} - // @public export class AggregateField { readonly aggregateType: AggregateType; @@ -93,147 +53,18 @@ export type AggregateSpecData = { // @public export type AggregateType = 'count' | 'avg' | 'sum'; -// @beta (undocumented) -export class And extends FirestoreFunction implements FilterCondition { - constructor(conditions: (FilterCondition)[]); - // (undocumented) - filterable: true; -} - // @public export function and(...queryConstraints: QueryFilterConstraint[]): QueryCompositeFilterConstraint; -// @beta -export function andFunction(left: FilterCondition, ...right: (FilterCondition)[]): And; - -// @beta (undocumented) -export class ArrayConcat extends FirestoreFunction { - constructor(array: Expr, elements: Expr[]); - } - -// @beta -export function arrayConcat(array: Expr, elements: Expr[]): ArrayConcat; - -// @beta -export function arrayConcat(array: Expr, elements: any[]): ArrayConcat; - -// @beta -export function arrayConcat(array: string, elements: Expr[]): ArrayConcat; - -// @beta -export function arrayConcat(array: string, elements: any[]): ArrayConcat; - -// @beta (undocumented) -export class ArrayContains extends FirestoreFunction implements FilterCondition { - constructor(array: Expr, element: Expr); - // (undocumented) - filterable: true; -} - -// @beta -export function arrayContains(array: Expr, element: Expr): ArrayContains; - -// @beta -export function arrayContains(array: Expr, element: any): ArrayContains; - -// @beta -export function arrayContains(array: string, element: Expr): ArrayContains; - -// @beta -export function arrayContains(array: string, element: any): ArrayContains; - -// @beta (undocumented) -export class ArrayContainsAll extends FirestoreFunction implements FilterCondition { - constructor(array: Expr, values: Expr[]); - // (undocumented) - filterable: true; - } - -// @beta -export function arrayContainsAll(array: Expr, values: Expr[]): ArrayContainsAll; - -// @beta -export function arrayContainsAll(array: Expr, values: any[]): ArrayContainsAll; - -// @beta -export function arrayContainsAll(array: string, values: Expr[]): ArrayContainsAll; - -// @beta -export function arrayContainsAll(array: string, values: any[]): ArrayContainsAll; - -// @beta (undocumented) -export class ArrayContainsAny extends FirestoreFunction implements FilterCondition { - constructor(array: Expr, values: Expr[]); - // (undocumented) - filterable: true; - } - -// @beta -export function arrayContainsAny(array: Expr, values: Expr[]): ArrayContainsAny; - -// @beta -export function arrayContainsAny(array: Expr, values: any[]): ArrayContainsAny; - -// @beta -export function arrayContainsAny(array: string, values: Expr[]): ArrayContainsAny; - -// @beta -export function arrayContainsAny(array: string, values: any[]): ArrayContainsAny; - -// @beta (undocumented) -export class ArrayElement extends FirestoreFunction { - constructor(); -} - -// @beta (undocumented) -export class ArrayLength extends FirestoreFunction { - constructor(array: Expr); - } - -// @beta -export function arrayLength(array: Expr): ArrayLength; - // @public export function arrayRemove(...elements: unknown[]): FieldValue; -// @beta (undocumented) -export class ArrayReverse extends FirestoreFunction { - constructor(array: Expr); - } - // @public export function arrayUnion(...elements: unknown[]): FieldValue; -// @beta -export function ascending(expr: Expr): Ordering; - // @public export function average(field: string | FieldPath): AggregateField; -// @beta (undocumented) -export class Avg extends FirestoreFunction implements Accumulator { - constructor(value: Expr, distinct: boolean); - // (undocumented) - accumulator: true; - } - -// @beta -export function avgFunction(value: Expr): Avg; - -// @beta -export function avgFunction(value: string): Avg; - -// @beta (undocumented) -export class ByteLength extends FirestoreFunction { - constructor(value: Expr); - } - -// @beta -export function byteLength(expr: Expr): ByteLength; - -// @beta -export function byteLength(field: string): ByteLength; - // @public export class Bytes { static fromBase64String(base64: string): Bytes; @@ -247,17 +78,6 @@ export class Bytes { // @public export const CACHE_SIZE_UNLIMITED = -1; -// @beta (undocumented) -export class CharLength extends FirestoreFunction { - constructor(value: Expr); - } - -// @beta -export function charLength(field: string): CharLength; - -// @beta -export function charLength(expr: Expr): CharLength; - // @public export type ChildUpdateFields = V extends Record ? AddPrefixToKeys> : never; @@ -276,13 +96,6 @@ export function collection(refer // @public export function collectionGroup(firestore: Firestore, collectionId: string): Query; -// @beta (undocumented) -export class CollectionGroupSource implements Stage { - constructor(collectionId: string); - // (undocumented) - name: string; -} - // @public export class CollectionReference extends Query { get id(): string; @@ -293,98 +106,14 @@ export class CollectionReference; } -// @beta (undocumented) -export class CollectionSource implements Stage { - constructor(collectionPath: string); - // (undocumented) - name: string; -} - -// @beta (undocumented) -export class Cond extends FirestoreFunction { - constructor(condition: FilterCondition, thenExpr: Expr, elseExpr: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function cond(condition: FilterCondition, thenExpr: Expr, elseExpr: Expr): Cond; - // @public export function connectFirestoreEmulator(firestore: Firestore, host: string, port: number, options?: { mockUserToken?: EmulatorMockTokenOptions | string; }): void; -// @beta -export class Constant extends Expr { - // (undocumented) - exprType: ExprType; - static of(value: number): Constant; - static of(value: string): Constant; - static of(value: boolean): Constant; - static of(value: null): Constant; - static of(value: undefined): Constant; - static of(value: GeoPoint): Constant; - static of(value: Timestamp): Constant; - static of(value: Date): Constant; - static of(value: Uint8Array): Constant; - static of(value: DocumentReference): Constant; - static of(value: any[]): Constant; - static of(value: Map): Constant; - static of(value: VectorValue): Constant; - static vector(value: number[] | VectorValue): Constant; -} - -// @beta (undocumented) -export class CosineDistance extends FirestoreFunction { - constructor(vector1: Expr, vector2: Expr); - } - -// @beta -export function cosineDistance(expr: string, other: number[]): CosineDistance; - -// @beta -export function cosineDistance(expr: string, other: VectorValue): CosineDistance; - -// @beta -export function cosineDistance(expr: string, other: Expr): CosineDistance; - -// @beta -export function cosineDistance(expr: Expr, other: number[]): CosineDistance; - -// @beta -export function cosineDistance(expr: Expr, other: VectorValue): CosineDistance; - -// @beta -export function cosineDistance(expr: Expr, other: Expr): CosineDistance; - -// @beta (undocumented) -export class Count extends FirestoreFunction implements Accumulator { - constructor(value: Expr | undefined, distinct: boolean); - // (undocumented) - accumulator: true; - } - // @public export function count(): AggregateField; -// @beta -export function countAll(): Count; - -// @beta -export function countFunction(value: Expr): Count; - -// Warning: (ae-incompatible-release-tags) The symbol "countFunction" is marked as @public, but its signature references "Count" which is marked as @beta -// -// @public -export function countFunction(value: string): Count; - -// @beta (undocumented) -export class DatabaseSource implements Stage { - // (undocumented) - name: string; -} - // @public export function deleteAllPersistentCacheIndexes(indexManager: PersistentCacheIndexManager): void; @@ -394,39 +123,12 @@ export function deleteDoc(refere // @public export function deleteField(): FieldValue; -// @beta -export function descending(expr: Expr): Ordering; - // @public export function disableNetwork(firestore: Firestore): Promise; // @public export function disablePersistentCacheIndexAutoCreation(indexManager: PersistentCacheIndexManager): void; -// @beta (undocumented) -export class Distinct implements Stage { - constructor(groups: Map); - // (undocumented) - name: string; -} - -// @beta (undocumented) -export class Divide extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } - -// @beta -export function divide(left: Expr, right: Expr): Divide; - -// @beta -export function divide(left: Expr, right: any): Divide; - -// @beta -export function divide(left: string, right: Expr): Divide; - -// @beta -export function divide(left: string, right: any): Divide; - // @public export function doc(firestore: Firestore, path: string, ...pathSegments: string[]): DocumentReference; @@ -478,38 +180,6 @@ export class DocumentSnapshot; } -// @beta (undocumented) -export class DocumentsSource implements Stage { - constructor(docPaths: string[]); - // (undocumented) - name: string; - // (undocumented) - static of(refs: DocumentReference[]): DocumentsSource; -} - -// @beta (undocumented) -export class DotProduct extends FirestoreFunction { - constructor(vector1: Expr, vector2: Expr); - } - -// @beta -export function dotProduct(expr: string, other: number[]): DotProduct; - -// @beta -export function dotProduct(expr: string, other: VectorValue): DotProduct; - -// @beta -export function dotProduct(expr: string, other: Expr): DotProduct; - -// @beta -export function dotProduct(expr: Expr, other: number[]): DotProduct; - -// @beta -export function dotProduct(expr: Expr, other: VectorValue): DotProduct; - -// @beta -export function dotProduct(expr: Expr, other: Expr): DotProduct; - export { EmulatorMockTokenOptions } // @public @deprecated @@ -536,290 +206,22 @@ export function endBefore(snapsh // @public export function endBefore(...fieldValues: unknown[]): QueryEndAtConstraint; -// @beta (undocumented) -export class EndsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr, suffix: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function endsWith(expr: string, suffix: string): EndsWith; - -// @beta -export function endsWith(expr: string, suffix: Expr): EndsWith; - -// @beta -export function endsWith(expr: Expr, suffix: string): EndsWith; - -// @beta -export function endsWith(expr: Expr, suffix: Expr): EndsWith; - -// @beta (undocumented) -export class Eq extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, right: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function eq(left: Expr, right: Expr): Eq; - -// @beta -export function eq(left: Expr, right: any): Eq; - -// @beta -export function eq(left: string, right: Expr): Eq; - -// @beta -export function eq(left: string, right: any): Eq; - -// @beta (undocumented) -export class EqAny extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, others: Expr[]); - // (undocumented) - filterable: true; - } - -// @beta -export function eqAny(element: Expr, others: Expr[]): EqAny; - -// @beta -export function eqAny(element: Expr, others: any[]): EqAny; - -// @beta -export function eqAny(element: string, others: Expr[]): EqAny; - -// @beta -export function eqAny(element: string, others: any[]): EqAny; - -// @beta (undocumented) -export class EuclideanDistance extends FirestoreFunction { - constructor(vector1: Expr, vector2: Expr); - } - -// @beta -export function euclideanDistance(expr: string, other: number[]): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: string, other: VectorValue): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: string, other: Expr): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: Expr, other: number[]): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: Expr, other: VectorValue): EuclideanDistance; - -// @beta -export function euclideanDistance(expr: Expr, other: Expr): EuclideanDistance; - -// Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta -// -// @public (undocumented) -export function execute(pipeline: Pipeline): Promise; - -// @beta (undocumented) -export class Exists extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr); - // (undocumented) - filterable: true; -} - -// @beta -export function exists(value: Expr): Exists; - -// @beta -export function exists(field: string): Exists; - // @public export interface ExperimentalLongPollingOptions { timeoutSeconds?: number; } -// @beta -export abstract class Expr { - add(other: Expr): Add; - add(other: any): Add; - arrayConcat(...arrays: Expr[]): ArrayConcat; - arrayConcat(...arrays: any[][]): ArrayConcat; - arrayContains(element: Expr): ArrayContains; - arrayContains(element: any): ArrayContains; - arrayContainsAll(...values: Expr[]): ArrayContainsAll; - arrayContainsAll(...values: any[]): ArrayContainsAll; - arrayContainsAny(...values: Expr[]): ArrayContainsAny; - arrayContainsAny(...values: any[]): ArrayContainsAny; - arrayLength(): ArrayLength; - as(name: string): ExprWithAlias; - ascending(): Ordering; - avg(): Avg; - byteLength(): ByteLength; - charLength(): CharLength; - cosineDistance(other: Expr): CosineDistance; - cosineDistance(other: VectorValue): CosineDistance; - cosineDistance(other: number[]): CosineDistance; - count(): Count; - descending(): Ordering; - divide(other: Expr): Divide; - divide(other: any): Divide; - dotProduct(other: Expr): DotProduct; - dotProduct(other: VectorValue): DotProduct; - dotProduct(other: number[]): DotProduct; - endsWith(suffix: string): EndsWith; - endsWith(suffix: Expr): EndsWith; - eq(other: Expr): Eq; - eq(other: any): Eq; - eqAny(...others: Expr[]): EqAny; - eqAny(...others: any[]): EqAny; - euclideanDistance(other: Expr): EuclideanDistance; - euclideanDistance(other: VectorValue): EuclideanDistance; - euclideanDistance(other: number[]): EuclideanDistance; - exists(): Exists; - // (undocumented) - abstract exprType: ExprType; - gt(other: Expr): Gt; - gt(other: any): Gt; - gte(other: Expr): Gte; - gte(other: any): Gte; - isNaN(): IsNan; - like(pattern: string): Like; - like(pattern: Expr): Like; - logicalMaximum(other: Expr): LogicalMaximum; - logicalMaximum(other: any): LogicalMaximum; - logicalMinimum(other: Expr): LogicalMinimum; - logicalMinimum(other: any): LogicalMinimum; - lt(other: Expr): Lt; - lt(other: any): Lt; - lte(other: Expr): Lte; - lte(other: any): Lte; - mapGet(subfield: string): MapGet; - maximum(): Maximum; - minimum(): Minimum; - mod(other: Expr): Mod; - mod(other: any): Mod; - multiply(other: Expr): Multiply; - multiply(other: any): Multiply; - neq(other: Expr): Neq; - neq(other: any): Neq; - notEqAny(...others: Expr[]): NotEqAny; - notEqAny(...others: any[]): NotEqAny; - regexContains(pattern: string): RegexContains; - regexContains(pattern: Expr): RegexContains; - regexMatch(pattern: string): RegexMatch; - regexMatch(pattern: Expr): RegexMatch; - replaceAll(find: string, replace: string): ReplaceAll; - replaceAll(find: Expr, replace: Expr): ReplaceAll; - replaceFirst(find: string, replace: string): ReplaceFirst; - replaceFirst(find: Expr, replace: Expr): ReplaceFirst; - reverse(): Reverse; - startsWith(prefix: string): StartsWith; - startsWith(prefix: Expr): StartsWith; - strConcat(...elements: Array): StrConcat; - strContains(substring: string): StrContains; - strContains(expr: Expr): StrContains; - subtract(other: Expr): Subtract; - subtract(other: any): Subtract; - sum(): Sum; - timestampAdd(unit: Expr, amount: Expr): TimestampAdd; - timestampAdd(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - timestampSub(unit: Expr, amount: Expr): TimestampSub; - timestampSub(unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - timestampToUnixMicros(): TimestampToUnixMicros; - timestampToUnixMillis(): TimestampToUnixMillis; - timestampToUnixSeconds(): TimestampToUnixSeconds; - toLower(): ToLower; - toUpper(): ToUpper; - trim(): Trim; - unixMicrosToTimestamp(): UnixMicrosToTimestamp; - unixMillisToTimestamp(): UnixMillisToTimestamp; - unixSecondsToTimestamp(): UnixSecondsToTimestamp; - vectorLength(): VectorLength; -} - -// @beta -export type ExprType = 'Field' | 'Constant' | 'Function' | 'ListOfExprs' | 'ExprWithAlias'; - -// @beta (undocumented) -export class ExprWithAlias extends Expr implements Selectable { - constructor(expr: T, alias: string); - // (undocumented) - readonly alias: string; - // (undocumented) - readonly expr: T; - // (undocumented) - exprType: ExprType; - // (undocumented) - selectable: true; -} - -// @beta -export class Field extends Expr implements Selectable { - // (undocumented) - exprType: ExprType; - // (undocumented) - fieldName(): string; - static of(name: string): Field; - // (undocumented) - static of(path: FieldPath): Field; - // (undocumented) - static of(pipeline: Pipeline, name: string): Field; - // (undocumented) - selectable: true; -} - // @public export class FieldPath { constructor(...fieldNames: string[]); isEqual(other: FieldPath): boolean; } -// @beta (undocumented) -export class Fields extends Expr implements Selectable { - // (undocumented) - exprType: ExprType; - // (undocumented) - fieldList(): Field[]; - // (undocumented) - static of(name: string, ...others: string[]): Fields; - // (undocumented) - static ofAll(): Fields; - // (undocumented) - selectable: true; -} - // @public export abstract class FieldValue { abstract isEqual(other: FieldValue): boolean; } -// @beta -export interface FilterCondition extends Expr { - // (undocumented) - filterable: true; -} - -// @beta (undocumented) -export class FindNearest implements Stage { - // (undocumented) - name: string; -} - -// @beta (undocumented) -export interface FindNearestOptions { - // (undocumented) - distanceField?: string; - // (undocumented) - distanceMeasure: 'euclidean' | 'cosine' | 'dot_product'; - // (undocumented) - field: Field; - // (undocumented) - limit?: number; - // (undocumented) - vectorValue: VectorValue | number[]; -} - // @public export class Firestore { get app(): FirebaseApp; @@ -844,13 +246,6 @@ export class FirestoreError extends FirebaseError { // @public export type FirestoreErrorCode = 'cancelled' | 'unknown' | 'invalid-argument' | 'deadline-exceeded' | 'not-found' | 'already-exists' | 'permission-denied' | 'resource-exhausted' | 'failed-precondition' | 'aborted' | 'out-of-range' | 'unimplemented' | 'internal' | 'unavailable' | 'data-loss' | 'unauthenticated'; -// @beta -export class FirestoreFunction extends Expr { - constructor(name: string, params: Expr[]); - // (undocumented) - exprType: ExprType; - } - // @public export type FirestoreLocalCache = MemoryLocalCache | PersistentLocalCache; @@ -866,16 +261,6 @@ export interface FirestoreSettings { ssl?: boolean; } -// @beta -export function genericFunction(name: string, params: Expr[]): FirestoreFunction; - -// @beta (undocumented) -export class GenericStage implements Stage { - constructor(name: string, params: unknown[]); - // (undocumented) - name: string; -} - // @public export class GeoPoint { constructor(latitude: number, longitude: number); @@ -929,44 +314,6 @@ export function getFirestore(app: FirebaseApp, databaseId: string): Firestore; // @public export function getPersistentCacheIndexManager(firestore: Firestore): PersistentCacheIndexManager | null; -// @beta (undocumented) -export class Gt extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, right: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function gt(left: Expr, right: Expr): Gt; - -// @beta -export function gt(left: Expr, right: any): Gt; - -// @beta -export function gt(left: string, right: Expr): Gt; - -// @beta -export function gt(left: string, right: any): Gt; - -// @beta (undocumented) -export class Gte extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, right: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function gte(left: Expr, right: Expr): Gte; - -// @beta -export function gte(left: Expr, right: any): Gte; - -// @beta -export function gte(left: string, right: Expr): Gte; - -// @beta -export function gte(left: string, right: any): Gte; - // @public export function increment(n: number): FieldValue; @@ -997,45 +344,6 @@ export interface IndexField { // @public export function initializeFirestore(app: FirebaseApp, settings: FirestoreSettings, databaseId?: string): Firestore; -// @beta (undocumented) -export class IsNan extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr); - // (undocumented) - filterable: true; -} - -// @beta -export function isNan(value: Expr): IsNan; - -// @beta -export function isNan(value: string): IsNan; - -// @beta (undocumented) -export class Like extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr, pattern: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function like(left: string, pattern: string): Like; - -// @beta -export function like(left: string, pattern: Expr): Like; - -// @beta -export function like(left: Expr, pattern: string): Like; - -// @beta -export function like(left: Expr, pattern: Expr): Like; - -// @beta (undocumented) -export class Limit implements Stage { - constructor(limit: number); - // (undocumented) - name: string; -} - // @public export function limit(limit: number): QueryLimitConstraint; @@ -1056,114 +364,15 @@ export class LoadBundleTask implements PromiseLike { } // @public -export interface LoadBundleTaskProgress { - bytesLoaded: number; - documentsLoaded: number; - taskState: TaskState; - totalBytes: number; - totalDocuments: number; -} - -// @beta (undocumented) -export class LogicalMaximum extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } - -// @beta -export function logicalMaximum(left: Expr, right: Expr): LogicalMaximum; - -// @beta -export function logicalMaximum(left: Expr, right: any): LogicalMaximum; - -// @beta -export function logicalMaximum(left: string, right: Expr): LogicalMaximum; - -// @beta -export function logicalMaximum(left: string, right: any): LogicalMaximum; - -// @beta (undocumented) -export class LogicalMinimum extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } - -// @beta -export function logicalMinimum(left: Expr, right: Expr): LogicalMinimum; - -// @beta -export function logicalMinimum(left: Expr, right: any): LogicalMinimum; - -// @beta -export function logicalMinimum(left: string, right: Expr): LogicalMinimum; - -// @beta -export function logicalMinimum(left: string, right: any): LogicalMinimum; - -export { LogLevel } - -// @beta (undocumented) -export class Lt extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, right: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function lt(left: Expr, right: Expr): Lt; - -// @beta -export function lt(left: Expr, right: any): Lt; - -// @beta -export function lt(left: string, right: Expr): Lt; - -// @beta -export function lt(left: string, right: any): Lt; - -// @beta (undocumented) -export class Lte extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, right: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function lte(left: Expr, right: Expr): Lte; - -// @beta -export function lte(left: Expr, right: any): Lte; - -// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Expr" which is marked as @beta -// Warning: (ae-incompatible-release-tags) The symbol "lte" is marked as @public, but its signature references "Lte" which is marked as @beta -// -// @public -export function lte(left: string, right: Expr): Lte; - -// @beta -export function lte(left: string, right: any): Lte; - -// @beta (undocumented) -export class MapGet extends FirestoreFunction { - constructor(map: Expr, name: string); -} - -// @beta -export function mapGet(mapField: string, subField: string): MapGet; - -// @beta -export function mapGet(mapExpr: Expr, subField: string): MapGet; - -// @beta (undocumented) -export class Maximum extends FirestoreFunction implements Accumulator { - constructor(value: Expr, distinct: boolean); - // (undocumented) - accumulator: true; - } - -// @beta -export function maximum(value: Expr): Maximum; +export interface LoadBundleTaskProgress { + bytesLoaded: number; + documentsLoaded: number; + taskState: TaskState; + totalBytes: number; + totalDocuments: number; +} -// @beta -export function maximum(value: string): Maximum; +export { LogLevel } // @public export interface MemoryCacheSettings { @@ -1202,116 +411,14 @@ export function memoryLruGarbageCollector(settings?: { cacheSizeBytes?: number; }): MemoryLruGarbageCollector; -// @beta (undocumented) -export class Minimum extends FirestoreFunction implements Accumulator { - constructor(value: Expr, distinct: boolean); - // (undocumented) - accumulator: true; - } - -// @beta -export function minimum(value: Expr): Minimum; - -// @beta -export function minimum(value: string): Minimum; - -// @beta (undocumented) -export class Mod extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } - -// @beta -export function mod(left: Expr, right: Expr): Mod; - -// @beta -export function mod(left: Expr, right: any): Mod; - -// @beta -export function mod(left: string, right: Expr): Mod; - -// @beta -export function mod(left: string, right: any): Mod; - -// @beta (undocumented) -export class Multiply extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } - -// @beta -export function multiply(left: Expr, right: Expr): Multiply; - -// @beta -export function multiply(left: Expr, right: any): Multiply; - -// @beta -export function multiply(left: string, right: Expr): Multiply; - -// @beta -export function multiply(left: string, right: any): Multiply; - // @public export function namedQuery(firestore: Firestore, name: string): Promise; -// @beta (undocumented) -export class Neq extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, right: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function neq(left: Expr, right: Expr): Neq; - -// @beta -export function neq(left: Expr, right: any): Neq; - -// @beta -export function neq(left: string, right: Expr): Neq; - -// @beta -export function neq(left: string, right: any): Neq; - // @public export type NestedUpdateFields> = UnionToIntersection<{ [K in keyof T & string]: ChildUpdateFields; }[keyof T & string]>; -// @beta (undocumented) -export class Not extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr); - // (undocumented) - filterable: true; -} - -// @beta -export function not(filter: FilterCondition): Not; - -// @beta (undocumented) -export class NotEqAny extends FirestoreFunction implements FilterCondition { - constructor(left: Expr, others: Expr[]); - // (undocumented) - filterable: true; - } - -// @beta -export function notEqAny(element: Expr, others: Expr[]): NotEqAny; - -// @beta -export function notEqAny(element: Expr, others: any[]): NotEqAny; - -// @beta -export function notEqAny(element: string, others: Expr[]): NotEqAny; - -// @beta -export function notEqAny(element: string, others: any[]): NotEqAny; - -// @beta (undocumented) -export class Offset implements Stage { - constructor(offset: number); - // (undocumented) - name: string; - } - // @public export function onSnapshot(reference: DocumentReference, observer: { next?: (snapshot: DocumentSnapshot) => void; @@ -1362,13 +469,6 @@ export function onSnapshotsInSync(firestore: Firestore, observer: { // @public export function onSnapshotsInSync(firestore: Firestore, onSync: () => void): Unsubscribe; -// @beta (undocumented) -export class Or extends FirestoreFunction implements FilterCondition { - constructor(conditions: (FilterCondition)[]); - // (undocumented) - filterable: true; -} - // @public export function or(...queryConstraints: QueryFilterConstraint[]): QueryCompositeFilterConstraint; @@ -1378,18 +478,6 @@ export function orderBy(fieldPath: string | FieldPath, directionStr?: OrderByDir // @public export type OrderByDirection = 'desc' | 'asc'; -// @beta -export class Ordering { - constructor(expr: Expr, direction: 'ascending' | 'descending'); - // (undocumented) - readonly direction: 'ascending' | 'descending'; - // (undocumented) - readonly expr: Expr; -} - -// @beta -export function orFunction(left: FilterCondition, ...right: (FilterCondition)[]): Or; - // @public export type PartialWithFieldValue = Partial | (T extends Primitive ? T : T extends {} ? { [K in keyof T]?: PartialWithFieldValue | FieldValue; @@ -1446,78 +534,6 @@ export interface PersistentSingleTabManagerSettings { // @public export type PersistentTabManager = PersistentSingleTabManager | PersistentMultipleTabManager; -// @public (undocumented) -export class Pipeline { - /* Excluded from this release type: newPipeline */ - // Warning: (ae-incompatible-release-tags) The symbol "addFields" is marked as @public, but its signature references "Selectable" which is marked as @beta - addFields(...fields: Selectable[]): Pipeline; - // Warning: (ae-incompatible-release-tags) The symbol "aggregate" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta - aggregate(...accumulators: AccumulatorTarget[]): Pipeline; - aggregate(options: { accumulators: AccumulatorTarget[]; groups?: Array; }): Pipeline; - // Warning: (ae-incompatible-release-tags) The symbol "distinct" is marked as @public, but its signature references "Selectable" which is marked as @beta - distinct(...groups: Array): Pipeline; - // Warning: (ae-incompatible-release-tags) The symbol "execute" is marked as @public, but its signature references "PipelineResult" which is marked as @beta - execute(): Promise; - // Warning: (ae-incompatible-release-tags) The symbol "findNearest" is marked as @public, but its signature references "FindNearestOptions" which is marked as @beta - // - // (undocumented) - findNearest(options: FindNearestOptions): Pipeline; - genericStage(name: string, params: any[]): Pipeline; - limit(limit: number): Pipeline; - offset(offset: number): Pipeline; - readUserData: any; - // Warning: (ae-incompatible-release-tags) The symbol "select" is marked as @public, but its signature references "Selectable" which is marked as @beta - select(...selections: Array): Pipeline; - // (undocumented) - selectablesToMap: any; - // Warning: (ae-incompatible-release-tags) The symbol "sort" is marked as @public, but its signature references "Ordering" which is marked as @beta - sort(...orderings: Ordering[]): Pipeline; - // (undocumented) - sort(options: { orderings: Ordering[]; }): Pipeline; - // (undocumented) - stages: any; - // (undocumented) - userDataReader: any; - // Warning: (ae-incompatible-release-tags) The symbol "where" is marked as @public, but its signature references "FilterCondition" which is marked as @beta - where(condition: FilterCondition): Pipeline; -} - -// Warning: (ae-incompatible-release-tags) The symbol "pipeline" is marked as @public, but its signature references "PipelineSource" which is marked as @beta -// -// @public -export function pipeline(firestore: Firestore): PipelineSource; - -// @public -export function pipeline(query: Query): Pipeline; - -// @beta -export class PipelineResult { - /* Excluded from this release type: _ref */ - /* Excluded from this release type: _fields */ - /* Excluded from this release type: __constructor */ - get createTime(): Timestamp | undefined; - data(): AppModelType | undefined; - get executionTime(): Timestamp; - get(fieldPath: string | FieldPath): any; - get id(): string | undefined; - get ref(): DocumentReference | undefined; - get updateTime(): Timestamp | undefined; -} - -// @beta -export class PipelineSource { - /* Excluded from this release type: _createPipeline */ - /* Excluded from this release type: __constructor */ - // (undocumented) - collection(collectionPath: string): PipelineType; - // (undocumented) - collectionGroup(collectionId: string): PipelineType; - // (undocumented) - database(): PipelineType; - // (undocumented) - documents(docs: DocumentReference[]): PipelineType; -} - // @public export type Primitive = string | number | boolean | undefined | null; @@ -1604,99 +620,9 @@ export class QueryStartAtConstraint extends QueryConstraint { // @public export function refEqual(left: DocumentReference | CollectionReference, right: DocumentReference | CollectionReference): boolean; -// @beta (undocumented) -export class RegexContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr, pattern: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function regexContains(left: string, pattern: string): RegexContains; - -// @beta -export function regexContains(left: string, pattern: Expr): RegexContains; - -// @beta -export function regexContains(left: Expr, pattern: string): RegexContains; - -// @beta -export function regexContains(left: Expr, pattern: Expr): RegexContains; - -// @beta (undocumented) -export class RegexMatch extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr, pattern: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function regexMatch(left: string, pattern: string): RegexMatch; - -// @beta -export function regexMatch(left: string, pattern: Expr): RegexMatch; - -// @beta -export function regexMatch(left: Expr, pattern: string): RegexMatch; - -// @beta -export function regexMatch(left: Expr, pattern: Expr): RegexMatch; - -// @beta (undocumented) -export class ReplaceAll extends FirestoreFunction { - constructor(value: Expr, find: Expr, replace: Expr); - } - -// @beta -export function replaceAll(value: Expr, find: string, replace: string): ReplaceAll; - -// @beta -export function replaceAll(value: Expr, find: Expr, replace: Expr): ReplaceAll; - -// @beta -export function replaceAll(field: string, find: string, replace: string): ReplaceAll; - -// @beta (undocumented) -export class ReplaceFirst extends FirestoreFunction { - constructor(value: Expr, find: Expr, replace: Expr); - } - -// @beta -export function replaceFirst(value: Expr, find: string, replace: string): ReplaceFirst; - -// @beta -export function replaceFirst(value: Expr, find: Expr, replace: Expr): ReplaceFirst; - -// @beta -export function replaceFirst(field: string, find: string, replace: string): ReplaceFirst; - -// @beta (undocumented) -export class Reverse extends FirestoreFunction { - constructor(value: Expr); - } - -// @beta -export function reverse(expr: Expr): Reverse; - -// @beta -export function reverse(field: string): Reverse; - // @public export function runTransaction(firestore: Firestore, updateFunction: (transaction: Transaction) => Promise, options?: TransactionOptions): Promise; -// @beta (undocumented) -export class Select implements Stage { - constructor(projections: Map); - // (undocumented) - name: string; - } - -// @beta -export interface Selectable extends Expr { - // (undocumented) - selectable: true; -} - // @public export function serverTimestamp(): FieldValue; @@ -1743,19 +669,6 @@ export interface SnapshotOptions { readonly serverTimestamps?: 'estimate' | 'previous' | 'none'; } -// @beta (undocumented) -export class Sort implements Stage { - constructor(orders: Ordering[]); - // (undocumented) - name: string; - } - -// @beta (undocumented) -export interface Stage { - // (undocumented) - name: string; -} - // @public export function startAfter(snapshot: DocumentSnapshot): QueryStartAtConstraint; @@ -1768,88 +681,9 @@ export function startAt(snapshot // @public export function startAt(...fieldValues: unknown[]): QueryStartAtConstraint; -// @beta (undocumented) -export class StartsWith extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr, prefix: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function startsWith(expr: string, prefix: string): StartsWith; - -// @beta -export function startsWith(expr: string, prefix: Expr): StartsWith; - -// @beta -export function startsWith(expr: Expr, prefix: string): StartsWith; - -// @beta -export function startsWith(expr: Expr, prefix: Expr): StartsWith; - -// @beta (undocumented) -export class StrConcat extends FirestoreFunction { - constructor(first: Expr, rest: Expr[]); - } - -// @beta -export function strConcat(first: string, ...elements: Array): StrConcat; - -// @beta -export function strConcat(first: Expr, ...elements: Array): StrConcat; - -// @beta (undocumented) -export class StrContains extends FirestoreFunction implements FilterCondition { - constructor(expr: Expr, substring: Expr); - // (undocumented) - filterable: true; - } - -// @beta -export function strContains(left: string, substring: string): StrContains; - -// @beta -export function strContains(left: string, substring: Expr): StrContains; - -// @beta -export function strContains(left: Expr, substring: string): StrContains; - -// @beta -export function strContains(left: Expr, substring: Expr): StrContains; - -// @beta (undocumented) -export class Subtract extends FirestoreFunction { - constructor(left: Expr, right: Expr); - } - -// @beta -export function subtract(left: Expr, right: Expr): Subtract; - -// @beta -export function subtract(left: Expr, right: any): Subtract; - -// @beta -export function subtract(left: string, right: Expr): Subtract; - -// @beta -export function subtract(left: string, right: any): Subtract; - -// @beta (undocumented) -export class Sum extends FirestoreFunction implements Accumulator { - constructor(value: Expr, distinct: boolean); - // (undocumented) - accumulator: true; - } - // @public export function sum(field: string | FieldPath): AggregateField; -// @beta -export function sumFunction(value: Expr): Sum; - -// @beta -export function sumFunction(value: string): Sum; - // @public export type TaskState = 'Error' | 'Running' | 'Success'; @@ -1877,89 +711,6 @@ export class Timestamp { valueOf(): string; } -// @beta (undocumented) -export class TimestampAdd extends FirestoreFunction { - constructor(timestamp: Expr, unit: Expr, amount: Expr); - } - -// @beta -export function timestampAdd(timestamp: Expr, unit: Expr, amount: Expr): TimestampAdd; - -// @beta -export function timestampAdd(timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - -// @beta -export function timestampAdd(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampAdd; - -// @beta (undocumented) -export class TimestampSub extends FirestoreFunction { - constructor(timestamp: Expr, unit: Expr, amount: Expr); - } - -// @beta -export function timestampSub(timestamp: Expr, unit: Expr, amount: Expr): TimestampSub; - -// @beta -export function timestampSub(timestamp: Expr, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - -// @beta -export function timestampSub(field: string, unit: 'microsecond' | 'millisecond' | 'second' | 'minute' | 'hour' | 'day', amount: number): TimestampSub; - -// @beta (undocumented) -export class TimestampToUnixMicros extends FirestoreFunction { - constructor(input: Expr); - } - -// @beta -export function timestampToUnixMicros(expr: Expr): TimestampToUnixMicros; - -// @beta -export function timestampToUnixMicros(field: string): TimestampToUnixMicros; - -// @beta (undocumented) -export class TimestampToUnixMillis extends FirestoreFunction { - constructor(input: Expr); - } - -// @beta -export function timestampToUnixMillis(expr: Expr): TimestampToUnixMillis; - -// @beta -export function timestampToUnixMillis(field: string): TimestampToUnixMillis; - -// @beta (undocumented) -export class TimestampToUnixSeconds extends FirestoreFunction { - constructor(input: Expr); - } - -// @beta -export function timestampToUnixSeconds(expr: Expr): TimestampToUnixSeconds; - -// @beta -export function timestampToUnixSeconds(field: string): TimestampToUnixSeconds; - -// @beta (undocumented) -export class ToLower extends FirestoreFunction { - constructor(expr: Expr); - } - -// @beta -export function toLower(expr: string): ToLower; - -// @beta -export function toLower(expr: Expr): ToLower; - -// @beta (undocumented) -export class ToUpper extends FirestoreFunction { - constructor(expr: Expr); - } - -// @beta -export function toUpper(expr: string): ToUpper; - -// @beta -export function toUpper(expr: Expr): ToUpper; - // @public export class Transaction { delete(documentRef: DocumentReference): this; @@ -1975,53 +726,9 @@ export interface TransactionOptions { readonly maxAttempts?: number; } -// @beta (undocumented) -export class Trim extends FirestoreFunction { - constructor(expr: Expr); - } - -// @beta -export function trim(expr: string): Trim; - -// @beta -export function trim(expr: Expr): Trim; - // @public export type UnionToIntersection = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never; -// @beta (undocumented) -export class UnixMicrosToTimestamp extends FirestoreFunction { - constructor(input: Expr); - } - -// @beta -export function unixMicrosToTimestamp(expr: Expr): UnixMicrosToTimestamp; - -// @beta -export function unixMicrosToTimestamp(field: string): UnixMicrosToTimestamp; - -// @beta (undocumented) -export class UnixMillisToTimestamp extends FirestoreFunction { - constructor(input: Expr); - } - -// @beta -export function unixMillisToTimestamp(expr: Expr): UnixMillisToTimestamp; - -// @beta -export function unixMillisToTimestamp(field: string): UnixMillisToTimestamp; - -// @beta (undocumented) -export class UnixSecondsToTimestamp extends FirestoreFunction { - constructor(input: Expr); - } - -// @beta -export function unixSecondsToTimestamp(expr: Expr): UnixSecondsToTimestamp; - -// @beta -export function unixSecondsToTimestamp(field: string): UnixSecondsToTimestamp; - // @public export interface Unsubscribe { (): void; @@ -2041,17 +748,6 @@ export function updateDoc(refere // @public export function vector(values?: number[]): VectorValue; -// @beta (undocumented) -export class VectorLength extends FirestoreFunction { - constructor(value: Expr); - } - -// @beta -export function vectorLength(expr: Expr): VectorLength; - -// @beta -export function vectorLength(field: string): VectorLength; - // @public export class VectorValue { /* Excluded from this release type: __constructor */ @@ -2062,13 +758,6 @@ export class VectorValue { // @public export function waitForPendingWrites(firestore: Firestore): Promise; -// @beta (undocumented) -export class Where implements Stage { - constructor(condition: FilterCondition); - // (undocumented) - name: string; -} - // @public export function where(fieldPath: string | FieldPath, opStr: WhereFilterOp, value: unknown): QueryFieldFilterConstraint; @@ -2093,21 +782,5 @@ export class WriteBatch { // @public export function writeBatch(firestore: Firestore): WriteBatch; -// @beta (undocumented) -export class Xor extends FirestoreFunction implements FilterCondition { - constructor(conditions: (FilterCondition)[]); - // (undocumented) - filterable: true; -} - -// @beta -export function xor(left: FilterCondition, ...right: (FilterCondition)[]): Xor; - - -// Warnings were encountered during analysis: -// -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/all_packages.d.ts:5962:26 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/all_packages.d.ts:5962:61 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta -// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/all_packages.d.ts:5989:21 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta ``` From 58db6bfa49c630ac3bed3c2bc8c8f3219f79b347 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 21 Mar 2025 13:58:23 -0600 Subject: [PATCH 72/75] Fixing tests and improving test coverage --- .../firestore/lite/pipelines/pipelines.ts | 1 - packages/firestore/src/api_pipelines.ts | 7 +- packages/firestore/src/core/pipeline-util.ts | 14 +- .../firestore/src/lite-api/expressions.ts | 144 +- packages/firestore/src/lite-api/pipeline.ts | 5 +- packages/firestore/src/lite-api/stage.ts | 2 +- .../test/integration/api/pipeline.test.ts | 1279 +++++++++-------- .../integration/api/query_to_pipeline.test.ts | 549 +++++-- .../test/integration/util/helpers.ts | 7 + packages/firestore/test/lite/pipeline.test.ts | 17 +- 10 files changed, 1150 insertions(+), 875 deletions(-) diff --git a/packages/firestore/lite/pipelines/pipelines.ts b/packages/firestore/lite/pipelines/pipelines.ts index 02c2748c308..e03e5f4883b 100644 --- a/packages/firestore/lite/pipelines/pipelines.ts +++ b/packages/firestore/lite/pipelines/pipelines.ts @@ -107,7 +107,6 @@ export { bitXor, divide, isNotNan, - manhattanDistance, map, isNotNull, isNull, diff --git a/packages/firestore/src/api_pipelines.ts b/packages/firestore/src/api_pipelines.ts index 1b3d3cbd517..ad7815af3e4 100644 --- a/packages/firestore/src/api_pipelines.ts +++ b/packages/firestore/src/api_pipelines.ts @@ -17,7 +17,11 @@ export { PipelineSource } from './lite-api/pipeline-source'; -export { PipelineResult, PipelineSnapshot } from './lite-api/pipeline-result'; +export { + PipelineResult, + PipelineSnapshot, + pipelineResultEqual +} from './lite-api/pipeline-result'; export { Pipeline } from './api/pipeline'; @@ -130,7 +134,6 @@ export { mapMerge, documentId, substr, - manhattanDistance, Expr, ExprWithAlias, Field, diff --git a/packages/firestore/src/core/pipeline-util.ts b/packages/firestore/src/core/pipeline-util.ts index dcc4a327687..4409daffc2e 100644 --- a/packages/firestore/src/core/pipeline-util.ts +++ b/packages/firestore/src/core/pipeline-util.ts @@ -65,9 +65,9 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { } } else if (isNullValue(f.value)) { if (f.op === Operator.EQUAL) { - return and(fieldValue.exists(), fieldValue.eq(null)); + return and(fieldValue.exists(), fieldValue.isNull()); } else { - return and(fieldValue.exists(), fieldValue.neq(null)); + return and(fieldValue.exists(), fieldValue.isNotNull()); } } else { // Comparison filters @@ -113,7 +113,7 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { Constant._fromProto(val) ); if (!values) { - return fieldValue.exists(); + return and(fieldValue.exists(), fieldValue.eqAny([])); } else if (values.length === 1) { return and(fieldValue.exists(), fieldValue.eq(values[0])); } else { @@ -131,7 +131,7 @@ export function toPipelineBooleanExpr(f: FilterInternal): BooleanExpr { Constant._fromProto(val) ); if (!values) { - return fieldValue.exists(); + return and(fieldValue.exists(), fieldValue.notEqAny([])); } else if (values.length === 1) { return and(fieldValue.exists(), fieldValue.neq(values[0])); } else { @@ -215,13 +215,13 @@ export function toPipeline(query: Query, db: Firestore): Pipeline { // cursors if (query.startAt !== null) { pipeline = pipeline.where( - whereConditionsFromCursor(query.startAt, orderings, 'before') + whereConditionsFromCursor(query.startAt, orderings, 'after') ); } if (query.endAt !== null) { pipeline = pipeline.where( - whereConditionsFromCursor(query.endAt, orderings, 'after') + whereConditionsFromCursor(query.endAt, orderings, 'before') ); } @@ -265,7 +265,7 @@ function whereConditionsFromCursor( const conditions: BooleanExpr[] = cursorSubset.map((cursor, index) => { if (index < cursorSubset.length - 1) { return eq(orderings[index].expr as Field, cursor); - } else if (bound.inclusive && i === orderings.length) { + } else if (bound.inclusive && i === orderings.length - 1) { return filterInclusiveFunc(orderings[index].expr as Field, cursor); } else { return filterFunc(orderings[index].expr as Field, cursor); diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 8c97cc62a9a..377dfe5c063 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -1208,7 +1208,7 @@ export abstract class Expr implements ProtoValueSerializable, UserData { ...others: Array ): FunctionExpr { const values = [second, ...others]; - return new FunctionExpr('logical_min', [ + return new FunctionExpr('logical_minimum', [ this, ...values.map(valueToDefaultExpr) ]); @@ -1314,39 +1314,6 @@ export abstract class Expr implements ProtoValueSerializable, UserData { return new FunctionExpr('euclidean_distance', [this, vectorToExpr(other)]); } - /** - * @beta - * - * Calculates the Manhattan distance between the result of this expression and another VectorValue. - * - * ```typescript - * // Calculate the Manhattan distance between the 'location' field and a target location - * field("location").manhattanDistance(new VectorValue([37.7749, -122.4194])); - * ``` - * - * @param vector The other vector (as a VectorValue) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ - manhattanDistance(vector: VectorValue | number[]): FunctionExpr; - - /** - * @beta - * - * Calculates the Manhattan distance between two vector expressions. - * - * ```typescript - * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' - * field("pointA").manhattanDistance(field("pointB")); - * ``` - * - * @param vectorExpression The other vector (represented as an Expr) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ - manhattanDistance(vectorExpression: Expr): FunctionExpr; - manhattanDistance(other: Expr | number[] | VectorValue): FunctionExpr { - return new FunctionExpr('manhattan_distance', [this, vectorToExpr(other)]); - } - /** * Creates an expression that interprets this expression as the number of microseconds since the Unix epoch (1970-01-01 00:00:00 UTC) * and returns a timestamp. @@ -2281,8 +2248,6 @@ export function field(nameOrPath: string | FieldPath): Field { return new Field(documentIdFieldPath()._internalPath); } return new Field(fieldPathFromArgument('of', nameOrPath)); - } else if (documentIdFieldPath().isEqual(nameOrPath)) { - return new Field(documentIdFieldPath()._internalPath); } else { return new Field(nameOrPath._internalPath); } @@ -4611,6 +4576,21 @@ export function arrayContainsAll( return fieldOfOrExpr(array).arrayContainsAll(values); } +/** + * @beta + * + * Creates an expression that calculates the length of an array in a specified field. + * + * ```typescript + * // Get the number of items in field 'cart' + * arrayLength('cart'); + * ``` + * + * @param fieldName The name of the field containing an array to calculate the length of. + * @return A new {@code Expr} representing the length of the array. + */ +export function arrayLength(fieldName: string): FunctionExpr; + /** * @beta * @@ -4624,8 +4604,9 @@ export function arrayContainsAll( * @param array The array expression to calculate the length of. * @return A new {@code Expr} representing the length of the array. */ -export function arrayLength(array: Expr): FunctionExpr { - return array.arrayLength(); +export function arrayLength(array: Expr): FunctionExpr; +export function arrayLength(array: Expr | string): FunctionExpr { + return fieldOfOrExpr(array).arrayLength(); } /** @@ -5883,7 +5864,7 @@ export function strConcat( second: string | Expr, ...elements: Array ): FunctionExpr { - return valueToDefaultExpr(first).strConcat( + return fieldOfOrExpr(first).strConcat( valueToDefaultExpr(second), ...elements.map(valueToDefaultExpr) ); @@ -6366,91 +6347,6 @@ export function euclideanDistance( return expr1.euclideanDistance(expr2); } -/** - * @beta - * - * Calculates the Manhattan distance between a field's vector value and a double array. - * - * ```typescript - * // Calculate the Manhattan distance between the 'location' field and a target location - * manhattanDistance("location", [37.7749, -122.4194]); - * ``` - * - * @param fieldName The name of the field containing the first vector. - * @param vector The other vector (as an array of doubles or VectorValue) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ -export function manhattanDistance( - fieldName: string, - vector: number[] | VectorValue -): FunctionExpr; - -/** - * @beta - * - * Calculates the Manhattan distance between a field's vector value and a vector expression. - * - * ```typescript - * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' - * manhattanDistance("pointA", field("pointB")); - * ``` - * - * @param fieldName The name of the field containing the first vector. - * @param vectorExpression The other vector (represented as an Expr) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ -export function manhattanDistance( - fieldName: string, - vectorExpression: Expr -): FunctionExpr; - -/** - * @beta - * - * Calculates the Manhattan distance between a vector expression and a double array. - * - * ```typescript - * // Calculate the Manhattan distance between the 'location' field and a target location - * - * manhattanDistance(field("location"), [37.7749, -122.4194]); - * ``` - * - * @param vectorExpression The first vector (represented as an Expr) to compare against. - * @param vector The other vector (as an array of doubles or VectorValue) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ -export function manhattanDistance( - vectorExpression: Expr, - vector: number[] | VectorValue -): FunctionExpr; - -/** - * @beta - * - * Calculates the Manhattan distance between two vector expressions. - * - * ```typescript - * // Calculate the Manhattan distance between two vector fields: 'pointA' and 'pointB' - * manhattanDistance(field("pointA"), field("pointB")); - * ``` - * - * @param vectorExpression The first vector (represented as an Expr) to compare against. - * @param otherVectorExpression The other vector (represented as an Expr) to compare against. - * @return A new {@code Expr} representing the Manhattan distance between the two vectors. - */ -export function manhattanDistance( - vectorExpression: Expr, - otherVectorExpression: Expr -): FunctionExpr; -export function manhattanDistance( - fieldOrExpr: Expr | string, - other: Expr | number[] | VectorValue -): FunctionExpr { - const expr1 = fieldOfOrExpr(fieldOrExpr); - const expr2 = vectorToExpr(other); - return expr1.manhattanDistance(expr2); -} - /** * @beta * diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index 299e5b89a93..4d4b391c592 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -812,10 +812,9 @@ export class Pipeline implements ProtoSerializable { if (typeof selectable === 'string') { result.set(selectable as string, field(selectable)); } else if (selectable instanceof Field) { - result.set((selectable as Field).fieldName(), selectable); + result.set(selectable.alias, selectable.expr); } else if (selectable instanceof ExprWithAlias) { - const expr = selectable as ExprWithAlias; - result.set(expr.alias, expr.expr); + result.set(selectable.alias, selectable.expr); } } return result; diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index 7e29f2b0aaa..ba4d2df148c 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -464,7 +464,7 @@ export class Unnest implements Stage { * @beta */ export class Replace implements Stage { - name = 'replace'; + name = 'replace_with'; constructor( private field: Field, diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 7e5b329a982..6a3a34a0730 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -22,12 +22,14 @@ import { AggregateFunction, ascending, BooleanExpr, + byteLength, constantVector, FunctionExpr, timestampAdd, timestampToUnixMicros, timestampToUnixMillis, timestampToUnixSeconds, + toLower, unixMicrosToTimestamp, unixMillisToTimestamp, vectorLength @@ -53,15 +55,20 @@ import { writeBatch, addDoc } from '../util/firebase_export'; -import { apiDescribe, withTestCollection } from '../util/helpers'; +import { apiDescribe, withTestCollection, itIf } from '../util/helpers'; import { array, mod, + pipelineResultEqual, + sum, + replaceFirst, + replaceAll, descending, isNan, map, execute, add, + arrayContainsAll, unixSecondsToTimestamp, and, arrayContains, @@ -69,17 +76,21 @@ import { count, avg, cosineDistance, + not, countAll, dotProduct, endsWith, eq, reverse, + toUpper, euclideanDistance, gt, like, lt, strContains, + divide, lte, + arrayLength, arrayConcat, mapGet, neq, @@ -87,6 +98,7 @@ import { regexContains, regexMatch, startsWith, + strConcat, subtract, cond, eqAny, @@ -100,6 +112,7 @@ import { bitNot, exists, bitLeftShift, + charLength, bitRightShift, rand, arrayOffset, @@ -108,6 +121,7 @@ import { currentContext, isError, ifError, + trim, isAbsent, isNull, isNotNull, @@ -117,7 +131,6 @@ import { mapMerge, documentId, substr, - manhattanDistance, logicalMinimum, xor, field, @@ -130,6 +143,8 @@ use(chaiAsPromised); setLogLevel('debug'); +const testUnsupportedFeatures = false; + apiDescribe.only('Pipelines', persistence => { addEqualityMatcher(); @@ -138,6 +153,8 @@ apiDescribe.only('Pipelines', persistence => { let beginDocCreation: number = 0; let endDocCreation: number = 0; + const timestampDeltaMS = 1000; + async function testCollectionWithDocs(docs: { [id: string]: DocumentData; }): Promise> { @@ -326,8 +343,12 @@ apiDescribe.only('Pipelines', persistence => { expect(snapshot.results.length).to.equal(0); }); - it('full snapshot as expected', async () => { - const ppl = firestore.pipeline().collection(randomCol.path); + // Skipping because __name__ is not currently working in DBE + itIf(testUnsupportedFeatures)('full snapshot as expected', async () => { + const ppl = firestore + .pipeline() + .collection(randomCol.path) + .sort(ascending('__name__')); const snapshot = await execute(ppl); expect(snapshot.results.length).to.equal(10); expect(snapshot.pipeline).to.equal(ppl); @@ -346,6 +367,20 @@ apiDescribe.only('Pipelines', persistence => { ); }); + it('result equals works', async () => { + const ppl = firestore + .pipeline() + .collection(randomCol.path) + .sort(ascending('title')) + .limit(1); + const snapshot1 = await execute(ppl); + const snapshot2 = await execute(ppl); + expect(snapshot1.results.length).to.equal(1); + expect(snapshot2.results.length).to.equal(1); + expect(pipelineResultEqual(snapshot1.results[0], snapshot2.results[0])).to + .be.true; + }); + it('returns execution time', async () => { const start = new Date().valueOf(); const pipeline = firestore.pipeline().collection(randomCol.path); @@ -355,7 +390,7 @@ apiDescribe.only('Pipelines', persistence => { expect(snapshot.executionTime.toDate().valueOf()).to.approximately( (start + end) / 2, - end - start + timestampDeltaMS ); }); @@ -370,7 +405,7 @@ apiDescribe.only('Pipelines', persistence => { expect(snapshot.executionTime.toDate().valueOf()).to.approximately( (start + end) / 2, - end - start + timestampDeltaMS ); }); @@ -385,11 +420,11 @@ apiDescribe.only('Pipelines', persistence => { expect(doc.createTime!.toDate().valueOf()).to.approximately( (beginDocCreation + endDocCreation) / 2, - endDocCreation - beginDocCreation + timestampDeltaMS ); expect(doc.updateTime!.toDate().valueOf()).to.approximately( (beginDocCreation + endDocCreation) / 2, - endDocCreation - beginDocCreation + timestampDeltaMS ); expect(doc.createTime?.valueOf()).to.equal(doc.updateTime?.valueOf()); }); @@ -425,7 +460,7 @@ apiDescribe.only('Pipelines', persistence => { expect(snapshot.executionTime.toDate().valueOf()).to.approximately( (start + end) / 2, - end - start + timestampDeltaMS ); }); @@ -492,26 +527,31 @@ apiDescribe.only('Pipelines', persistence => { await terminate(db2); }); - it('supports collection group as source', async () => { - const randomSubCollectionId = Math.random().toString(16).slice(2); - const doc1 = await addDoc( - collection(randomCol, 'book1', randomSubCollectionId), - { order: 1 } - ); - const doc2 = await addDoc( - collection(randomCol, 'book2', randomSubCollectionId), - { order: 2 } - ); - const snapshot = await execute( - firestore - .pipeline() - .collectionGroup(randomSubCollectionId) - .sort(ascending('order')) - ); - expectResults(snapshot, doc1.id, doc2.id); - }); + // Subcollections not currently supported in DBE + itIf(testUnsupportedFeatures)( + 'supports collection group as source', + async () => { + const randomSubCollectionId = Math.random().toString(16).slice(2); + const doc1 = await addDoc( + collection(randomCol, 'book1', randomSubCollectionId), + { order: 1 } + ); + const doc2 = await addDoc( + collection(randomCol, 'book2', randomSubCollectionId), + { order: 2 } + ); + const snapshot = await execute( + firestore + .pipeline() + .collectionGroup(randomSubCollectionId) + .sort(ascending('order')) + ); + expectResults(snapshot, doc1.id, doc2.id); + } + ); - it('supports database as source', async () => { + // subcollections not currently supported in dbe + itIf(testUnsupportedFeatures)('supports database as source', async () => { const randomId = Math.random().toString(16).slice(2); const doc1 = await addDoc(collection(randomCol, 'book1', 'sub'), { order: 1, @@ -654,11 +694,11 @@ apiDescribe.only('Pipelines', persistence => { .select( map({ 'number': 1, - 'undefined': array([undefined]) + undefined }).as('foo') ); }).to.throw( - 'Function constant() called with invalid data. Unsupported field value: undefined' + 'Function map() called with invalid data. Unsupported field value: undefined' ); }); @@ -670,7 +710,7 @@ apiDescribe.only('Pipelines', persistence => { .limit(1) .select(array([1, undefined]).as('foo')); }).to.throw( - 'Function constant() called with invalid data. Unsupported field value: undefined' + 'Function array() called with invalid data. Unsupported field value: undefined' ); }); @@ -785,10 +825,16 @@ apiDescribe.only('Pipelines', persistence => { .aggregate( countAll().as('count'), avg('rating').as('avgRating'), - field('rating').maximum().as('maxRating') + maximum('rating').as('maxRating'), + sum('rating').as('sumRating') ) ); - expectResults(snapshot, { count: 2, avgRating: 4.4, maxRating: 4.6 }); + expectResults(snapshot, { + count: 2, + avgRating: 4.4, + maxRating: 4.6, + sumRating: 8.8 + }); }); it('rejects groups without accumulators', async () => { @@ -1062,14 +1108,15 @@ apiDescribe.only('Pipelines', persistence => { eq('genre', 'Fantasy') ) ) + .sort(ascending('title')) .select('title') ); expectResults( snapshot, + { title: '1984' }, { title: 'Pride and Prejudice' }, - { title: 'The Lord of the Rings' }, { title: "The Handmaid's Tale" }, - { title: '1984' } + { title: 'The Lord of the Rings' } ); }); @@ -1135,10 +1182,10 @@ apiDescribe.only('Pipelines', persistence => { .limit(1) ); expectResults(snapshot, { - title: "The Hitchhiker's Guide to the Galaxy", metadata: { - author: 'Douglas Adams' - } + author: 'Frank Herbert' + }, + title: 'Dune' }); }); @@ -1152,7 +1199,7 @@ apiDescribe.only('Pipelines', persistence => { .select('title', 'author') .genericStage('add_fields', [ { - display: field('title').strConcat(' - ', field('author')) + display: strConcat('title', ' - ', field('author')) } ]) ); @@ -1304,7 +1351,8 @@ apiDescribe.only('Pipelines', persistence => { }); describe('union stage', () => { - it('run pipeline with union', async () => { + // __name__ not currently supported by dbe + itIf(testUnsupportedFeatures)('run pipeline with union', async () => { const snapshot = await execute( firestore .pipeline() @@ -1616,6 +1664,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .where(eqAny('published', [1979, 1999, 1967])) + .sort(descending('title')) .select('title') ); expectResults( @@ -1660,6 +1709,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .where(arrayContainsAny('tags', ['comedy', 'classic'])) + .sort(descending('title')) .select('title') ); expectResults( @@ -1674,7 +1724,7 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) - .where(field('tags').arrayContainsAll(['adventure', 'magic'])) + .where(arrayContainsAll('tags', ['adventure', 'magic'])) .select('title') ); expectResults(snapshot, { title: 'The Lord of the Rings' }); @@ -1685,7 +1735,7 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) - .select(field('tags').arrayLength().as('tagsCount')) + .select(arrayLength('tags').as('tagsCount')) .where(eq('tagsCount', 3)) ); expect(snapshot.results.length).to.equal(10); @@ -1696,6 +1746,7 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) + .sort(ascending('author')) .select( field('author').strConcat(' - ', field('title')).as('bookInfo') ) @@ -1761,7 +1812,7 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) - .select(field('title').charLength().as('titleLength'), field('title')) + .select(charLength('title').as('titleLength'), field('title')) .where(gt('titleLength', 20)) .sort(field('title').ascending()) ); @@ -1826,11 +1877,12 @@ apiDescribe.only('Pipelines', persistence => { firestore .pipeline() .collection(randomCol.path) + .where(eq('title', 'To Kill a Mockingbird')) .select( add(field('rating'), 1).as('ratingPlusOne'), subtract(field('published'), 1900).as('yearsSince1900'), field('rating').multiply(10).as('ratingTimesTen'), - field('rating').divide(2).as('ratingDividedByTwo'), + divide('rating', 2).as('ratingDividedByTwo'), multiply('rating', 10, 2).as('ratingTimes20'), add('rating', 1, 2).as('ratingPlus3'), mod('rating', 2).as('ratingMod2') @@ -1839,12 +1891,12 @@ apiDescribe.only('Pipelines', persistence => { ); expectResults(snapshot, { ratingPlusOne: 5.2, - yearsSince1900: 79, + yearsSince1900: 60, ratingTimesTen: 42, ratingDividedByTwo: 2.1, ratingTimes20: 84, ratingPlus3: 7.2, - ratingMod2: 0.2 + ratingMod2: 0.20000000000000018 }); }); @@ -1914,7 +1966,7 @@ apiDescribe.only('Pipelines', persistence => { isNotNull('title').as('titleIsNotNull'), isNotNan('cost').as('costIsNotNan'), exists('fooBarBaz').as('fooBarBazExists'), - field('title').as('titleExists') + field('title').exists().as('titleExists') ) ); expectResults(snapshot, { @@ -1998,9 +2050,6 @@ apiDescribe.only('Pipelines', persistence => { ), euclideanDistance(constantVector(sourceVector), targetVector).as( 'euclideanDistance' - ), - manhattanDistance(constantVector(sourceVector), targetVector).as( - 'manhattanDistance' ) ) .limit(1) @@ -2009,8 +2058,7 @@ apiDescribe.only('Pipelines', persistence => { expectResults(snapshot, { cosineDistance: 0.02560880430538015, dotProductDistance: 0.13, - euclideanDistance: 0.806225774829855, - manhattanDistance: 1.1 + euclideanDistance: 0.806225774829855 }); snapshot = await execute( @@ -2026,10 +2074,7 @@ apiDescribe.only('Pipelines', persistence => { .as('dotProductDistance'), constantVector(sourceVector) .euclideanDistance(targetVector) - .as('euclideanDistance'), - constantVector(sourceVector) - .manhattanDistance(targetVector) - .as('manhattanDistance') + .as('euclideanDistance') ) .limit(1) ); @@ -2037,8 +2082,7 @@ apiDescribe.only('Pipelines', persistence => { expectResults(snapshot, { cosineDistance: 0.02560880430538015, dotProductDistance: 0.13, - euclideanDistance: 0.806225774829855, - manhattanDistance: 1.1 + euclideanDistance: 0.806225774829855 }); }); @@ -2061,6 +2105,7 @@ apiDescribe.only('Pipelines', persistence => { .pipeline() .collection(randomCol.path) .where(eq('awards.hugo', true)) + .sort(descending('title')) .select('title', 'awards.hugo') ); expectResults( @@ -2084,6 +2129,7 @@ apiDescribe.only('Pipelines', persistence => { field('nestedField.level.1'), mapGet('nestedField', 'level.1').mapGet('level.2').as('nested') ) + .sort(descending('title')) ); expectResults( snapshot, @@ -2195,429 +2241,124 @@ apiDescribe.only('Pipelines', persistence => { }); }); - describe('not implemented in backend', () => { - it('supports Bit_and', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select(bitAnd(constant(5), 12).as('result')) - ); - expectResults(snapshot, { - result: 4 - }); - }); + itIf(testUnsupportedFeatures)('testReplaceFirst', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eq('title', 'The Lord of the Rings')) + .limit(1) + .select(replaceFirst('title', 'o', '0').as('newName')) + ); + expectResults(snapshot, { newName: 'The L0rd of the Rings' }); + }); - it('supports Bit_and', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select(constant(5).bitAnd(12).as('result')) - ); - expectResults(snapshot, { - result: 4 - }); - }); + itIf(testUnsupportedFeatures)('testReplaceAll', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eq('title', 'The Lord of the Rings')) + .limit(1) + .select(replaceAll('title', 'o', '0').as('newName')) + ); + expectResults(snapshot, { newName: 'The L0rd 0f the Rings' }); + }); - it('supports Bit_or', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select(bitOr(constant(5), 12).as('result')) - ); - expectResults(snapshot, { - result: 13 - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select(constant(5).bitOr(12).as('result')) - ); - expectResults(snapshot, { - result: 13 - }); + it('supports Rand', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(10) + .select(rand().as('result')) + ); + expect(snapshot.results.length).to.equal(10); + snapshot.results.forEach(d => { + expect(d.get('result')).to.be.lt(1); + expect(d.get('result')).to.be.gte(0); }); + }); - it('supports Bit_xor', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select(bitXor(constant(5), 12).as('result')) - ); - expectResults(snapshot, { - result: 9 - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select(constant(5).bitXor(12).as('result')) - ); - expectResults(snapshot, { - result: 9 - }); + it('supports array', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(array([1, 2, 3, 4]).as('metadata')) + ); + expect(snapshot.results.length).to.equal(1); + expectResults(snapshot, { + metadata: [1, 2, 3, 4] }); + }); - it('supports Bit_not', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select( - bitNot(constant(Bytes.fromUint8Array(Uint8Array.of(0xfd)))).as( - 'result' - ) - ) - ); - expectResults(snapshot, { - result: Bytes.fromUint8Array(Uint8Array.of(0x02)) - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select( - constant(Bytes.fromUint8Array(Uint8Array.of(0xfd))) - .bitNot() - .as('result') - ) - ); - expectResults(snapshot, { - result: Bytes.fromUint8Array(Uint8Array.of(0x02)) - }); + it('evaluates expression in array', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select( + array([1, 2, field('genre'), multiply('rating', 10)]).as('metadata') + ) + ); + expect(snapshot.results.length).to.equal(1); + expectResults(snapshot, { + metadata: [1, 2, 'Fantasy', 47] }); + }); - it('supports Bit_left_shift', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select( - bitLeftShift( - constant(Bytes.fromUint8Array(Uint8Array.of(0x02))), - 2 - ).as('result') - ) - ); - expectResults(snapshot, { - result: Bytes.fromUint8Array(Uint8Array.of(0x04)) - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select( - constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) - .bitLeftShift(2) - .as('result') - ) - ); - expectResults(snapshot, { - result: Bytes.fromUint8Array(Uint8Array.of(0x04)) - }); - }); + it('supports arrayOffset', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(arrayOffset('tags', 0).as('firstTag')) + ); + const expectedResults = [ + { + firstTag: 'adventure' + }, + { + firstTag: 'politics' + }, + { + firstTag: 'classic' + } + ]; + expectResults(snapshot, ...expectedResults); - it('supports Bit_right_shift', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select( - bitRightShift( - constant(Bytes.fromUint8Array(Uint8Array.of(0x02))), - 2 - ).as('result') - ) - ); - expectResults(snapshot, { - result: Bytes.fromUint8Array(Uint8Array.of(0x01)) - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(1) - .select( - constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) - .bitRightShift(2) - .as('result') - ) - ); - expectResults(snapshot, { - result: Bytes.fromUint8Array(Uint8Array.of(0x01)) - }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(3) + .select(field('tags').arrayOffset(0).as('firstTag')) + ); + expectResults(snapshot, ...expectedResults); + }); + + // TODO: current_context tests with are failing because of b/395937453 + itIf(testUnsupportedFeatures)('supports currentContext', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(currentContext().as('currentContext')) + ); + expectResults(snapshot, { + currentContext: 'TODO' }); - - it('supports Document_id', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(documentId(field('__path__')).as('docId')) - ); - expectResults(snapshot, { - docId: 'book4' - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(field('__path__').documentId().as('docId')) - ); - expectResults(snapshot, { - docId: 'book4' - }); - }); - - it('supports Substr', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(substr('title', 9, 2).as('of')) - ); - expectResults(snapshot, { - of: 'of' - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(field('title').substr(9, 2).as('of')) - ); - expectResults(snapshot, { - of: 'of' - }); - }); - - it('supports Substr without length', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(substr('title', 9).as('of')) - ); - expectResults(snapshot, { - of: 'of the Rings' - }); - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(field('title').substr(9).as('of')) - ); - expectResults(snapshot, { - of: 'of the Rings' - }); - }); - - it('arrayConcat works', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .select( - arrayConcat('tags', ['newTag1', 'newTag2'], field('tags'), [ - null - ]).as('modifiedTags') - ) - .limit(1) - ); - expectResults(snapshot, { - modifiedTags: [ - 'comedy', - 'space', - 'adventure', - 'newTag1', - 'newTag2', - 'comedy', - 'space', - 'adventure', - null - ] - }); - }); - - it('testToLowercase', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .select(field('title').toLower().as('lowercaseTitle')) - .limit(1) - ); - expectResults(snapshot, { - lowercaseTitle: "the hitchhiker's guide to the galaxy" - }); - }); - - it('testToUppercase', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .select(field('author').toUpper().as('uppercaseAuthor')) - .limit(1) - ); - expectResults(snapshot, { uppercaseAuthor: 'DOUGLAS ADAMS' }); - }); - - it('testTrim', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .addFields( - constant(" The Hitchhiker's Guide to the Galaxy ").as( - 'spacedTitle' - ) - ) - .select( - field('spacedTitle').trim().as('trimmedTitle'), - field('spacedTitle') - ) - .limit(1) - ); - expectResults(snapshot, { - spacedTitle: " The Hitchhiker's Guide to the Galaxy ", - trimmedTitle: "The Hitchhiker's Guide to the Galaxy" - }); - }); - - it('test reverse', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .where(eq('title', '1984')) - .limit(1) - .select(reverse('title').as('reverseTitle')) - ); - expectResults(snapshot, { title: '4891' }); - }); - }); - - it('supports Rand', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .limit(10) - .select(rand().as('result')) - ); - expect(snapshot.results.length).to.equal(10); - snapshot.results.forEach(d => { - expect(d.get('result')).to.be.lt(1); - expect(d.get('result')).to.be.gte(0); - }); - }); - - it('supports array', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(array([1, 2, 3, 4]).as('metadata')) - ); - expect(snapshot.results.length).to.equal(1); - expectResults(snapshot, { - metadata: [1, 2, 3, 4] - }); - }); - - it('evaluates expression in array', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select( - array([1, 2, field('genre'), multiply('rating', 10)]).as('metadata') - ) - ); - expect(snapshot.results.length).to.equal(1); - expectResults(snapshot, { - metadata: [1, 2, 'Fantasy', 47] - }); - }); - - it('supports arrayOffset', async () => { - let snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(3) - .select(arrayOffset('tags', 0).as('firstTag')) - ); - const expectedResults = [ - { - firstTag: 'adventure' - }, - { - firstTag: 'politics' - }, - { - firstTag: 'classic' - } - ]; - expectResults(snapshot, ...expectedResults); - - snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(3) - .select(field('tags').arrayOffset(0).as('firstTag')) - ); - expectResults(snapshot, ...expectedResults); - }); - - // TODO: current_context tests with are failing because of b/395937453 - it('supports currentContext', async () => { - const snapshot = await execute( - firestore - .pipeline() - .collection(randomCol.path) - .sort(field('rating').descending()) - .limit(1) - .select(currentContext().as('currentContext')) - ); - expectResults(snapshot, { - currentContext: 'TODO' - }); - }); + }); it('supports map', async () => { const snapshot = await execute( @@ -2789,150 +2530,520 @@ apiDescribe.only('Pipelines', persistence => { minus10millis: new Timestamp(1741380234, 990000000) }); }); - }); - describe('pagination', () => { - /** - * Adds several books to the test collection. These - * additional books support pagination test scenarios - * that would otherwise not be possible with the original - * set of books. - * @param collectionReference - */ - async function addBooks( - collectionReference: CollectionReference - ): Promise { - await setDoc(doc(collectionReference, 'book11'), { - title: 'Jonathan Strange & Mr Norrell', - author: 'Susanna Clarke', - genre: 'Fantasy', - published: 2004, - rating: 4.6, - tags: ['historical fantasy', 'magic', 'alternate history', 'england'], - awards: { hugo: false, nebula: false } + it('supports byteLength', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol) + .limit(1) + .select( + constant( + Bytes.fromUint8Array(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 0])) + ).as('bytes') + ) + .select(byteLength('bytes').as('byteLength')) + ); + + expectResults(snapshot, { + byteLength: 8 }); - await setDoc(doc(collectionReference, 'book12'), { - title: 'The Master and Margarita', - author: 'Mikhail Bulgakov', - genre: 'Satire', - published: 1967, // Though written much earlier - rating: 4.6, - tags: [ - 'russian literature', - 'supernatural', - 'philosophy', - 'dark comedy' - ], - awards: {} + }); + + it('supports not', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol) + .limit(1) + .select(constant(true).as('trueField')) + .select('trueField', not(eq('trueField', true)).as('falseField')) + ); + + expectResults(snapshot, { + trueField: true, + falseField: false }); - await setDoc(doc(collectionReference, 'book13'), { - title: 'A Long Way to a Small, Angry Planet', - author: 'Becky Chambers', - genre: 'Science Fiction', - published: 2014, - rating: 4.6, - tags: ['space opera', 'found family', 'character-driven', 'optimistic'], - awards: { hugo: false, nebula: false, kitschies: true } - }); - } + }); + }); - it('supports pagination with filters', async () => { - await addBooks(randomCol); - const pageSize = 2; - const pipeline = firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'rating', '__name__') - .sort(field('rating').descending(), field('__name__').ascending()); + describe('not yet implemented in backend', () => { + itIf(testUnsupportedFeatures)('supports Bit_and', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(bitAnd(constant(5), 12).as('result')) + ); + expectResults(snapshot, { + result: 4 + }); + }); - let snapshot = await execute(pipeline.limit(pageSize)); - expectResults( - snapshot, - { title: 'The Lord of the Rings', rating: 4.7 }, - { title: 'Jonathan Strange & Mr Norrell', rating: 4.6 } + itIf(testUnsupportedFeatures)('supports Bit_and', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constant(5).bitAnd(12).as('result')) ); + expectResults(snapshot, { + result: 4 + }); + }); - const lastDoc = snapshot.results[snapshot.results.length - 1]; + itIf(testUnsupportedFeatures)('supports Bit_or', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(bitOr(constant(5), 12).as('result')) + ); + expectResults(snapshot, { + result: 13 + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constant(5).bitOr(12).as('result')) + ); + expectResults(snapshot, { + result: 13 + }); + }); + itIf(testUnsupportedFeatures)('supports Bit_xor', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(bitXor(constant(5), 12).as('result')) + ); + expectResults(snapshot, { + result: 9 + }); snapshot = await execute( - pipeline - .where( - or( - and( - field('rating').eq(lastDoc.get('rating')), - field('__path__').gt(lastDoc.ref?.id) - ), - field('rating').lt(lastDoc.get('rating')) + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select(constant(5).bitXor(12).as('result')) + ); + expectResults(snapshot, { + result: 9 + }); + }); + + itIf(testUnsupportedFeatures)('supports Bit_not', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + bitNot(constant(Bytes.fromUint8Array(Uint8Array.of(0xfd)))).as( + 'result' ) ) - .limit(pageSize) ); - expectResults( - snapshot, - { title: 'Pride and Prejudice', rating: 4.5 }, - { title: 'Crime and Punishment', rating: 4.3 } + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x02)) + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + constant(Bytes.fromUint8Array(Uint8Array.of(0xfd))) + .bitNot() + .as('result') + ) ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x02)) + }); }); - it('supports pagination with offsets', async () => { - await addBooks(randomCol); - - const secondFilterField = '__path__'; + itIf(testUnsupportedFeatures)('supports Bit_left_shift', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + bitLeftShift( + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x04)) + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) + .bitLeftShift(2) + .as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x04)) + }); + }); - const pipeline = firestore - .pipeline() - .collection(randomCol.path) - .select('title', 'rating', secondFilterField) - .sort( - field('rating').descending(), - field(secondFilterField).ascending() - ); + itIf(testUnsupportedFeatures)('supports Bit_right_shift', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + bitRightShift( + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))), + 2 + ).as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x01)) + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .limit(1) + .select( + constant(Bytes.fromUint8Array(Uint8Array.of(0x02))) + .bitRightShift(2) + .as('result') + ) + ); + expectResults(snapshot, { + result: Bytes.fromUint8Array(Uint8Array.of(0x01)) + }); + }); - const pageSize = 2; - let currPage = 0; + itIf(testUnsupportedFeatures)('supports Document_id', async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(documentId(field('__path__')).as('docId')) + ); + expectResults(snapshot, { + docId: 'book4' + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('__path__').documentId().as('docId')) + ); + expectResults(snapshot, { + docId: 'book4' + }); + }); + itIf(testUnsupportedFeatures)('supports Substr', async () => { let snapshot = await execute( - pipeline.offset(currPage++ * pageSize).limit(pageSize) + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(substr('title', 9, 2).as('of')) ); + expectResults(snapshot, { + of: 'of' + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('title').substr(9, 2).as('of')) + ); + expectResults(snapshot, { + of: 'of' + }); + }); - expectResults( - snapshot, - { - title: 'The Lord of the Rings', - rating: 4.7 - }, - { title: 'Dune', rating: 4.6 } + itIf(testUnsupportedFeatures)( + 'supports Substr without length', + async () => { + let snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(substr('title', 9).as('of')) + ); + expectResults(snapshot, { + of: 'of the Rings' + }); + snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .sort(field('rating').descending()) + .limit(1) + .select(field('title').substr(9).as('of')) + ); + expectResults(snapshot, { + of: 'of the Rings' + }); + } + ); + + itIf(testUnsupportedFeatures)('arrayConcat works', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select( + arrayConcat('tags', ['newTag1', 'newTag2'], field('tags'), [ + null + ]).as('modifiedTags') + ) + .limit(1) ); + expectResults(snapshot, { + modifiedTags: [ + 'comedy', + 'space', + 'adventure', + 'newTag1', + 'newTag2', + 'comedy', + 'space', + 'adventure', + null + ] + }); + }); - snapshot = await execute( - pipeline.offset(currPage++ * pageSize).limit(pageSize) + itIf(testUnsupportedFeatures)('testToLowercase', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select(toLower('title').as('lowercaseTitle')) + .limit(1) ); - expectResults( - snapshot, - { - title: 'Jonathan Strange & Mr Norrell', - rating: 4.6 - }, - { title: 'The Master and Margarita', rating: 4.6 } + expectResults(snapshot, { + lowercaseTitle: "the hitchhiker's guide to the galaxy" + }); + }); + + itIf(testUnsupportedFeatures)('testToUppercase', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .select(toUpper('author').as('uppercaseAuthor')) + .limit(1) ); + expectResults(snapshot, { uppercaseAuthor: 'DOUGLAS ADAMS' }); + }); - snapshot = await execute( - pipeline.offset(currPage++ * pageSize).limit(pageSize) + itIf(testUnsupportedFeatures)('testTrim', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .addFields( + constant(" The Hitchhiker's Guide to the Galaxy ").as('spacedTitle') + ) + .select(trim('spacedTitle').as('trimmedTitle'), field('spacedTitle')) + .limit(1) ); - expectResults( - snapshot, - { - title: 'A Long Way to a Small, Angry Planet', - rating: 4.6 - }, - { - title: 'Pride and Prejudice', - rating: 4.5 - } + expectResults(snapshot, { + spacedTitle: " The Hitchhiker's Guide to the Galaxy ", + trimmedTitle: "The Hitchhiker's Guide to the Galaxy" + }); + }); + + itIf(testUnsupportedFeatures)('test reverse', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eq('title', '1984')) + .limit(1) + .select(reverse('title').as('reverseTitle')) ); + expectResults(snapshot, { title: '4891' }); }); }); + describe('pagination', () => { + /** + * Adds several books to the test collection. These + * additional books support pagination test scenarios + * that would otherwise not be possible with the original + * set of books. + * @param collectionReference + */ + async function addBooks( + collectionReference: CollectionReference + ): Promise { + await setDoc(doc(collectionReference, 'book11'), { + title: 'Jonathan Strange & Mr Norrell', + author: 'Susanna Clarke', + genre: 'Fantasy', + published: 2004, + rating: 4.6, + tags: ['historical fantasy', 'magic', 'alternate history', 'england'], + awards: { hugo: false, nebula: false } + }); + await setDoc(doc(collectionReference, 'book12'), { + title: 'The Master and Margarita', + author: 'Mikhail Bulgakov', + genre: 'Satire', + published: 1967, // Though written much earlier + rating: 4.6, + tags: [ + 'russian literature', + 'supernatural', + 'philosophy', + 'dark comedy' + ], + awards: {} + }); + await setDoc(doc(collectionReference, 'book13'), { + title: 'A Long Way to a Small, Angry Planet', + author: 'Becky Chambers', + genre: 'Science Fiction', + published: 2014, + rating: 4.6, + tags: ['space opera', 'found family', 'character-driven', 'optimistic'], + awards: { hugo: false, nebula: false, kitschies: true } + }); + } + + // sort on __name__ is not working + itIf(testUnsupportedFeatures)( + 'supports pagination with filters', + async () => { + await addBooks(randomCol); + const pageSize = 2; + const pipeline = firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'rating', '__name__') + .sort(field('rating').descending(), field('__name__').ascending()); + + let snapshot = await execute(pipeline.limit(pageSize)); + expectResults( + snapshot, + { title: 'The Lord of the Rings', rating: 4.7 }, + { title: 'Jonathan Strange & Mr Norrell', rating: 4.6 } + ); + + const lastDoc = snapshot.results[snapshot.results.length - 1]; + + snapshot = await execute( + pipeline + .where( + or( + and( + field('rating').eq(lastDoc.get('rating')), + field('__path__').gt(lastDoc.ref?.id) + ), + field('rating').lt(lastDoc.get('rating')) + ) + ) + .limit(pageSize) + ); + expectResults( + snapshot, + { title: 'Pride and Prejudice', rating: 4.5 }, + { title: 'Crime and Punishment', rating: 4.3 } + ); + } + ); + + // sort on __name__ is not working + itIf(testUnsupportedFeatures)( + 'supports pagination with offsets', + async () => { + await addBooks(randomCol); + + const secondFilterField = '__path__'; + + const pipeline = firestore + .pipeline() + .collection(randomCol.path) + .select('title', 'rating', secondFilterField) + .sort( + field('rating').descending(), + field(secondFilterField).ascending() + ); + + const pageSize = 2; + let currPage = 0; + + let snapshot = await execute( + pipeline.offset(currPage++ * pageSize).limit(pageSize) + ); + + expectResults( + snapshot, + { + title: 'The Lord of the Rings', + rating: 4.7 + }, + { title: 'Dune', rating: 4.6 } + ); + + snapshot = await execute( + pipeline.offset(currPage++ * pageSize).limit(pageSize) + ); + expectResults( + snapshot, + { + title: 'Jonathan Strange & Mr Norrell', + rating: 4.6 + }, + { title: 'The Master and Margarita', rating: 4.6 } + ); + + snapshot = await execute( + pipeline.offset(currPage++ * pageSize).limit(pageSize) + ); + expectResults( + snapshot, + { + title: 'A Long Way to a Small, Angry Planet', + rating: 4.6 + }, + { + title: 'Pride and Prejudice', + rating: 4.5 + } + ); + } + ); + }); + describe('console support', () => { it('supports internal serialization to proto', async () => { const pipeline = firestore diff --git a/packages/firestore/test/integration/api/query_to_pipeline.test.ts b/packages/firestore/test/integration/api/query_to_pipeline.test.ts index 99aa6771143..8eac50a5afa 100644 --- a/packages/firestore/test/integration/api/query_to_pipeline.test.ts +++ b/packages/firestore/test/integration/api/query_to_pipeline.test.ts @@ -40,12 +40,14 @@ import { and, documentId, addDoc, - getDoc + getDoc, + or } from '../util/firebase_export'; import { apiDescribe, PERSISTENCE_MODE_UNSPECIFIED, - withTestCollection + withTestCollection, + itIf } from '../util/helpers'; import { execute } from '../util/pipeline_export'; @@ -53,6 +55,8 @@ use(chaiAsPromised); setLogLevel('debug'); +const testUnsupportedFeatures = false; + // This is the Query integration tests from the lite API (no cache support) // with some additional test cases added for more complete coverage. apiDescribe.only('Query to Pipeline', persistence => { @@ -202,140 +206,189 @@ apiDescribe.only('Query to Pipeline', persistence => { ); }); - it('supports startAfter (with DocumentReference)', () => { + it('supports startAt with limitToLast', () => { return withTestCollection( PERSISTENCE_MODE_UNSPECIFIED, { - 1: { id: 1, foo: 1, bar: 1, baz: 1 }, - 2: { id: 2, foo: 1, bar: 1, baz: 2 }, - 3: { id: 3, foo: 1, bar: 1, baz: 2 }, - 4: { id: 4, foo: 1, bar: 2, baz: 1 }, - 5: { id: 5, foo: 1, bar: 2, baz: 2 }, - 6: { id: 6, foo: 1, bar: 2, baz: 2 }, - 7: { id: 7, foo: 2, bar: 1, baz: 1 }, - 8: { id: 8, foo: 2, bar: 1, baz: 2 }, - 9: { id: 9, foo: 2, bar: 1, baz: 2 }, - 10: { id: 10, foo: 2, bar: 2, baz: 1 }, - 11: { id: 11, foo: 2, bar: 2, baz: 2 }, - 12: { id: 12, foo: 2, bar: 2, baz: 2 } + 1: { foo: 1 }, + 2: { foo: 2 }, + 3: { foo: 3 }, + 4: { foo: 4 }, + 5: { foo: 5 } }, async (collRef, db) => { - let docRef = await getDoc(doc(collRef, '2')); - let query1 = query( - collRef, - orderBy('foo'), - orderBy('bar'), - orderBy('baz'), - startAfter(docRef) - ); - let snapshot = await execute(db.pipeline().createFrom(query1)); - verifyResults( - snapshot, - { id: 3, foo: 1, bar: 1, baz: 2 }, - { id: 4, foo: 1, bar: 2, baz: 1 }, - { id: 5, foo: 1, bar: 2, baz: 2 }, - { id: 6, foo: 1, bar: 2, baz: 2 }, - { id: 7, foo: 2, bar: 1, baz: 1 }, - { id: 8, foo: 2, bar: 1, baz: 2 }, - { id: 9, foo: 2, bar: 1, baz: 2 }, - { id: 10, foo: 2, bar: 2, baz: 1 }, - { id: 11, foo: 2, bar: 2, baz: 2 }, - { id: 12, foo: 2, bar: 2, baz: 2 } - ); - - docRef = await getDoc(doc(collRef, '3')); - query1 = query( + const query1 = query( collRef, orderBy('foo'), - orderBy('bar'), - orderBy('baz'), - startAfter(docRef) - ); - snapshot = await execute(db.pipeline().createFrom(query1)); - verifyResults( - snapshot, - { id: 4, foo: 1, bar: 2, baz: 1 }, - { id: 5, foo: 1, bar: 2, baz: 2 }, - { id: 6, foo: 1, bar: 2, baz: 2 }, - { id: 7, foo: 2, bar: 1, baz: 1 }, - { id: 8, foo: 2, bar: 1, baz: 2 }, - { id: 9, foo: 2, bar: 1, baz: 2 }, - { id: 10, foo: 2, bar: 2, baz: 1 }, - { id: 11, foo: 2, bar: 2, baz: 2 }, - { id: 12, foo: 2, bar: 2, baz: 2 } + startAt(3), + limitToLast(4) ); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 3 }, { foo: 4 }, { foo: 5 }); } ); }); - it('supports startAt (with DocumentReference)', () => { + it('supports endAt with limitToLast', () => { return withTestCollection( PERSISTENCE_MODE_UNSPECIFIED, { - 1: { id: 1, foo: 1, bar: 1, baz: 1 }, - 2: { id: 2, foo: 1, bar: 1, baz: 2 }, - 3: { id: 3, foo: 1, bar: 1, baz: 2 }, - 4: { id: 4, foo: 1, bar: 2, baz: 1 }, - 5: { id: 5, foo: 1, bar: 2, baz: 2 }, - 6: { id: 6, foo: 1, bar: 2, baz: 2 }, - 7: { id: 7, foo: 2, bar: 1, baz: 1 }, - 8: { id: 8, foo: 2, bar: 1, baz: 2 }, - 9: { id: 9, foo: 2, bar: 1, baz: 2 }, - 10: { id: 10, foo: 2, bar: 2, baz: 1 }, - 11: { id: 11, foo: 2, bar: 2, baz: 2 }, - 12: { id: 12, foo: 2, bar: 2, baz: 2 } + 1: { foo: 1 }, + 2: { foo: 2 }, + 3: { foo: 3 }, + 4: { foo: 4 }, + 5: { foo: 5 } }, async (collRef, db) => { - let docRef = await getDoc(doc(collRef, '2')); - let query1 = query( - collRef, - orderBy('foo'), - orderBy('bar'), - orderBy('baz'), - startAt(docRef) - ); - let snapshot = await execute(db.pipeline().createFrom(query1)); - verifyResults( - snapshot, - { id: 2, foo: 1, bar: 1, baz: 2 }, - { id: 3, foo: 1, bar: 1, baz: 2 }, - { id: 4, foo: 1, bar: 2, baz: 1 }, - { id: 5, foo: 1, bar: 2, baz: 2 }, - { id: 6, foo: 1, bar: 2, baz: 2 }, - { id: 7, foo: 2, bar: 1, baz: 1 }, - { id: 8, foo: 2, bar: 1, baz: 2 }, - { id: 9, foo: 2, bar: 1, baz: 2 }, - { id: 10, foo: 2, bar: 2, baz: 1 }, - { id: 11, foo: 2, bar: 2, baz: 2 }, - { id: 12, foo: 2, bar: 2, baz: 2 } - ); - - docRef = await getDoc(doc(collRef, '3')); - query1 = query( - collRef, - orderBy('foo'), - orderBy('bar'), - orderBy('baz'), - startAt(docRef) - ); - snapshot = await execute(db.pipeline().createFrom(query1)); - verifyResults( - snapshot, - { id: 3, foo: 1, bar: 1, baz: 2 }, - { id: 4, foo: 1, bar: 2, baz: 1 }, - { id: 5, foo: 1, bar: 2, baz: 2 }, - { id: 6, foo: 1, bar: 2, baz: 2 }, - { id: 7, foo: 2, bar: 1, baz: 1 }, - { id: 8, foo: 2, bar: 1, baz: 2 }, - { id: 9, foo: 2, bar: 1, baz: 2 }, - { id: 10, foo: 2, bar: 2, baz: 1 }, - { id: 11, foo: 2, bar: 2, baz: 2 }, - { id: 12, foo: 2, bar: 2, baz: 2 } - ); + const query1 = query(collRef, orderBy('foo'), endAt(3), limitToLast(2)); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 2 }, { foo: 3 }); } ); }); + // sort on __name__ is not working + itIf(testUnsupportedFeatures)( + 'supports startAfter (with DocumentSnapshot)', + () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { id: 1, foo: 1, bar: 1, baz: 1 }, + 2: { id: 2, foo: 1, bar: 1, baz: 2 }, + 3: { id: 3, foo: 1, bar: 1, baz: 2 }, + 4: { id: 4, foo: 1, bar: 2, baz: 1 }, + 5: { id: 5, foo: 1, bar: 2, baz: 2 }, + 6: { id: 6, foo: 1, bar: 2, baz: 2 }, + 7: { id: 7, foo: 2, bar: 1, baz: 1 }, + 8: { id: 8, foo: 2, bar: 1, baz: 2 }, + 9: { id: 9, foo: 2, bar: 1, baz: 2 }, + 10: { id: 10, foo: 2, bar: 2, baz: 1 }, + 11: { id: 11, foo: 2, bar: 2, baz: 2 }, + 12: { id: 12, foo: 2, bar: 2, baz: 2 } + }, + async (collRef, db) => { + let docRef = await getDoc(doc(collRef, '2')); + let query1 = query( + collRef, + orderBy('foo'), + orderBy('bar'), + orderBy('baz'), + startAfter(docRef) + ); + let snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults( + snapshot, + { id: 3, foo: 1, bar: 1, baz: 2 }, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 }, + { id: 11, foo: 2, bar: 2, baz: 2 }, + { id: 12, foo: 2, bar: 2, baz: 2 } + ); + + docRef = await getDoc(doc(collRef, '3')); + query1 = query( + collRef, + orderBy('foo'), + orderBy('bar'), + orderBy('baz'), + startAfter(docRef) + ); + snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults( + snapshot, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 }, + { id: 11, foo: 2, bar: 2, baz: 2 }, + { id: 12, foo: 2, bar: 2, baz: 2 } + ); + } + ); + } + ); + + // sort on __name__ is not working + itIf(testUnsupportedFeatures)( + 'supports startAt (with DocumentSnapshot)', + () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { id: 1, foo: 1, bar: 1, baz: 1 }, + 2: { id: 2, foo: 1, bar: 1, baz: 2 }, + 3: { id: 3, foo: 1, bar: 1, baz: 2 }, + 4: { id: 4, foo: 1, bar: 2, baz: 1 }, + 5: { id: 5, foo: 1, bar: 2, baz: 2 }, + 6: { id: 6, foo: 1, bar: 2, baz: 2 }, + 7: { id: 7, foo: 2, bar: 1, baz: 1 }, + 8: { id: 8, foo: 2, bar: 1, baz: 2 }, + 9: { id: 9, foo: 2, bar: 1, baz: 2 }, + 10: { id: 10, foo: 2, bar: 2, baz: 1 }, + 11: { id: 11, foo: 2, bar: 2, baz: 2 }, + 12: { id: 12, foo: 2, bar: 2, baz: 2 } + }, + async (collRef, db) => { + let docRef = await getDoc(doc(collRef, '2')); + let query1 = query( + collRef, + orderBy('foo'), + orderBy('bar'), + orderBy('baz'), + startAt(docRef) + ); + let snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults( + snapshot, + { id: 2, foo: 1, bar: 1, baz: 2 }, + { id: 3, foo: 1, bar: 1, baz: 2 }, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 }, + { id: 11, foo: 2, bar: 2, baz: 2 }, + { id: 12, foo: 2, bar: 2, baz: 2 } + ); + + docRef = await getDoc(doc(collRef, '3')); + query1 = query( + collRef, + orderBy('foo'), + orderBy('bar'), + orderBy('baz'), + startAt(docRef) + ); + snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults( + snapshot, + { id: 3, foo: 1, bar: 1, baz: 2 }, + { id: 4, foo: 1, bar: 2, baz: 1 }, + { id: 5, foo: 1, bar: 2, baz: 2 }, + { id: 6, foo: 1, bar: 2, baz: 2 }, + { id: 7, foo: 2, bar: 1, baz: 1 }, + { id: 8, foo: 2, bar: 1, baz: 2 }, + { id: 9, foo: 2, bar: 1, baz: 2 }, + { id: 10, foo: 2, bar: 2, baz: 1 }, + { id: 11, foo: 2, bar: 2, baz: 2 }, + { id: 12, foo: 2, bar: 2, baz: 2 } + ); + } + ); + } + ); + it('supports startAfter', () => { return withTestCollection( PERSISTENCE_MODE_UNSPECIFIED, @@ -434,7 +487,8 @@ apiDescribe.only('Query to Pipeline', persistence => { ); }); - it('supports collection groups', () => { + // needs subcollection support + itIf(testUnsupportedFeatures)('supports collection groups', () => { return withTestCollection( PERSISTENCE_MODE_UNSPECIFIED, {}, @@ -460,30 +514,34 @@ apiDescribe.only('Query to Pipeline', persistence => { ); }); - it('supports query over collection path with special characters', () => { - return withTestCollection( - PERSISTENCE_MODE_UNSPECIFIED, - {}, - async (collRef, db) => { - const docWithSpecials = doc(collRef, 'so!@#$%^&*()_+special'); - - const collectionWithSpecials = collection( - docWithSpecials, - 'so!@#$%^&*()_+special' - ); - await addDoc(collectionWithSpecials, { foo: 1 }); - await addDoc(collectionWithSpecials, { foo: 2 }); - - const snapshot = await execute( - db - .pipeline() - .createFrom(query(collectionWithSpecials, orderBy('foo', 'asc'))) - ); - - verifyResults(snapshot, { foo: 1 }, { foo: 2 }); - } - ); - }); + // needs subcollection support + itIf(testUnsupportedFeatures)( + 'supports query over collection path with special characters', + () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + {}, + async (collRef, db) => { + const docWithSpecials = doc(collRef, 'so!@#$%^&*()_+special'); + + const collectionWithSpecials = collection( + docWithSpecials, + 'so!@#$%^&*()_+special' + ); + await addDoc(collectionWithSpecials, { foo: 1 }); + await addDoc(collectionWithSpecials, { foo: 2 }); + + const snapshot = await execute( + db + .pipeline() + .createFrom(query(collectionWithSpecials, orderBy('foo', 'asc'))) + ); + + verifyResults(snapshot, { foo: 1 }, { foo: 2 }); + } + ); + } + ); it('supports multiple inequality on same field', () => { return withTestCollection( @@ -555,4 +613,215 @@ apiDescribe.only('Query to Pipeline', persistence => { } ); }); + + it('supports collectionGroup query', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { 1: { foo: 1 } }, + async (collRef, db) => { + const snapshot = await execute( + db.pipeline().createFrom(collectionGroup(db, collRef.id)) + ); + verifyResults(snapshot, { foo: 1 }); + } + ); + }); + + it('supports eq nan', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1, bar: NaN }, + 2: { foo: 2, bar: 1 } + }, + async (collRef, db) => { + const query1 = query(collRef, where('bar', '==', NaN)); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 1, bar: NaN }); + } + ); + }); + + it('supports neq nan', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1, bar: NaN }, + 2: { foo: 2, bar: 1 } + }, + async (collRef, db) => { + const query1 = query(collRef, where('bar', '!=', NaN)); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 2, bar: 1 }); + } + ); + }); + + it('supports eq null', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1, bar: null }, + 2: { foo: 2, bar: 1 } + }, + async (collRef, db) => { + const query1 = query(collRef, where('bar', '==', null)); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 1, bar: null }); + } + ); + }); + + it('supports neq null', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1, bar: null }, + 2: { foo: 2, bar: 1 } + }, + async (collRef, db) => { + const query1 = query(collRef, where('bar', '!=', null)); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 2, bar: 1 }); + } + ); + }); + + it('supports neq', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1, bar: 0 }, + 2: { foo: 2, bar: 1 } + }, + async (collRef, db) => { + const query1 = query(collRef, where('bar', '!=', 0)); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 2, bar: 1 }); + } + ); + }); + + it('supports array contains', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1, bar: [0, 2, 4, 6] }, + 2: { foo: 2, bar: [1, 3, 5, 7] } + }, + async (collRef, db) => { + const query1 = query(collRef, where('bar', 'array-contains', 4)); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 1, bar: [0, 2, 4, 6] }); + } + ); + }); + + // sorting on name required + itIf(testUnsupportedFeatures)('supports array contains any', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1, bar: [0, 2, 4, 6] }, + 2: { foo: 2, bar: [1, 3, 5, 7] }, + 3: { foo: 3, bar: [10, 20, 30, 40] } + }, + async (collRef, db) => { + const query1 = query( + collRef, + where('bar', 'array-contains-any', [4, 5]) + ); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults( + snapshot, + { foo: 1, bar: [0, 2, 4, 6] }, + { foo: 2, bar: [1, 3, 5, 7] } + ); + } + ); + }); + + it('supports in', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1, bar: 2 }, + 2: { foo: 2 }, + 3: { foo: 3, bar: 10 } + }, + async (collRef, db) => { + const query1 = query(collRef, where('bar', 'in', [0, 10, 20])); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 3, bar: 10 }); + } + ); + }); + + it('supports in with 1', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1, bar: 2 }, + 2: { foo: 2 }, + 3: { foo: 3, bar: 10 } + }, + async (collRef, db) => { + const query1 = query(collRef, where('bar', 'in', [2])); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 1, bar: 2 }); + } + ); + }); + + itIf(testUnsupportedFeatures)('supports not in', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1, bar: 2 }, + 2: { foo: 2, bar: 1 }, + 3: { foo: 3, bar: 10 } + }, + async (collRef, db) => { + const query1 = query(collRef, where('bar', 'not-in', [0, 10, 20])); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 1, bar: 2 }, { foo: 2, bar: 1 }); + } + ); + }); + + it('supports not in with 1', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1, bar: 2 }, + 2: { foo: 2 }, + 3: { foo: 3, bar: 10 } + }, + async (collRef, db) => { + const query1 = query(collRef, where('bar', 'not-in', [2])); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 3, bar: 10 }); + } + ); + }); + + it('supports or operator', () => { + return withTestCollection( + PERSISTENCE_MODE_UNSPECIFIED, + { + 1: { foo: 1, bar: 2 }, + 2: { foo: 2, bar: 0 }, + 3: { foo: 3, bar: 10 } + }, + async (collRef, db) => { + const query1 = query( + collRef, + or(where('bar', '==', 2), where('foo', '==', 3)), + orderBy('foo') + ); + const snapshot = await execute(db.pipeline().createFrom(query1)); + verifyResults(snapshot, { foo: 1, bar: 2 }, { foo: 3, bar: 10 }); + } + ); + }); }); diff --git a/packages/firestore/test/integration/util/helpers.ts b/packages/firestore/test/integration/util/helpers.ts index 465bc8edd61..81d97867d09 100644 --- a/packages/firestore/test/integration/util/helpers.ts +++ b/packages/firestore/test/integration/util/helpers.ts @@ -557,3 +557,10 @@ export async function checkOnlineAndOfflineResultsMatch( const docsFromCache = await getDocsFromCache(query); expect(toIds(docsFromServer)).to.deep.equal(toIds(docsFromCache)); } + +export function itIf( + condition: boolean | 'only' +): Mocha.TestFunction | Mocha.PendingTestFunction { + // eslint-disable-next-line no-restricted-properties + return condition === 'only' ? it.only : condition ? it : it.skip; +} diff --git a/packages/firestore/test/lite/pipeline.test.ts b/packages/firestore/test/lite/pipeline.test.ts index f82a224ec5c..e3e5083a811 100644 --- a/packages/firestore/test/lite/pipeline.test.ts +++ b/packages/firestore/test/lite/pipeline.test.ts @@ -52,7 +52,6 @@ import { bitRightShift, bitXor, isNotNan, - manhattanDistance, map, isNotNull, isNull, @@ -1991,9 +1990,6 @@ describe('Firestore Pipelines', () => { ), euclideanDistance(constantVector(sourceVector), targetVector).as( 'euclideanDistance' - ), - manhattanDistance(constantVector(sourceVector), targetVector).as( - 'manhattanDistance' ) ) .limit(1) @@ -2002,8 +1998,7 @@ describe('Firestore Pipelines', () => { expectResults(snapshot, { cosineDistance: 0.02560880430538015, dotProductDistance: 0.13, - euclideanDistance: 0.806225774829855, - manhattanDistance: 1.1 + euclideanDistance: 0.806225774829855 }); snapshot = await execute( @@ -2019,10 +2014,7 @@ describe('Firestore Pipelines', () => { .as('dotProductDistance'), constantVector(sourceVector) .euclideanDistance(targetVector) - .as('euclideanDistance'), - constantVector(sourceVector) - .manhattanDistance(targetVector) - .as('manhattanDistance') + .as('euclideanDistance') ) .limit(1) ); @@ -2030,8 +2022,7 @@ describe('Firestore Pipelines', () => { expectResults(snapshot, { cosineDistance: 0.02560880430538015, dotProductDistance: 0.13, - euclideanDistance: 0.806225774829855, - manhattanDistance: 1.1 + euclideanDistance: 0.806225774829855 }); }); @@ -2870,7 +2861,7 @@ describe('Firestore Pipelines', () => { it('supports pagination with offsets', async () => { await addBooks(randomCol); - const secondFilterField = '__path__'; + const secondFilterField = '__name__'; const pipeline = firestore .pipeline() From 129b62b3f5e74bfaf9b22c00436178693e51e0ac Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 21 Mar 2025 14:17:08 -0600 Subject: [PATCH 73/75] PR feedback --- packages/firestore/src/api/pipeline_impl.ts | 11 +- .../firestore/src/lite-api/expressions.ts | 158 +++++++++--------- .../firestore/src/lite-api/pipeline_impl.ts | 11 +- 3 files changed, 91 insertions(+), 89 deletions(-) diff --git a/packages/firestore/src/api/pipeline_impl.ts b/packages/firestore/src/api/pipeline_impl.ts index 3fbfbf5f7a6..ba6e08105bb 100644 --- a/packages/firestore/src/api/pipeline_impl.ts +++ b/packages/firestore/src/api/pipeline_impl.ts @@ -37,11 +37,12 @@ declare module './database' { /** * Executes this pipeline and returns a Promise to represent the asynchronous operation. * - *

    The returned Promise can be used to track the progress of the pipeline execution + * The returned Promise can be used to track the progress of the pipeline execution * and retrieve the results (or handle any errors) asynchronously. * - *

    The pipeline results are returned as a list of {@link PipelineResult} objects. Each {@link - * PipelineResult} typically represents a single key/value map that has passed through all the + * The pipeline results are returned as a {@link PipelineSnapshot} that contains + * a list of {@link PipelineResult} objects. Each {@link PipelineResult} typically + * represents a single key/value map that has passed through all the * stages of the pipeline, however this might differ depending on the stages involved in the * pipeline. For example: * @@ -57,9 +58,11 @@ declare module './database' { *

    Example: * * ```typescript - * const futureResults = await execute(firestore.pipeline().collection("books") + * const snapshot: PipelineSnapshot = await execute(firestore.pipeline().collection("books") * .where(gt(field("rating"), 4.5)) * .select("title", "author", "rating")); + * + * const results: PipelineResults = snapshot.results; * ``` * * @param pipeline The pipeline to execute. diff --git a/packages/firestore/src/lite-api/expressions.ts b/packages/firestore/src/lite-api/expressions.ts index 377dfe5c063..6eaebf2c4f0 100644 --- a/packages/firestore/src/lite-api/expressions.ts +++ b/packages/firestore/src/lite-api/expressions.ts @@ -111,7 +111,7 @@ function vectorToExpr(value: VectorValue | number[] | Expr): Expr { * @internal * @param value */ -function fieldOfOrExpr(value: unknown): Expr { +function fieldOrExpression(value: unknown): Expr { if (isString(value)) { const result = field(value); result._createdFromLiteral = true; @@ -208,8 +208,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The constant value to subtract. * @return A new `Expr` representing the subtraction operation. */ - subtract(other: unknown): FunctionExpr; - subtract(other: unknown): FunctionExpr { + subtract(other: number): FunctionExpr; + subtract(other: number | Expr): FunctionExpr { return new FunctionExpr('subtract', [this, valueToDefaultExpr(other)]); } @@ -226,8 +226,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @return A new `Expr` representing the multiplication operation. */ multiply( - second: Expr | unknown, - ...others: Array + second: Expr | number, + ...others: Array ): FunctionExpr { return new FunctionExpr('multiply', [ this, @@ -260,8 +260,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param other The constant value to divide by. * @return A new `Expr` representing the division operation. */ - divide(other: unknown): FunctionExpr; - divide(other: unknown): FunctionExpr { + divide(other: number): FunctionExpr; + divide(other: number | Expr): FunctionExpr { return new FunctionExpr('divide', [this, valueToDefaultExpr(other)]); } @@ -289,8 +289,8 @@ export abstract class Expr implements ProtoValueSerializable, UserData { * @param value The constant value to divide by. * @return A new `Expr` representing the modulo operation. */ - mod(value: unknown): FunctionExpr; - mod(other: unknown): FunctionExpr { + mod(value: number): FunctionExpr; + mod(other: number | Expr): FunctionExpr { return new FunctionExpr('mod', [this, valueToDefaultExpr(other)]); } @@ -2641,12 +2641,10 @@ export function bitAnd( otherBitsExpression: Expr ): FunctionExpr; export function bitAnd( - fieldOrExpression: string | Expr, + bits: string | Expr, bitsOrExpression: number | Expr | Bytes ): FunctionExpr { - return fieldOfOrExpr(fieldOrExpression).bitAnd( - valueToDefaultExpr(bitsOrExpression) - ); + return fieldOrExpression(bits).bitAnd(valueToDefaultExpr(bitsOrExpression)); } /** @@ -2716,12 +2714,10 @@ export function bitOr( otherBitsExpression: Expr ): FunctionExpr; export function bitOr( - fieldOrExpression: string | Expr, + bits: string | Expr, bitsOrExpression: number | Expr | Bytes ): FunctionExpr { - return fieldOfOrExpr(fieldOrExpression).bitOr( - valueToDefaultExpr(bitsOrExpression) - ); + return fieldOrExpression(bits).bitOr(valueToDefaultExpr(bitsOrExpression)); } /** @@ -2791,12 +2787,10 @@ export function bitXor( otherBitsExpression: Expr ): FunctionExpr; export function bitXor( - fieldOrExpression: string | Expr, + bits: string | Expr, bitsOrExpression: number | Expr | Bytes ): FunctionExpr { - return fieldOfOrExpr(fieldOrExpression).bitXor( - valueToDefaultExpr(bitsOrExpression) - ); + return fieldOrExpression(bits).bitXor(valueToDefaultExpr(bitsOrExpression)); } /** @@ -2828,7 +2822,7 @@ export function bitNot(field: string): FunctionExpr; */ export function bitNot(bitsValueExpression: Expr): FunctionExpr; export function bitNot(bits: string | Expr): FunctionExpr { - return fieldOfOrExpr(bits).bitNot(); + return fieldOrExpression(bits).bitNot(); } /** @@ -2895,7 +2889,7 @@ export function bitLeftShift( xValue: string | Expr, numberExpr: number | Expr ): FunctionExpr { - return fieldOfOrExpr(xValue).bitLeftShift(valueToDefaultExpr(numberExpr)); + return fieldOrExpression(xValue).bitLeftShift(valueToDefaultExpr(numberExpr)); } /** @@ -2962,7 +2956,9 @@ export function bitRightShift( xValue: string | Expr, numberExpr: number | Expr ): FunctionExpr { - return fieldOfOrExpr(xValue).bitRightShift(valueToDefaultExpr(numberExpr)); + return fieldOrExpression(xValue).bitRightShift( + valueToDefaultExpr(numberExpr) + ); } /** @@ -3044,7 +3040,7 @@ export function arrayOffset( array: Expr | string, offset: Expr | number ): FunctionExpr { - return fieldOfOrExpr(array).arrayOffset(valueToDefaultExpr(offset)); + return fieldOrExpression(array).arrayOffset(valueToDefaultExpr(offset)); } /** @@ -3147,7 +3143,7 @@ export function isAbsent(value: Expr): BooleanExpr; */ export function isAbsent(field: string): BooleanExpr; export function isAbsent(value: Expr | string): BooleanExpr { - return fieldOfOrExpr(value).isAbsent(); + return fieldOrExpression(value).isAbsent(); } /** @@ -3180,7 +3176,7 @@ export function isNull(value: Expr): BooleanExpr; */ export function isNull(value: string): BooleanExpr; export function isNull(value: Expr | string): BooleanExpr { - return fieldOfOrExpr(value).isNull(); + return fieldOrExpression(value).isNull(); } /** @@ -3213,7 +3209,7 @@ export function isNotNull(value: Expr): BooleanExpr; */ export function isNotNull(value: string): BooleanExpr; export function isNotNull(value: Expr | string): BooleanExpr { - return fieldOfOrExpr(value).isNotNull(); + return fieldOrExpression(value).isNotNull(); } /** @@ -3246,7 +3242,7 @@ export function isNotNan(value: Expr): BooleanExpr; */ export function isNotNan(value: string): BooleanExpr; export function isNotNan(value: Expr | string): BooleanExpr { - return fieldOfOrExpr(value).isNotNan(); + return fieldOrExpression(value).isNotNan(); } /** @@ -3310,7 +3306,7 @@ export function mapRemove( mapExpr: Expr | string, stringExpr: Expr | string ): FunctionExpr { - return fieldOfOrExpr(mapExpr).mapRemove(valueToDefaultExpr(stringExpr)); + return fieldOrExpression(mapExpr).mapRemove(valueToDefaultExpr(stringExpr)); } /** @@ -3366,7 +3362,7 @@ export function mapMerge( ): FunctionExpr { const secondMapExpr = valueToDefaultExpr(secondMap); const otherMapExprs = otherMaps.map(valueToDefaultExpr); - return fieldOfOrExpr(firstMap).mapMerge(secondMapExpr, ...otherMapExprs); + return fieldOrExpression(firstMap).mapMerge(secondMapExpr, ...otherMapExprs); } /** @@ -3472,7 +3468,7 @@ export function substr( position: Expr | number, length?: Expr | number ): FunctionExpr { - const fieldExpr = fieldOfOrExpr(field); + const fieldExpr = fieldOrExpression(field); const positionExpr = valueToDefaultExpr(position); const lengthExpr = length === undefined ? undefined : valueToDefaultExpr(length); @@ -3526,7 +3522,7 @@ export function add( second: Expr | unknown, ...others: Array ): FunctionExpr { - return fieldOfOrExpr(first).add( + return fieldOrExpression(first).add( valueToDefaultExpr(second), ...others.map(value => valueToDefaultExpr(value)) ); @@ -3651,7 +3647,7 @@ export function multiply( second: Expr | unknown, ...others: Array ): FunctionExpr { - return fieldOfOrExpr(first).multiply( + return fieldOrExpression(first).multiply( valueToDefaultExpr(second), ...others.map(valueToDefaultExpr) ); @@ -4330,8 +4326,8 @@ export function arrayConcat( ...otherArrays: Array ): FunctionExpr { const exprValues = otherArrays.map(element => valueToDefaultExpr(element)); - return fieldOfOrExpr(firstArray).arrayConcat( - fieldOfOrExpr(secondArray), + return fieldOrExpression(firstArray).arrayConcat( + fieldOrExpression(secondArray), ...exprValues ); } @@ -4403,7 +4399,7 @@ export function arrayContains( array: Expr | string, element: unknown ): BooleanExpr { - const arrayExpr = fieldOfOrExpr(array); + const arrayExpr = fieldOrExpression(array); const elementExpr = valueToDefaultExpr(element); return arrayExpr.arrayContains(elementExpr); } @@ -4488,7 +4484,7 @@ export function arrayContainsAny( values: unknown[] | Expr ): BooleanExpr { // @ts-ignore implementation accepts both types - return fieldOfOrExpr(array).arrayContainsAny(values); + return fieldOrExpression(array).arrayContainsAny(values); } /** @@ -4573,7 +4569,7 @@ export function arrayContainsAll( values: unknown[] | Expr ): BooleanExpr { // @ts-ignore implementation accepts both types - return fieldOfOrExpr(array).arrayContainsAll(values); + return fieldOrExpression(array).arrayContainsAll(values); } /** @@ -4606,7 +4602,7 @@ export function arrayLength(fieldName: string): FunctionExpr; */ export function arrayLength(array: Expr): FunctionExpr; export function arrayLength(array: Expr | string): FunctionExpr { - return fieldOfOrExpr(array).arrayLength(); + return fieldOrExpression(array).arrayLength(); } /** @@ -4686,7 +4682,7 @@ export function eqAny( values: unknown[] | Expr ): BooleanExpr { // @ts-ignore implementation accepts both types - return fieldOfOrExpr(element).eqAny(values); + return fieldOrExpression(element).eqAny(values); } /** @@ -4767,7 +4763,7 @@ export function notEqAny( values: unknown[] | Expr ): BooleanExpr { // @ts-ignore implementation accepts both types - return fieldOfOrExpr(element).notEqAny(values); + return fieldOrExpression(element).notEqAny(values); } /** @@ -4890,7 +4886,7 @@ export function logicalMaximum( second: Expr | unknown, ...others: Array ): FunctionExpr { - return fieldOfOrExpr(first).logicalMaximum( + return fieldOrExpression(first).logicalMaximum( valueToDefaultExpr(second), ...others.map(value => valueToDefaultExpr(value)) ); @@ -4948,7 +4944,7 @@ export function logicalMinimum( second: Expr | unknown, ...others: Array ): FunctionExpr { - return fieldOfOrExpr(first).logicalMinimum( + return fieldOrExpression(first).logicalMinimum( valueToDefaultExpr(second), ...others.map(value => valueToDefaultExpr(value)) ); @@ -4984,7 +4980,7 @@ export function exists(value: Expr): BooleanExpr; */ export function exists(fieldName: string): BooleanExpr; export function exists(valueOrField: Expr | string): BooleanExpr { - return fieldOfOrExpr(valueOrField).exists(); + return fieldOrExpression(valueOrField).exists(); } /** @@ -5017,7 +5013,7 @@ export function isNan(value: Expr): BooleanExpr; */ export function isNan(fieldName: string): BooleanExpr; export function isNan(value: Expr | string): BooleanExpr { - return fieldOfOrExpr(value).isNan(); + return fieldOrExpression(value).isNan(); } /** @@ -5050,7 +5046,7 @@ export function reverse(stringExpression: Expr): FunctionExpr; */ export function reverse(field: string): FunctionExpr; export function reverse(expr: Expr | string): FunctionExpr { - return fieldOfOrExpr(expr).reverse(); + return fieldOrExpression(expr).reverse(); } /** @@ -5121,7 +5117,7 @@ export function replaceFirst( find: Expr | string, replace: Expr | string ): FunctionExpr { - const normalizedValue = fieldOfOrExpr(value); + const normalizedValue = fieldOrExpression(value); const normalizedFind = valueToDefaultExpr(find); const normalizedReplace = valueToDefaultExpr(replace); return normalizedValue.replaceFirst(normalizedFind, normalizedReplace); @@ -5195,7 +5191,7 @@ export function replaceAll( find: Expr | string, replace: Expr | string ): FunctionExpr { - const normalizedValue = fieldOfOrExpr(value); + const normalizedValue = fieldOrExpression(value); const normalizedFind = valueToDefaultExpr(find); const normalizedReplace = valueToDefaultExpr(replace); return normalizedValue.replaceAll(normalizedFind, normalizedReplace); @@ -5231,7 +5227,7 @@ export function byteLength(expr: Expr): FunctionExpr; */ export function byteLength(fieldName: string): FunctionExpr; export function byteLength(expr: Expr | string): FunctionExpr { - const normalizedExpr = fieldOfOrExpr(expr); + const normalizedExpr = fieldOrExpression(expr); return normalizedExpr.byteLength(); } @@ -5265,7 +5261,7 @@ export function charLength(fieldName: string): FunctionExpr; */ export function charLength(stringExpression: Expr): FunctionExpr; export function charLength(value: Expr | string): FunctionExpr { - const valueExpr = fieldOfOrExpr(value); + const valueExpr = fieldOrExpression(value); return valueExpr.charLength(); } @@ -5338,7 +5334,7 @@ export function like( left: Expr | string, pattern: Expr | string ): FunctionExpr { - const leftExpr = fieldOfOrExpr(left); + const leftExpr = fieldOrExpression(left); const patternExpr = valueToDefaultExpr(pattern); return leftExpr.like(patternExpr); } @@ -5420,7 +5416,7 @@ export function regexContains( left: Expr | string, pattern: Expr | string ): BooleanExpr { - const leftExpr = fieldOfOrExpr(left); + const leftExpr = fieldOrExpression(left); const patternExpr = valueToDefaultExpr(pattern); return leftExpr.regexContains(patternExpr); } @@ -5497,7 +5493,7 @@ export function regexMatch( left: Expr | string, pattern: Expr | string ): BooleanExpr { - const leftExpr = fieldOfOrExpr(left); + const leftExpr = fieldOrExpression(left); const patternExpr = valueToDefaultExpr(pattern); return leftExpr.regexMatch(patternExpr); } @@ -5575,7 +5571,7 @@ export function strContains( left: Expr | string, substring: Expr | string ): BooleanExpr { - const leftExpr = fieldOfOrExpr(left); + const leftExpr = fieldOrExpression(left); const substringExpr = valueToDefaultExpr(substring); return leftExpr.strContains(substringExpr); } @@ -5647,7 +5643,7 @@ export function startsWith( expr: Expr | string, prefix: Expr | string ): BooleanExpr { - return fieldOfOrExpr(expr).startsWith(valueToDefaultExpr(prefix)); + return fieldOrExpression(expr).startsWith(valueToDefaultExpr(prefix)); } /** @@ -5717,7 +5713,7 @@ export function endsWith( expr: Expr | string, suffix: Expr | string ): BooleanExpr { - return fieldOfOrExpr(expr).endsWith(valueToDefaultExpr(suffix)); + return fieldOrExpression(expr).endsWith(valueToDefaultExpr(suffix)); } /** @@ -5750,7 +5746,7 @@ export function toLower(fieldName: string): FunctionExpr; */ export function toLower(stringExpression: Expr): FunctionExpr; export function toLower(expr: Expr | string): FunctionExpr { - return fieldOfOrExpr(expr).toLower(); + return fieldOrExpression(expr).toLower(); } /** @@ -5783,7 +5779,7 @@ export function toUpper(fieldName: string): FunctionExpr; */ export function toUpper(stringExpression: Expr): FunctionExpr; export function toUpper(expr: Expr | string): FunctionExpr { - return fieldOfOrExpr(expr).toUpper(); + return fieldOrExpression(expr).toUpper(); } /** @@ -5816,7 +5812,7 @@ export function trim(fieldName: string): FunctionExpr; */ export function trim(stringExpression: Expr): FunctionExpr; export function trim(expr: Expr | string): FunctionExpr { - return fieldOfOrExpr(expr).trim(); + return fieldOrExpression(expr).trim(); } /** @@ -5864,7 +5860,7 @@ export function strConcat( second: string | Expr, ...elements: Array ): FunctionExpr { - return fieldOfOrExpr(first).strConcat( + return fieldOrExpression(first).strConcat( valueToDefaultExpr(second), ...elements.map(valueToDefaultExpr) ); @@ -5905,7 +5901,7 @@ export function mapGet( fieldOrExpr: string | Expr, subField: string ): FunctionExpr { - return fieldOfOrExpr(fieldOrExpr).mapGet(subField); + return fieldOrExpression(fieldOrExpr).mapGet(subField); } /** @@ -5953,7 +5949,7 @@ export function count(expression: Expr): AggregateFunction; */ export function count(fieldName: string): AggregateFunction; export function count(value: Expr | string): AggregateFunction { - return fieldOfOrExpr(value).count(); + return fieldOrExpression(value).count(); } /** @@ -5988,7 +5984,7 @@ export function sum(expression: Expr): AggregateFunction; */ export function sum(fieldName: string): AggregateFunction; export function sum(value: Expr | string): AggregateFunction { - return fieldOfOrExpr(value).sum(); + return fieldOrExpression(value).sum(); } /** @@ -6023,7 +6019,7 @@ export function avg(expression: Expr): AggregateFunction; */ export function avg(fieldName: string): AggregateFunction; export function avg(value: Expr | string): AggregateFunction { - return fieldOfOrExpr(value).avg(); + return fieldOrExpression(value).avg(); } /** @@ -6057,7 +6053,7 @@ export function minimum(expression: Expr): AggregateFunction; */ export function minimum(fieldName: string): AggregateFunction; export function minimum(value: Expr | string): AggregateFunction { - return fieldOfOrExpr(value).minimum(); + return fieldOrExpression(value).minimum(); } /** @@ -6091,7 +6087,7 @@ export function maximum(expression: Expr): AggregateFunction; */ export function maximum(fieldName: string): AggregateFunction; export function maximum(value: Expr | string): AggregateFunction { - return fieldOfOrExpr(value).maximum(); + return fieldOrExpression(value).maximum(); } /** @@ -6173,7 +6169,7 @@ export function cosineDistance( expr: Expr | string, other: Expr | number[] | VectorValue ): FunctionExpr { - const expr1 = fieldOfOrExpr(expr); + const expr1 = fieldOrExpression(expr); const expr2 = vectorToExpr(other); return expr1.cosineDistance(expr2); } @@ -6257,7 +6253,7 @@ export function dotProduct( expr: Expr | string, other: Expr | number[] | VectorValue ): FunctionExpr { - const expr1 = fieldOfOrExpr(expr); + const expr1 = fieldOrExpression(expr); const expr2 = vectorToExpr(other); return expr1.dotProduct(expr2); } @@ -6342,7 +6338,7 @@ export function euclideanDistance( expr: Expr | string, other: Expr | number[] | VectorValue ): FunctionExpr { - const expr1 = fieldOfOrExpr(expr); + const expr1 = fieldOrExpression(expr); const expr2 = vectorToExpr(other); return expr1.euclideanDistance(expr2); } @@ -6377,7 +6373,7 @@ export function vectorLength(vectorExpression: Expr): FunctionExpr; */ export function vectorLength(fieldName: string): FunctionExpr; export function vectorLength(expr: Expr | string): FunctionExpr { - return fieldOfOrExpr(expr).vectorLength(); + return fieldOrExpression(expr).vectorLength(); } /** @@ -6412,7 +6408,7 @@ export function unixMicrosToTimestamp(expr: Expr): FunctionExpr; */ export function unixMicrosToTimestamp(fieldName: string): FunctionExpr; export function unixMicrosToTimestamp(expr: Expr | string): FunctionExpr { - return fieldOfOrExpr(expr).unixMicrosToTimestamp(); + return fieldOrExpression(expr).unixMicrosToTimestamp(); } /** @@ -6445,7 +6441,7 @@ export function timestampToUnixMicros(expr: Expr): FunctionExpr; */ export function timestampToUnixMicros(fieldName: string): FunctionExpr; export function timestampToUnixMicros(expr: Expr | string): FunctionExpr { - return fieldOfOrExpr(expr).timestampToUnixMicros(); + return fieldOrExpression(expr).timestampToUnixMicros(); } /** @@ -6480,7 +6476,7 @@ export function unixMillisToTimestamp(expr: Expr): FunctionExpr; */ export function unixMillisToTimestamp(fieldName: string): FunctionExpr; export function unixMillisToTimestamp(expr: Expr | string): FunctionExpr { - const normalizedExpr = fieldOfOrExpr(expr); + const normalizedExpr = fieldOrExpression(expr); return normalizedExpr.unixMillisToTimestamp(); } @@ -6514,7 +6510,7 @@ export function timestampToUnixMillis(expr: Expr): FunctionExpr; */ export function timestampToUnixMillis(fieldName: string): FunctionExpr; export function timestampToUnixMillis(expr: Expr | string): FunctionExpr { - const normalizedExpr = fieldOfOrExpr(expr); + const normalizedExpr = fieldOrExpression(expr); return normalizedExpr.timestampToUnixMillis(); } @@ -6550,7 +6546,7 @@ export function unixSecondsToTimestamp(expr: Expr): FunctionExpr; */ export function unixSecondsToTimestamp(fieldName: string): FunctionExpr; export function unixSecondsToTimestamp(expr: Expr | string): FunctionExpr { - const normalizedExpr = fieldOfOrExpr(expr); + const normalizedExpr = fieldOrExpression(expr); return normalizedExpr.unixSecondsToTimestamp(); } @@ -6584,7 +6580,7 @@ export function timestampToUnixSeconds(expr: Expr): FunctionExpr; */ export function timestampToUnixSeconds(fieldName: string): FunctionExpr; export function timestampToUnixSeconds(expr: Expr | string): FunctionExpr { - const normalizedExpr = fieldOfOrExpr(expr); + const normalizedExpr = fieldOrExpression(expr); return normalizedExpr.timestampToUnixSeconds(); } @@ -6662,7 +6658,7 @@ export function timestampAdd( | 'day', amount: Expr | number ): FunctionExpr { - const normalizedTimestamp = fieldOfOrExpr(timestamp); + const normalizedTimestamp = fieldOrExpression(timestamp); const normalizedUnit = valueToDefaultExpr(unit); const normalizedAmount = valueToDefaultExpr(amount); return normalizedTimestamp.timestampAdd(normalizedUnit, normalizedAmount); @@ -6742,7 +6738,7 @@ export function timestampSub( | 'day', amount: Expr | number ): FunctionExpr { - const normalizedTimestamp = fieldOfOrExpr(timestamp); + const normalizedTimestamp = fieldOrExpression(timestamp); const normalizedUnit = valueToDefaultExpr(unit); const normalizedAmount = valueToDefaultExpr(amount); return normalizedTimestamp.timestampSub(normalizedUnit, normalizedAmount); @@ -6828,7 +6824,7 @@ export function ascending(expr: Expr): Ordering; */ export function ascending(fieldName: string): Ordering; export function ascending(field: Expr | string): Ordering { - return new Ordering(fieldOfOrExpr(field), 'ascending'); + return new Ordering(fieldOrExpression(field), 'ascending'); } /** @@ -6863,7 +6859,7 @@ export function descending(expr: Expr): Ordering; */ export function descending(fieldName: string): Ordering; export function descending(field: Expr | string): Ordering { - return new Ordering(fieldOfOrExpr(field), 'descending'); + return new Ordering(fieldOrExpression(field), 'descending'); } /** diff --git a/packages/firestore/src/lite-api/pipeline_impl.ts b/packages/firestore/src/lite-api/pipeline_impl.ts index 6179a35b8b6..c1ca940a56b 100644 --- a/packages/firestore/src/lite-api/pipeline_impl.ts +++ b/packages/firestore/src/lite-api/pipeline_impl.ts @@ -36,11 +36,12 @@ declare module './database' { /** * Executes this pipeline and returns a Promise to represent the asynchronous operation. * - *

    The returned Promise can be used to track the progress of the pipeline execution + * The returned Promise can be used to track the progress of the pipeline execution * and retrieve the results (or handle any errors) asynchronously. * - *

    The pipeline results are returned as a list of {@link PipelineResult} objects. Each {@link - * PipelineResult} typically represents a single key/value map that has passed through all the + * The pipeline results are returned as a {@link PipelineSnapshot} that contains + * a list of {@link PipelineResult} objects. Each {@link PipelineResult} typically + * represents a single key/value map that has passed through all the * stages of the pipeline, however this might differ depending on the stages involved in the * pipeline. For example: * @@ -56,9 +57,11 @@ declare module './database' { *

    Example: * * ```typescript - * const futureResults = await execute(firestore.pipeline().collection("books") + * const snapshot: PipelineSnapshot = await execute(firestore.pipeline().collection("books") * .where(gt(field("rating"), 4.5)) * .select("title", "author", "rating")); + * + * const results: PipelineResults = snapshot.results; * ``` * * @param pipeline The pipeline to execute. From 4469c58ea4446529ca7b1131b25c472fe33b619a Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 21 Mar 2025 14:55:55 -0600 Subject: [PATCH 74/75] Updating replaceWith to take an Expr --- packages/firestore/src/lite-api/pipeline.ts | 48 +++++++++++++++++-- packages/firestore/src/lite-api/stage.ts | 2 +- .../test/integration/api/pipeline.test.ts | 25 +++++++++- 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/packages/firestore/src/lite-api/pipeline.ts b/packages/firestore/src/lite-api/pipeline.ts index 4d4b391c592..e07c7a37b9f 100644 --- a/packages/firestore/src/lite-api/pipeline.ts +++ b/packages/firestore/src/lite-api/pipeline.ts @@ -599,7 +599,7 @@ export class Pipeline implements ProtoSerializable { * // } * * // Emit parents as document. - * firestore.pipeline().collection('people').replaceWith(field('parents')); + * firestore.pipeline().collection('people').replaceWith('parents'); * * // Output * // { @@ -608,12 +608,50 @@ export class Pipeline implements ProtoSerializable { * // } * ``` * - * @param fieldValue The {@link Field} field containing the nested map. + * @param fieldName The {@link Field} field containing the nested map. * @return A new {@code Pipeline} object with this stage appended to the stage list. */ - replaceWith(fieldValue: Field | string): Pipeline { - const fieldExpr = - typeof fieldValue === 'string' ? field(fieldValue) : fieldValue; + replaceWith(fieldName: string): Pipeline; + + /** + * Fully overwrites all fields in a document with those coming from a map. + * + *

    This stage allows you to emit a map value as a document. Each key of the map becomes a field + * on the document that contains the corresponding value. + * + *

    Example: + * + * ```typescript + * // Input. + * // { + * // 'name': 'John Doe Jr.', + * // 'parents': { + * // 'father': 'John Doe Sr.', + * // 'mother': 'Jane Doe' + * // } + * // } + * + * // Emit parents as document. + * firestore.pipeline().collection('people').replaceWith(map({ + * foo: 'bar', + * info: { + * name: field('name') + * } + * })); + * + * // Output + * // { + * // 'father': 'John Doe Sr.', + * // 'mother': 'Jane Doe' + * // } + * ``` + * + * @param expr An {@link Expr} that when returned evaluates to a map. + * @return A new {@code Pipeline} object with this stage appended to the stage list. + */ + replaceWith(expr: Expr): Pipeline; + replaceWith(value: Expr | string): Pipeline { + const fieldExpr = typeof value === 'string' ? field(value) : value; this.readUserData('replaceWith', fieldExpr); return this._addStage(new Replace(fieldExpr, 'full_replace')); } diff --git a/packages/firestore/src/lite-api/stage.ts b/packages/firestore/src/lite-api/stage.ts index ba4d2df148c..1d8ae06eaf6 100644 --- a/packages/firestore/src/lite-api/stage.ts +++ b/packages/firestore/src/lite-api/stage.ts @@ -467,7 +467,7 @@ export class Replace implements Stage { name = 'replace_with'; constructor( - private field: Field, + private field: Expr, private mode: | 'full_replace' | 'merge_prefer_nest' diff --git a/packages/firestore/test/integration/api/pipeline.test.ts b/packages/firestore/test/integration/api/pipeline.test.ts index 6a3a34a0730..7fc26ce58cd 100644 --- a/packages/firestore/test/integration/api/pipeline.test.ts +++ b/packages/firestore/test/integration/api/pipeline.test.ts @@ -1297,8 +1297,8 @@ apiDescribe.only('Pipelines', persistence => { }); }); - describe('replace stage', () => { - it('run pipleine with replace', async () => { + describe('replaceWith stage', () => { + it('run pipeline with replaceWith field name', async () => { const snapshot = await execute( firestore .pipeline() @@ -1312,6 +1312,27 @@ apiDescribe.only('Pipelines', persistence => { others: { unknown: { year: 1980 } } }); }); + + it('run pipeline with replaceWith Expr result', async () => { + const snapshot = await execute( + firestore + .pipeline() + .collection(randomCol.path) + .where(eq('title', "The Hitchhiker's Guide to the Galaxy")) + .replaceWith( + map({ + foo: 'bar', + baz: { + title: field('title') + } + }) + ) + ); + expectResults(snapshot, { + foo: 'bar', + baz: { title: "The Hitchhiker's Guide to the Galaxy" } + }); + }); }); describe('sample stage', () => { From ddc7a6f6f22428f54cdb5b7544a89d64f6924dc3 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Fri, 21 Mar 2025 14:59:05 -0600 Subject: [PATCH 75/75] yarn format --- packages/firestore/pipelines/pipelines.d.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/firestore/pipelines/pipelines.d.ts b/packages/firestore/pipelines/pipelines.d.ts index 5e7944e5731..e7edb233991 100644 --- a/packages/firestore/pipelines/pipelines.d.ts +++ b/packages/firestore/pipelines/pipelines.d.ts @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {PipelineSource, Pipeline} from "../dist/pipelines"; +import { PipelineSource, Pipeline } from '../dist/pipelines'; // Augument the Firestore and Query classes with the pipeline() method. // This is stripped from dist/lite/pipelines.d.ts during the build @@ -23,9 +23,6 @@ declare module '@firebase/firestore' { interface Firestore { pipeline(): PipelineSource; } - interface Query { - pipeline(): Pipeline; - } } -export * from "../dist/pipelines"; +export * from '../dist/pipelines';