Skip to content

Commit dd1e63c

Browse files
Add remaining firestore-exp functionality (#3321)
1 parent 982acf9 commit dd1e63c

File tree

7 files changed

+16220
-31
lines changed

7 files changed

+16220
-31
lines changed

.changeset/twelve-spiders-return.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

packages/firestore/exp/index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export function waitForPendingWrites(
9191
export function enableNetwork(firestore: FirebaseFirestore): Promise<void>;
9292
export function disableNetwork(firestore: FirebaseFirestore): Promise<void>;
9393

94+
// TODO(firestoreexp): Add experimentalForceOwningTab support
9495
export function enableIndexedDbPersistence(
9596
firestore: FirebaseFirestore
9697
): Promise<void>;

packages/firestore/exp/index.node.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,22 @@ import { Firestore } from './src/api/database';
2323
export { FieldPath, documentId } from '../lite/src/api/field_path';
2424

2525
export {
26-
Firestore,
26+
Firestore as FirebaseFirestore,
2727
initializeFirestore,
2828
getFirestore,
29+
enableIndexedDbPersistence,
30+
enableMultiTabIndexedDbPersistence,
31+
clearIndexedDbPersistence,
32+
waitForPendingWrites,
33+
disableNetwork,
34+
enableNetwork,
2935
terminate
3036
} from './src/api/database';
3137

3238
export {
3339
DocumentSnapshot,
3440
QueryDocumentSnapshot,
41+
QuerySnapshot,
3542
snapshotEqual
3643
} from './src/api/snapshot';
3744

@@ -53,6 +60,9 @@ export {
5360
getDoc,
5461
getDocFromCache,
5562
getDocFromServer,
63+
getQuery,
64+
getQueryFromCache,
65+
getQueryFromServer,
5666
onSnapshot,
5767
onSnapshotsInSync,
5868
setDoc,

packages/firestore/exp/src/api/database.ts

+123-2
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,22 @@ import { FirebaseApp, _FirebaseService } from '@firebase/app-types-exp';
2222
import { Provider } from '@firebase/component';
2323

2424
import { FirebaseAuthInternalName } from '@firebase/auth-interop-types';
25-
import { FirestoreClient } from '../../../src/core/firestore_client';
25+
import {
26+
FirestoreClient,
27+
PersistenceSettings
28+
} from '../../../src/core/firestore_client';
2629
import { AsyncQueue } from '../../../src/util/async_queue';
2730
import {
2831
ComponentProvider,
32+
IndexedDbComponentProvider,
2933
MemoryComponentProvider
3034
} from '../../../src/core/component_provider';
3135

3236
import { Firestore as LiteFirestore } from '../../../lite/src/api/database';
3337
import { cast } from '../../../lite/src/api/util';
38+
import { Code, FirestoreError } from '../../../src/util/error';
39+
import { Deferred } from '../../../src/util/promise';
40+
import { LruParams } from '../../../src/local/lru_garbage_collector';
3441

3542
/**
3643
* The root reference to the Firestore database and the entry point for the
@@ -45,10 +52,13 @@ export class Firestore extends LiteFirestore
4552
// Assigned via _getFirestoreClient()
4653
private _firestoreClientPromise?: Promise<FirestoreClient>;
4754

55+
protected _persistenceSettings: PersistenceSettings = { durable: false };
4856
// We override the Settings property of the Lite SDK since the full Firestore
4957
// SDK supports more settings.
5058
protected _settings?: firestore.Settings;
5159

60+
_terminated: boolean = false;
61+
5262
constructor(
5363
app: FirebaseApp,
5464
authProvider: Provider<FirebaseAuthInternalName>
@@ -80,16 +90,72 @@ export class Firestore extends LiteFirestore
8090
);
8191

8292
this._firestoreClientPromise = firestoreClient
83-
.start(this._componentProvider, { durable: false })
93+
.start(this._componentProvider, this._persistenceSettings)
8494
.then(() => firestoreClient);
8595
}
8696

8797
return this._firestoreClientPromise;
8898
}
8999

100+
// TODO(firestorexp): Factor out MultiTabComponentProvider and remove
101+
// `synchronizeTabs` argument
102+
_enablePersistence(
103+
persistenceProvider: ComponentProvider,
104+
synchronizeTabs: boolean
105+
): Promise<void> {
106+
if (this._firestoreClientPromise) {
107+
throw new FirestoreError(
108+
Code.FAILED_PRECONDITION,
109+
'Firestore has already been started and persistence can no longer ' +
110+
'be enabled. You can only call enable persistence before calling ' +
111+
'any other methods on a Firestore object.'
112+
);
113+
}
114+
115+
const settings = this._getSettings();
116+
this._persistenceSettings = {
117+
durable: true,
118+
synchronizeTabs,
119+
forceOwningTab: false,
120+
cacheSizeBytes:
121+
settings.cacheSizeBytes ?? LruParams.DEFAULT_CACHE_SIZE_BYTES
122+
};
123+
this._componentProvider = persistenceProvider;
124+
125+
// TODO(firestorexp): Add support for Persistence fallback
126+
return this._getFirestoreClient().then(() => {});
127+
}
128+
90129
delete(): Promise<void> {
91130
return terminate(this);
92131
}
132+
133+
_clearPersistence(): Promise<void> {
134+
if (this._firestoreClientPromise !== undefined && !this._terminated) {
135+
throw new FirestoreError(
136+
Code.FAILED_PRECONDITION,
137+
'Persistence can only be cleared before the Firestore instance is ' +
138+
'initialized or after it is terminated.'
139+
);
140+
}
141+
142+
const settings = this._getSettings();
143+
const deferred = new Deferred<void>();
144+
this._queue.enqueueAndForgetEvenAfterShutdown(async () => {
145+
try {
146+
const databaseInfo = this._makeDatabaseInfo(
147+
settings.host,
148+
settings.ssl,
149+
settings.experimentalForceLongPolling
150+
);
151+
await this._componentProvider.clearPersistence(databaseInfo);
152+
deferred.resolve();
153+
} catch (e) {
154+
deferred.reject(e);
155+
}
156+
});
157+
return deferred.promise;
158+
}
93159
}
94160

95161
export function initializeFirestore(
@@ -108,11 +174,66 @@ export function getFirestore(app: FirebaseApp): Firestore {
108174
return _getProvider(app, 'firestore-exp').getImmediate() as Firestore;
109175
}
110176

177+
export function enableIndexedDbPersistence(
178+
firestore: firestore.FirebaseFirestore
179+
): Promise<void> {
180+
const firestoreImpl = cast(firestore, Firestore);
181+
return firestoreImpl._enablePersistence(
182+
new IndexedDbComponentProvider(),
183+
/*synchronizeTabs=*/ false
184+
);
185+
}
186+
187+
export function enableMultiTabIndexedDbPersistence(
188+
firestore: firestore.FirebaseFirestore
189+
): Promise<void> {
190+
const firestoreImpl = cast(firestore, Firestore);
191+
return firestoreImpl._enablePersistence(
192+
new IndexedDbComponentProvider(),
193+
/*synchronizeTabs=*/ true
194+
);
195+
}
196+
197+
export function clearIndexedDbPersistence(
198+
firestore: firestore.FirebaseFirestore
199+
): Promise<void> {
200+
const firestoreImpl = cast(firestore, Firestore);
201+
return firestoreImpl._clearPersistence();
202+
}
203+
204+
export function waitForPendingWrites(
205+
firestore: firestore.FirebaseFirestore
206+
): Promise<void> {
207+
const firestoreImpl = cast(firestore, Firestore);
208+
return firestoreImpl
209+
._getFirestoreClient()
210+
.then(firestoreClient => firestoreClient.waitForPendingWrites());
211+
}
212+
213+
export function enableNetwork(
214+
firestore: firestore.FirebaseFirestore
215+
): Promise<void> {
216+
const firestoreImpl = cast(firestore, Firestore);
217+
return firestoreImpl
218+
._getFirestoreClient()
219+
.then(firestoreClient => firestoreClient.enableNetwork());
220+
}
221+
222+
export function disableNetwork(
223+
firestore: firestore.FirebaseFirestore
224+
): Promise<void> {
225+
const firestoreImpl = cast(firestore, Firestore);
226+
return firestoreImpl
227+
._getFirestoreClient()
228+
.then(firestoreClient => firestoreClient.disableNetwork());
229+
}
230+
111231
export function terminate(
112232
firestore: firestore.FirebaseFirestore
113233
): Promise<void> {
114234
_removeServiceInstance(firestore.app, 'firestore/lite');
115235
const firestoreImpl = cast(firestore, Firestore);
236+
firestoreImpl._terminated = true;
116237
return firestoreImpl
117238
._getFirestoreClient()
118239
.then(firestoreClient => firestoreClient.terminate());

0 commit comments

Comments
 (0)