Skip to content

Commit a42b0d1

Browse files
committed
Change return type of execute from PipelineResult[] to PipelineSnapshot
1 parent 2e981af commit a42b0d1

File tree

6 files changed

+372
-329
lines changed

6 files changed

+372
-329
lines changed

packages/firestore/src/api/pipeline_impl.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { Pipeline } from '../api/pipeline';
1919
import { firestoreClientExecutePipeline } from '../core/firestore_client';
2020
import { toPipeline } from '../core/pipeline-util';
2121
import { Pipeline as LitePipeline } from '../lite-api/pipeline';
22-
import { PipelineResult } from '../lite-api/pipeline-result';
22+
import { PipelineResult, PipelineSnapshot } from '../lite-api/pipeline-result';
2323
import { PipelineSource } from '../lite-api/pipeline-source';
2424
import { Stage } from '../lite-api/stage';
2525
import { newUserDataReader } from '../lite-api/user_data_reader';
@@ -66,10 +66,16 @@ declare module './database' {
6666
* @param pipeline The pipeline to execute.
6767
* @return A Promise representing the asynchronous pipeline execution.
6868
*/
69-
export function execute(pipeline: LitePipeline): Promise<PipelineResult[]> {
69+
export function execute(pipeline: LitePipeline): Promise<PipelineSnapshot> {
7070
const firestore = cast(pipeline._db, Firestore);
7171
const client = ensureFirestoreConfigured(firestore);
7272
return firestoreClientExecutePipeline(client, pipeline).then(result => {
73+
// Get the execution time from the first result.
74+
// firestoreClientExecutePipeline returns at least one PipelineStreamElement
75+
// even if the returned document set is empty.
76+
const executionTime =
77+
result.length > 0 ? result[0].executionTime?.toTimestamp() : undefined;
78+
7379
const docs = result
7480
// Currently ignore any response from ExecutePipeline that does
7581
// not contain any document data in the `fields` property.
@@ -82,13 +88,12 @@ export function execute(pipeline: LitePipeline): Promise<PipelineResult[]> {
8288
? new DocumentReference(firestore, null, element.key)
8389
: undefined,
8490
element.fields,
85-
element.executionTime?.toTimestamp(),
8691
element.createTime?.toTimestamp(),
8792
element.updateTime?.toTimestamp()
8893
)
8994
);
9095

91-
return docs;
96+
return new PipelineSnapshot(pipeline, docs, executionTime);
9297
});
9398
}
9499

packages/firestore/src/lite-api/pipeline-result.ts

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,58 @@
1818
import { ObjectValue } from '../model/object_value';
1919
import { isOptionalEqual } from '../util/misc';
2020

21+
import { Field } from './expressions';
2122
import { FieldPath } from './field_path';
23+
import { Pipeline } from './pipeline';
2224
import { DocumentData, DocumentReference, refEqual } from './reference';
2325
import { fieldPathFromArgument } from './snapshot';
2426
import { Timestamp } from './timestamp';
2527
import { AbstractUserDataWriter } from './user_data_writer';
2628

29+
export class PipelineSnapshot {
30+
private readonly _pipeline: Pipeline;
31+
private readonly _executionTime: Timestamp | undefined;
32+
private readonly _results: PipelineResult[];
33+
constructor(
34+
pipeline: Pipeline,
35+
results: PipelineResult[],
36+
executionTime?: Timestamp
37+
) {
38+
this._pipeline = pipeline;
39+
this._executionTime = executionTime;
40+
this._results = results;
41+
}
42+
43+
/**
44+
* The Pipeline on which you called `execute()` in order to get this
45+
* `PipelineSnapshot`.
46+
*/
47+
get pipeline(): Pipeline {
48+
return this._pipeline;
49+
}
50+
51+
/** An array of all the results in the `PipelineSnapshot`. */
52+
get results(): PipelineResult[] {
53+
return this._results;
54+
}
55+
56+
/**
57+
* The time at which the pipeline producing this result is executed.
58+
*
59+
* @type {Timestamp}
60+
* @readonly
61+
*
62+
*/
63+
get executionTime(): Timestamp {
64+
if (this._executionTime === undefined) {
65+
throw new Error(
66+
"'executionTime' is expected to exist, but it is undefined"
67+
);
68+
}
69+
return this._executionTime;
70+
}
71+
}
72+
2773
/**
2874
* @beta
2975
*
@@ -36,7 +82,6 @@ import { AbstractUserDataWriter } from './user_data_writer';
3682
export class PipelineResult<AppModelType = DocumentData> {
3783
private readonly _userDataWriter: AbstractUserDataWriter;
3884

39-
private readonly _executionTime: Timestamp | undefined;
4085
private readonly _createTime: Timestamp | undefined;
4186
private readonly _updateTime: Timestamp | undefined;
4287

@@ -69,13 +114,11 @@ export class PipelineResult<AppModelType = DocumentData> {
69114
userDataWriter: AbstractUserDataWriter,
70115
ref?: DocumentReference,
71116
fields?: ObjectValue,
72-
executionTime?: Timestamp,
73117
createTime?: Timestamp,
74118
updateTime?: Timestamp
75119
) {
76120
this._ref = ref;
77121
this._userDataWriter = userDataWriter;
78-
this._executionTime = executionTime;
79122
this._createTime = createTime;
80123
this._updateTime = updateTime;
81124
this._fields = fields;
@@ -120,22 +163,6 @@ export class PipelineResult<AppModelType = DocumentData> {
120163
return this._updateTime;
121164
}
122165

123-
/**
124-
* The time at which the pipeline producing this result is executed.
125-
*
126-
* @type {Timestamp}
127-
* @readonly
128-
*
129-
*/
130-
get executionTime(): Timestamp {
131-
if (this._executionTime === undefined) {
132-
throw new Error(
133-
"'executionTime' is expected to exist, but it is undefined"
134-
);
135-
}
136-
return this._executionTime;
137-
}
138-
139166
/**
140167
* Retrieves all fields in the result as an object. Returns 'undefined' if
141168
* the document doesn't exist.
@@ -166,7 +193,7 @@ export class PipelineResult<AppModelType = DocumentData> {
166193
/**
167194
* Retrieves the field specified by `field`.
168195
*
169-
* @param {string|FieldPath} field The field path
196+
* @param {string|FieldPath|Field} field The field path
170197
* (e.g. 'foo' or 'foo.bar') to a specific field.
171198
* @returns {*} The data at the specified field location or undefined if no
172199
* such field exists.
@@ -184,7 +211,7 @@ export class PipelineResult<AppModelType = DocumentData> {
184211
// We deliberately use `any` in the external API to not impose type-checking
185212
// on end users.
186213
// eslint-disable-next-line @typescript-eslint/no-explicit-any
187-
get(fieldPath: string | FieldPath): any {
214+
get(fieldPath: string | FieldPath | Field): any {
188215
if (this._fields === undefined) {
189216
return undefined;
190217
}

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

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { invokeExecutePipeline } from '../remote/datastore';
2020
import { getDatastore } from './components';
2121
import { Firestore } from './database';
2222
import { Pipeline } from './pipeline';
23-
import { PipelineResult } from './pipeline-result';
23+
import { PipelineResult, PipelineSnapshot } from './pipeline-result';
2424
import { PipelineSource } from './pipeline-source';
2525
import { DocumentReference, Query } from './reference';
2626
import { LiteUserDataWriter } from './reference_impl';
@@ -70,28 +70,33 @@ declare module './reference' {
7070
* @param pipeline The pipeline to execute.
7171
* @return A Promise representing the asynchronous pipeline execution.
7272
*/
73-
export function execute(pipeline: Pipeline): Promise<PipelineResult[]> {
73+
export function execute(pipeline: Pipeline): Promise<PipelineSnapshot> {
7474
const datastore = getDatastore(pipeline._db);
7575
return invokeExecutePipeline(datastore, pipeline).then(result => {
76-
return (
77-
result
78-
// Currently ignore any response from ExecutePipeline that does
79-
// not contain any document data in the `fields` property.
80-
.filter(element => !!element.fields)
81-
.map(
82-
element =>
83-
new PipelineResult(
84-
pipeline._userDataWriter,
85-
element.key?.path
86-
? new DocumentReference(pipeline._db, null, element.key)
87-
: undefined,
88-
element.fields,
89-
element.executionTime?.toTimestamp(),
90-
element.createTime?.toTimestamp(),
91-
element.updateTime?.toTimestamp()
92-
)
93-
)
94-
);
76+
// Get the execution time from the first result.
77+
// firestoreClientExecutePipeline returns at least one PipelineStreamElement
78+
// even if the returned document set is empty.
79+
const executionTime =
80+
result.length > 0 ? result[0].executionTime?.toTimestamp() : undefined;
81+
82+
const docs = result
83+
// Currently ignore any response from ExecutePipeline that does
84+
// not contain any document data in the `fields` property.
85+
.filter(element => !!element.fields)
86+
.map(
87+
element =>
88+
new PipelineResult(
89+
pipeline._userDataWriter,
90+
element.key?.path
91+
? new DocumentReference(pipeline._db, null, element.key)
92+
: undefined,
93+
element.fields,
94+
element.createTime?.toTimestamp(),
95+
element.updateTime?.toTimestamp()
96+
)
97+
);
98+
99+
return new PipelineSnapshot(pipeline, docs, executionTime);
95100
});
96101
}
97102

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { FieldPath as InternalFieldPath } from '../model/path';
2323
import { arrayEquals } from '../util/misc';
2424

2525
import { Firestore } from './database';
26+
import { Field } from './expressions';
2627
import { FieldPath } from './field_path';
2728
import {
2829
DocumentData,
@@ -515,12 +516,14 @@ export function snapshotEqual<AppModelType, DbModelType extends DocumentData>(
515516
*/
516517
export function fieldPathFromArgument(
517518
methodName: string,
518-
arg: string | FieldPath | Compat<FieldPath>
519+
arg: string | FieldPath | Compat<FieldPath> | Field
519520
): InternalFieldPath {
520521
if (typeof arg === 'string') {
521522
return fieldPathFromDotSeparatedString(methodName, arg);
522523
} else if (arg instanceof FieldPath) {
523524
return arg._internalPath;
525+
} else if (arg instanceof Field) {
526+
return fieldPathFromDotSeparatedString(methodName, arg.fieldName());
524527
} else {
525528
return arg._delegate._internalPath;
526529
}

0 commit comments

Comments
 (0)