Skip to content

Commit 682997d

Browse files
committed
And/or overloads. Pipeline serialization for console.
1 parent ad82093 commit 682997d

File tree

8 files changed

+89
-116
lines changed

8 files changed

+89
-116
lines changed

common/api-review/firestore.api.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,15 @@ export class And extends FirestoreFunction implements FilterCondition {
100100
filterable: true;
101101
}
102102

103+
// @beta
104+
export function and(left: FilterExpr, ...right: FilterExpr[]): And;
105+
103106
// @public
104107
export function and(...queryConstraints: QueryFilterConstraint[]): QueryCompositeFilterConstraint;
105108

106-
// @beta
107-
export function andExpression(left: FilterExpr, ...right: FilterExpr[]): And;
109+
// @public (undocumented)
110+
export namespace and {
111+
}
108112

109113
// @beta (undocumented)
110114
export class ArrayConcat extends FirestoreFunction {
@@ -1738,9 +1742,16 @@ export class Or extends FirestoreFunction implements FilterCondition {
17381742
filterable: true;
17391743
}
17401744

1745+
// @beta
1746+
export function or(left: FilterExpr, ...right: FilterExpr[]): Or;
1747+
17411748
// @public
17421749
export function or(...queryConstraints: QueryFilterConstraint[]): QueryCompositeFilterConstraint;
17431750

1751+
// @public (undocumented)
1752+
export namespace or {
1753+
}
1754+
17441755
// @public
17451756
export function orderBy(fieldPath: string | FieldPath, directionStr?: OrderByDirection): QueryOrderByConstraint;
17461757

@@ -1752,9 +1763,6 @@ export class Ordering {
17521763
constructor(expr: Constant, direction: 'ascending' | 'descending');
17531764
}
17541765

1755-
// @beta
1756-
export function orExpression(left: FilterExpr, ...right: FilterExpr[]): Or;
1757-
17581766
// @public
17591767
export type PartialWithFieldValue<T> = Partial<T> | (T extends Primitive ? T : T extends {} ? {
17601768
[K in keyof T]?: PartialWithFieldValue<T[K]> | FieldValue;
@@ -2466,8 +2474,8 @@ export function xor(left: FilterExpr, ...right: FilterExpr[]): Xor;
24662474

24672475
// Warnings were encountered during analysis:
24682476
//
2469-
// /home/runner/work/firebase-js-sdk/firebase-js-sdk/packages/firestore/dist/index.d.ts:10111:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta
2470-
// /home/runner/work/firebase-js-sdk/firebase-js-sdk/packages/firestore/dist/index.d.ts:10112:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta
2471-
// /home/runner/work/firebase-js-sdk/firebase-js-sdk/packages/firestore/dist/index.d.ts:10141:9 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta
2477+
// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/index.d.ts:10115:9 - (ae-incompatible-release-tags) The symbol "accumulators" is marked as @public, but its signature references "AccumulatorTarget" which is marked as @beta
2478+
// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/index.d.ts:10116:9 - (ae-incompatible-release-tags) The symbol "groups" is marked as @public, but its signature references "Selectable" which is marked as @beta
2479+
// /Users/markduckworth/projects/firebase-js-sdk/packages/firestore/dist/index.d.ts:10145:9 - (ae-incompatible-release-tags) The symbol "orderings" is marked as @public, but its signature references "Ordering" which is marked as @beta
24722480

24732481
```

packages/firestore/src/api.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ export {
6161
arrayLength,
6262
inAny,
6363
notInAny,
64-
and as andExpression,
65-
or as orExpression,
6664
xor,
6765
ifFunction,
6866
not,
@@ -183,6 +181,8 @@ export {
183181
Accumulator
184182
} from './lite-api/expressions';
185183

184+
export { and, or } from './lite-api/overloads';
185+
186186
export {
187187
aggregateFieldEqual,
188188
aggregateQuerySnapshotEqual,
@@ -282,12 +282,10 @@ export {
282282
} from './api/reference';
283283

284284
export {
285-
and,
286285
endAt,
287286
endBefore,
288287
limit,
289288
limitToLast,
290-
or,
291289
orderBy,
292290
OrderByDirection,
293291
query,
@@ -392,7 +390,8 @@ export { isBase64Available as _isBase64Available } from './platform/base64';
392390
export { DatabaseId as _DatabaseId } from './core/database_info';
393391
export {
394392
_internalQueryToProtoQueryTarget,
395-
_internalAggregationQueryToProtoRunAggregationQueryRequest
393+
_internalAggregationQueryToProtoRunAggregationQueryRequest,
394+
_internalPipelineToExecutePipelineRequestProto
396395
} from './remote/internal_serializer';
397396
export {
398397
cast as _cast,

packages/firestore/src/api/database.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import {
4646
connectFirestoreEmulator,
4747
Firestore as LiteFirestore
4848
} from '../lite-api/database';
49+
import type { PipelineSource } from '../lite-api/pipeline-source';
4950
import { Query } from '../lite-api/reference';
5051
import {
5152
indexedDbClearPersistence,
@@ -128,17 +129,16 @@ export class Firestore extends LiteFirestore {
128129
await terminate;
129130
}
130131
}
131-
}
132132

133-
// Undocumented method of Firestore. This is only
134-
// in place to give developers a runtime error suggesting
135-
// how to correctly initialize Firestore for use with Pipelines.
136-
// @ts-ignore
137-
Firestore.prototype.pipeline = function (): unknown {
138-
throw new Error(
139-
'Pipelines not initialized. Your application must call `useFirestorePipelines()` before using Firestore Pipeline features.'
140-
);
141-
};
133+
/**
134+
* Pipeline query.
135+
*/
136+
pipeline(): PipelineSource {
137+
throw new Error(
138+
'Pipelines not initialized. Your application must call `useFirestorePipelines()` before using Firestore Pipeline features.'
139+
);
140+
}
141+
}
142142

143143
/**
144144
* Initializes a new instance of {@link Firestore} with the provided settings.

packages/firestore/src/api/database_augmentation.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { And, FilterExpr, Or } from '../lite-api/expressions';
2+
import { and, or } from '../lite-api/overloads';
13
import { Pipeline } from '../lite-api/pipeline';
24
import { PipelineSource } from '../lite-api/pipeline-source';
35
import { newUserDataReader } from '../lite-api/user_data_reader';
@@ -37,4 +39,12 @@ export function useFirestorePipelines(): void {
3739

3840
return pipeline;
3941
};
42+
43+
and._andFunction = function (left: FilterExpr, ...right: FilterExpr[]): And {
44+
return new And([left, ...right]);
45+
};
46+
47+
or._orFunction = function (left: FilterExpr, ...right: FilterExpr[]): Or {
48+
return new Or([left, ...right]);
49+
};
4050
}

packages/firestore/src/lite-api/expressions.ts

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4517,44 +4517,6 @@ export function notInAny(element: Expr | string, others: any[]): Not {
45174517
return new Not(new In(elementExpr, exprOthers));
45184518
}
45194519

4520-
/**
4521-
* @beta
4522-
*
4523-
* Creates an expression that performs a logical 'AND' operation on multiple filter conditions.
4524-
*
4525-
* ```typescript
4526-
* // Check if the 'age' field is greater than 18 AND the 'city' field is "London" AND
4527-
* // the 'status' field is "active"
4528-
* const condition = and(gt("age", 18), eq("city", "London"), eq("status", "active"));
4529-
* ```
4530-
*
4531-
* @param left The first filter condition.
4532-
* @param right Additional filter conditions to 'AND' together.
4533-
* @return A new {@code Expr} representing the logical 'AND' operation.
4534-
*/
4535-
export function and(left: FilterExpr, ...right: FilterExpr[]): And {
4536-
return new And([left, ...right]);
4537-
}
4538-
4539-
/**
4540-
* @beta
4541-
*
4542-
* Creates an expression that performs a logical 'OR' operation on multiple filter conditions.
4543-
*
4544-
* ```typescript
4545-
* // Check if the 'age' field is greater than 18 OR the 'city' field is "London" OR
4546-
* // the 'status' field is "active"
4547-
* const condition = or(gt("age", 18), eq("city", "London"), eq("status", "active"));
4548-
* ```
4549-
*
4550-
* @param left The first filter condition.
4551-
* @param right Additional filter conditions to 'OR' together.
4552-
* @return A new {@code Expr} representing the logical 'OR' operation.
4553-
*/
4554-
export function or(left: FilterExpr, ...right: FilterExpr[]): Or {
4555-
return new Or([left, ...right]);
4556-
}
4557-
45584520
/**
45594521
* @beta
45604522
*

packages/firestore/src/lite-api/query.ts

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -367,54 +367,6 @@ export type QueryFilterConstraint =
367367
| QueryFieldFilterConstraint
368368
| QueryCompositeFilterConstraint;
369369

370-
/**
371-
* Creates a new {@link QueryCompositeFilterConstraint} that is a disjunction of
372-
* the given filter constraints. A disjunction filter includes a document if it
373-
* satisfies any of the given filters.
374-
*
375-
* @param queryConstraints - Optional. The list of
376-
* {@link QueryFilterConstraint}s to perform a disjunction for. These must be
377-
* created with calls to {@link where}, {@link or}, or {@link and}.
378-
* @returns The newly created {@link QueryCompositeFilterConstraint}.
379-
*/
380-
export function or(
381-
...queryConstraints: QueryFilterConstraint[]
382-
): QueryCompositeFilterConstraint {
383-
// Only support QueryFilterConstraints
384-
queryConstraints.forEach(queryConstraint =>
385-
validateQueryFilterConstraint('or', queryConstraint)
386-
);
387-
388-
return QueryCompositeFilterConstraint._create(
389-
CompositeOperator.OR,
390-
queryConstraints as QueryFilterConstraint[]
391-
);
392-
}
393-
394-
/**
395-
* Creates a new {@link QueryCompositeFilterConstraint} that is a conjunction of
396-
* the given filter constraints. A conjunction filter includes a document if it
397-
* satisfies all of the given filters.
398-
*
399-
* @param queryConstraints - Optional. The list of
400-
* {@link QueryFilterConstraint}s to perform a conjunction for. These must be
401-
* created with calls to {@link where}, {@link or}, or {@link and}.
402-
* @returns The newly created {@link QueryCompositeFilterConstraint}.
403-
*/
404-
export function and(
405-
...queryConstraints: QueryFilterConstraint[]
406-
): QueryCompositeFilterConstraint {
407-
// Only support QueryFilterConstraints
408-
queryConstraints.forEach(queryConstraint =>
409-
validateQueryFilterConstraint('and', queryConstraint)
410-
);
411-
412-
return QueryCompositeFilterConstraint._create(
413-
CompositeOperator.AND,
414-
queryConstraints as QueryFilterConstraint[]
415-
);
416-
}
417-
418370
/**
419371
* A `QueryOrderByConstraint` is used to sort the set of documents returned by a
420372
* Firestore query. `QueryOrderByConstraint`s are created by invoking

packages/firestore/src/remote/internal_serializer.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { ensureFirestoreConfigured, Firestore } from '../api/database';
1919
import { AggregateImpl } from '../core/aggregate';
2020
import { queryToAggregateTarget, queryToTarget } from '../core/query';
2121
import { AggregateSpec } from '../lite-api/aggregate_types';
22+
import { Pipeline } from '../lite-api/pipeline';
2223
import { Query } from '../lite-api/reference';
2324
import { cast } from '../util/input_validation';
2425
import { mapToArray } from '../util/obj';
@@ -87,3 +88,28 @@ export function _internalAggregationQueryToProtoRunAggregationQueryRequest<
8788
/* skipAliasing= */ true
8889
).request;
8990
}
91+
92+
/**
93+
* @internal
94+
* @private
95+
*
96+
* This function is for internal use only.
97+
*
98+
* Returns the `ExecutePipelineRequest` representation of the given query.
99+
* Returns `null` if the Firestore client associated with the given query has
100+
* not been initialized or has been terminated.
101+
*
102+
* @param pipeline - The Pipeline to convert to proto representation.
103+
*/
104+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
105+
export function _internalPipelineToExecutePipelineRequestProto(
106+
pipeline: Pipeline
107+
): any {
108+
const firestore = cast(pipeline._db, Firestore);
109+
const client = ensureFirestoreConfigured(firestore);
110+
const serializer = client._onlineComponents?.datastore.serializer;
111+
if (serializer === undefined) {
112+
return null;
113+
}
114+
return pipeline._toProto(serializer);
115+
}

packages/firestore/test/integration/api/pipeline.test.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ import chaiAsPromised from 'chai-as-promised';
1818
import { addEqualityMatcher } from '../../util/equality_matcher';
1919
import { Deferred } from '../../util/promise';
2020
import {
21+
_internalPipelineToExecutePipelineRequestProto,
2122
add,
22-
andExpression,
23+
and,
2324
arrayContains,
2425
arrayContainsAny,
2526
avg,
@@ -42,7 +43,7 @@ import {
4243
mapGet,
4344
neq,
4445
not,
45-
orExpression,
46+
or,
4647
PipelineResult,
4748
regexContains,
4849
regexMatch,
@@ -384,15 +385,15 @@ apiDescribe.only('Pipelines', persistence => {
384385
it('where with and', async () => {
385386
const results = await randomCol
386387
.pipeline()
387-
.where(andExpression(gt('rating', 4.5), eq('genre', 'Science Fiction')))
388+
.where(and(gt('rating', 4.5), eq('genre', 'Science Fiction')))
388389
.execute();
389390
expectResults(results, 'book10');
390391
});
391392

392393
it('where with or', async () => {
393394
const results = await randomCol
394395
.pipeline()
395-
.where(orExpression(eq('genre', 'Romance'), eq('genre', 'Dystopian')))
396+
.where(or(eq('genre', 'Romance'), eq('genre', 'Dystopian')))
396397
.select('title')
397398
.execute();
398399
expectResults(
@@ -637,7 +638,7 @@ apiDescribe.only('Pipelines', persistence => {
637638
const results = await randomCol
638639
.pipeline()
639640
.where(
640-
andExpression(
641+
and(
641642
gt('rating', 4.2),
642643
lte(Field.of('rating'), 4.5),
643644
neq('genre', 'Science Fiction')
@@ -661,8 +662,8 @@ apiDescribe.only('Pipelines', persistence => {
661662
const results = await randomCol
662663
.pipeline()
663664
.where(
664-
orExpression(
665-
andExpression(gt('rating', 4.5), eq('genre', 'Science Fiction')),
665+
or(
666+
and(gt('rating', 4.5), eq('genre', 'Science Fiction')),
666667
lt('published', 1900)
667668
)
668669
)
@@ -793,6 +794,21 @@ apiDescribe.only('Pipelines', persistence => {
793794
);
794795
});
795796

797+
it('supports internal serialization to proto', async () => {
798+
const pipeline = firestore
799+
.pipeline()
800+
.collection('books')
801+
.where(eq('awards.hugo', true))
802+
.select(
803+
'title',
804+
Field.of('nestedField.level.1'),
805+
mapGet('nestedField', 'level.1').mapGet('level.2').as('nested')
806+
);
807+
808+
const proto = _internalPipelineToExecutePipelineRequestProto(pipeline);
809+
expect(proto).not.to.be.null;
810+
});
811+
796812
// TODO(pipeline) support converter
797813
// it('pipeline converter works', async () => {
798814
// interface AppModel {myTitle: string; myAuthor: string; myPublished: number}

0 commit comments

Comments
 (0)