Skip to content

Commit 4cab3ec

Browse files
authored
Release Bundles for Next SDK (#4352)
1 parent 8f7be4e commit 4cab3ec

File tree

10 files changed

+184
-61
lines changed

10 files changed

+184
-61
lines changed

common/api-review/firestore-exp.api.md

+28
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,33 @@ export function limit(limit: number): QueryConstraint;
278278
// @public
279279
export function limitToLast(limit: number): QueryConstraint;
280280

281+
// @public
282+
export function loadBundle(firestore: FirebaseFirestore, bundleData: ReadableStream<Uint8Array> | ArrayBuffer | string): LoadBundleTask;
283+
284+
// @public
285+
export class LoadBundleTask implements PromiseLike<LoadBundleTaskProgress> {
286+
catch<R>(onRejected: (a: Error) => R | PromiseLike<R>): Promise<R | LoadBundleTaskProgress>;
287+
_completeWith(progress: LoadBundleTaskProgress): void;
288+
_failWith(error: FirestoreError): void;
289+
onProgress(next?: (progress: LoadBundleTaskProgress) => unknown, error?: (err: Error) => unknown, complete?: () => void): void;
290+
then<T, R>(onFulfilled?: (a: LoadBundleTaskProgress) => T | PromiseLike<T>, onRejected?: (a: Error) => R | PromiseLike<R>): Promise<T | R>;
291+
_updateProgress(progress: LoadBundleTaskProgress): void;
292+
}
293+
294+
// @public
295+
export interface LoadBundleTaskProgress {
296+
bytesLoaded: number;
297+
documentsLoaded: number;
298+
taskState: TaskState;
299+
totalBytes: number;
300+
totalDocuments: number;
301+
}
302+
281303
export { LogLevel }
282304

305+
// @public
306+
export function namedQuery(firestore: FirebaseFirestore, name: string): Promise<Query | null>;
307+
283308
// @public
284309
export function onSnapshot<T>(reference: DocumentReference<T>, observer: {
285310
next?: (snapshot: DocumentSnapshot<T>) => void;
@@ -463,6 +488,9 @@ export function startAt(snapshot: DocumentSnapshot_2<unknown>): QueryConstraint;
463488
// @public
464489
export function startAt(...fieldValues: unknown[]): QueryConstraint;
465490

491+
// @public
492+
export type TaskState = 'Error' | 'Running' | 'Success';
493+
466494
// @public
467495
export function terminate(firestore: FirebaseFirestore): Promise<void>;
468496

packages/firestore/exp/index.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,17 @@ export {
3232
disableNetwork,
3333
enableNetwork,
3434
terminate,
35-
useFirestoreEmulator
35+
useFirestoreEmulator,
36+
loadBundle,
37+
namedQuery
3638
} from '../src/exp/database';
3739

40+
export {
41+
LoadBundleTask,
42+
LoadBundleTaskProgress,
43+
TaskState
44+
} from '../src/exp/bundle';
45+
3846
export { Settings, PersistenceSettings } from '../src/exp/settings';
3947

4048
export {

packages/firestore/export.ts

+31-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515
* limitations under the License.
1616
*/
1717

18+
import { Firestore, Query } from './src/api/database';
19+
import { LoadBundleTask } from './src/exp/bundle';
20+
import {
21+
loadBundle as expLoadBundle,
22+
namedQuery as expNamedQuery
23+
} from './src/exp/database';
24+
1825
export { Blob } from './src/api/blob';
1926
export {
2027
CollectionReference,
@@ -36,4 +43,27 @@ export { FieldPath } from './src/api/field_path';
3643
export { FieldValue } from './src/api/field_value';
3744
export { Timestamp } from './src/api/timestamp';
3845
export { FirebaseFirestore as ExpFirebaseFirestore } from './src/exp/database';
39-
export { loadBundle, namedQuery } from './src/api/bundle';
46+
47+
export function loadBundle(
48+
this: Firestore,
49+
data: ArrayBuffer | ReadableStream<Uint8Array> | string
50+
): LoadBundleTask {
51+
return expLoadBundle(this._delegate, data);
52+
}
53+
54+
export function namedQuery(
55+
this: Firestore,
56+
queryName: string
57+
): Promise<Query | null> {
58+
return expNamedQuery(this._delegate, queryName).then(expQuery => {
59+
if (!expQuery) {
60+
return null;
61+
}
62+
return new Query(
63+
this,
64+
// We can pass `expQuery` here directly since named queries don't have a UserDataConverter.
65+
// Otherwise, we would have to create a new ExpQuery and pass the old UserDataConverter.
66+
expQuery
67+
);
68+
});
69+
}

packages/firestore/index.bundle.ts

+2-12
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,8 @@ import { Firestore, loadBundle, namedQuery } from './export';
2121
* Prototype patches bundle loading to Firestore.
2222
*/
2323
export function registerBundle(instance: typeof Firestore): void {
24-
instance.prototype.loadBundle = function (
25-
this: Firestore,
26-
data: ArrayBuffer | ReadableStream<Uint8Array> | string
27-
) {
28-
return loadBundle(this, data);
29-
};
30-
instance.prototype.namedQuery = function (
31-
this: Firestore,
32-
queryName: string
33-
) {
34-
return namedQuery(this, queryName);
35-
};
24+
instance.prototype.loadBundle = loadBundle;
25+
instance.prototype.namedQuery = namedQuery;
3626
}
3727

3828
registerBundle(Firestore);

packages/firestore/src/api/database.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import {
4646
} from '@firebase/firestore-types';
4747

4848
import { DatabaseId } from '../core/database_info';
49+
import { LoadBundleTask } from '../exp/bundle';
4950
import { Bytes } from '../exp/bytes';
5051
import {
5152
clearIndexedDbPersistence,
@@ -122,7 +123,6 @@ import {
122123
import { setLogLevel as setClientLogLevel } from '../util/log';
123124

124125
import { Blob } from './blob';
125-
import { LoadBundleTask } from './bundle';
126126
import { Compat } from './compat';
127127
import {
128128
CompleteFn,

packages/firestore/src/core/firestore_client.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717

1818
import { GetOptions } from '@firebase/firestore-types';
1919

20-
import { LoadBundleTask } from '../api/bundle';
2120
import {
2221
CredentialChangeListener,
2322
CredentialsProvider
2423
} from '../api/credentials';
2524
import { User } from '../auth/user';
25+
import { LoadBundleTask } from '../exp/bundle';
2626
import { LocalStore } from '../local/local_store';
2727
import {
2828
localStoreExecuteQuery,

packages/firestore/src/core/sync_engine_impl.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { LoadBundleTask } from '../api/bundle';
1918
import { User } from '../auth/user';
19+
import { LoadBundleTask } from '../exp/bundle';
2020
import { ignoreIfPrimaryLeaseLoss, LocalStore } from '../local/local_store';
2121
import {
2222
localStoreAcknowledgeBatch,

packages/firestore/src/api/bundle.ts renamed to packages/firestore/src/exp/bundle.ts

+57-42
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,42 @@
1515
* limitations under the License.
1616
*/
1717

18-
import {
19-
LoadBundleTask as ApiLoadBundleTask,
20-
LoadBundleTaskProgress
21-
} from '@firebase/firestore-types';
22-
23-
import { ensureFirestoreConfigured } from '../../src/exp/database';
24-
import { Query as ExpQuery } from '../../src/exp/reference';
25-
import {
26-
firestoreClientGetNamedQuery,
27-
firestoreClientLoadBundle
28-
} from '../core/firestore_client';
18+
import { PartialObserver } from '../api/observer';
2919
import { debugAssert } from '../util/assert';
3020
import { FirestoreError } from '../util/error';
3121
import { Deferred } from '../util/promise';
3222

33-
import { Query, Firestore } from './database';
34-
import { PartialObserver } from './observer';
23+
/**
24+
* Represents the state of bundle loading tasks.
25+
*
26+
* Both 'Error' and 'Success' are sinking state: task will abort or complete and there will
27+
* be no more updates after they are reported.
28+
*/
29+
export type TaskState = 'Error' | 'Running' | 'Success';
3530

36-
export class LoadBundleTask
37-
implements ApiLoadBundleTask, PromiseLike<LoadBundleTaskProgress> {
31+
/**
32+
* Represents a progress update or a final state from loading bundles.
33+
*/
34+
export interface LoadBundleTaskProgress {
35+
/** How many documents have been loaded. */
36+
documentsLoaded: number;
37+
/** How many documents are in the bundle being loaded. */
38+
totalDocuments: number;
39+
/** How many bytes have been loaded. */
40+
bytesLoaded: number;
41+
/** How many bytes are in the bundle being loaded. */
42+
totalBytes: number;
43+
/** Current task state. */
44+
taskState: TaskState;
45+
}
46+
47+
/**
48+
* Represents the task of loading a Firestore bundle. It provides progress of bundle
49+
* loading, as well as task completion and error events.
50+
*
51+
* The API is compatible with `Promise<LoadBundleTaskProgress>`.
52+
*/
53+
export class LoadBundleTask implements PromiseLike<LoadBundleTaskProgress> {
3854
private _progressObserver: PartialObserver<LoadBundleTaskProgress> = {};
3955
private _taskCompletionResolver = new Deferred<LoadBundleTaskProgress>();
4056

@@ -46,6 +62,14 @@ export class LoadBundleTask
4662
documentsLoaded: 0
4763
};
4864

65+
/**
66+
* Registers functions to listen to bundle loading progress events.
67+
* @param next - Called when there is a progress update from bundle loading. Typically `next` calls occur
68+
* each time a Firestore document is loaded from the bundle.
69+
* @param error - Called when an error occurs during bundle loading. The task aborts after reporting the
70+
* error, and there should be no more updates after this.
71+
* @param complete - Called when the loading task is complete.
72+
*/
4973
onProgress(
5074
next?: (progress: LoadBundleTaskProgress) => unknown,
5175
error?: (err: Error) => unknown,
@@ -58,12 +82,24 @@ export class LoadBundleTask
5882
};
5983
}
6084

85+
/**
86+
* Implements the `Promise<LoadBundleTaskProgress>.catch` interface.
87+
*
88+
* @param onRejected - Called when an error occurs during bundle loading.
89+
*/
6190
catch<R>(
6291
onRejected: (a: Error) => R | PromiseLike<R>
6392
): Promise<R | LoadBundleTaskProgress> {
6493
return this._taskCompletionResolver.promise.catch(onRejected);
6594
}
6695

96+
/**
97+
* Implements the `Promise<LoadBundleTaskProgress>.then` interface.
98+
*
99+
* @param onFulfilled - Called on the completion of the loading task with a final `LoadBundleTaskProgress` update.
100+
* The update will always have its `taskState` set to `"Success"`.
101+
* @param onRejected - Called when an error occurs during bundle loading.
102+
*/
67103
then<T, R>(
68104
onFulfilled?: (a: LoadBundleTaskProgress) => T | PromiseLike<T>,
69105
onRejected?: (a: Error) => R | PromiseLike<R>
@@ -74,6 +110,8 @@ export class LoadBundleTask
74110
/**
75111
* Notifies all observers that bundle loading has completed, with a provided
76112
* `LoadBundleTaskProgress` object.
113+
*
114+
* @private
77115
*/
78116
_completeWith(progress: LoadBundleTaskProgress): void {
79117
debugAssert(
@@ -91,6 +129,8 @@ export class LoadBundleTask
91129
/**
92130
* Notifies all observers that bundle loading has failed, with a provided
93131
* `Error` as the reason.
132+
*
133+
* @private
94134
*/
95135
_failWith(error: FirestoreError): void {
96136
this._lastProgress.taskState = 'Error';
@@ -109,6 +149,8 @@ export class LoadBundleTask
109149
/**
110150
* Notifies a progress update of loading a bundle.
111151
* @param progress - The new progress.
152+
*
153+
* @private
112154
*/
113155
_updateProgress(progress: LoadBundleTaskProgress): void {
114156
debugAssert(
@@ -122,30 +164,3 @@ export class LoadBundleTask
122164
}
123165
}
124166
}
125-
126-
export function loadBundle(
127-
db: Firestore,
128-
bundleData: ArrayBuffer | ReadableStream<Uint8Array> | string
129-
): LoadBundleTask {
130-
const resultTask = new LoadBundleTask();
131-
firestoreClientLoadBundle(
132-
ensureFirestoreConfigured(db._delegate),
133-
db._databaseId,
134-
bundleData,
135-
resultTask
136-
);
137-
return resultTask;
138-
}
139-
140-
export function namedQuery(db: Firestore, name: string): Promise<Query | null> {
141-
return firestoreClientGetNamedQuery(
142-
ensureFirestoreConfigured(db._delegate),
143-
name
144-
).then(namedQuery => {
145-
if (!namedQuery) {
146-
return null;
147-
}
148-
149-
return new Query(db, new ExpQuery(db._delegate, null, namedQuery.query));
150-
});
151-
}

0 commit comments

Comments
 (0)