Skip to content

Commit 0767aa6

Browse files
Using Compat-Layer for IndexedDB persistence
1 parent 79b0493 commit 0767aa6

File tree

6 files changed

+182
-301
lines changed

6 files changed

+182
-301
lines changed

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

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { FirebaseFirestore } from './database';
18+
import { FirebaseFirestore, FirestoreCompat } from './database';
1919
import {
2020
MemoryOfflineComponentProvider,
2121
OfflineComponentProvider,
@@ -44,28 +44,27 @@ const LOG_TAG = 'ComponentProvider';
4444
// Instance maps that ensure that only one component provider exists per
4545
// Firestore instance.
4646
const offlineComponentProviders = new Map<
47-
FirebaseFirestore,
47+
FirestoreCompat,
4848
OfflineComponentProvider
4949
>();
5050
const onlineComponentProviders = new Map<
51-
FirebaseFirestore,
51+
FirestoreCompat,
5252
OnlineComponentProvider
5353
>();
5454

5555
export async function setOfflineComponentProvider(
56-
firestore: FirebaseFirestore,
56+
firestore: FirestoreCompat,
5757
offlineComponentProvider: OfflineComponentProvider
5858
): Promise<void> {
59+
firestore._queue.verifyOperationInProgress();
60+
5961
logDebug(LOG_TAG, 'Initializing OfflineComponentProvider');
6062
const configuration = await firestore._getConfiguration();
6163
await offlineComponentProvider.initialize(configuration);
6264
firestore._setCredentialChangeListener(user =>
63-
// TODO(firestorexp): This should be a retryable IndexedDB operation
64-
firestore._queue.enqueueAndForget(() =>
65-
// TODO(firestorexp): Make sure handleUserChange is a no-op if user
66-
// didn't change
67-
handleUserChange(offlineComponentProvider.localStore, user)
68-
)
65+
firestore._queue.enqueueRetryable(async () => {
66+
await handleUserChange(offlineComponentProvider.localStore, user);
67+
})
6968
);
7069
// When a user calls clearPersistence() in one client, all other clients
7170
// need to be terminated to allow the delete to succeed.
@@ -77,24 +76,23 @@ export async function setOfflineComponentProvider(
7776
}
7877

7978
export async function setOnlineComponentProvider(
80-
firestore: FirebaseFirestore,
79+
firestore: FirestoreCompat,
8180
onlineComponentProvider: OnlineComponentProvider
8281
): Promise<void> {
8382
firestore._queue.verifyOperationInProgress();
8483

85-
const configuration = await firestore._getConfiguration();
8684
const offlineComponentProvider = await getOfflineComponentProvider(firestore);
8785

8886
logDebug(LOG_TAG, 'Initializing OnlineComponentProvider');
87+
const configuration = await firestore._getConfiguration();
8988
await onlineComponentProvider.initialize(
9089
offlineComponentProvider,
9190
configuration
9291
);
9392
// The CredentialChangeListener of the online component provider takes
9493
// precedence over the offline component provider.
9594
firestore._setCredentialChangeListener(user =>
96-
// TODO(firestoreexp): This should be enqueueRetryable.
97-
firestore._queue.enqueueAndForget(() =>
95+
firestore._queue.enqueueRetryable(() =>
9896
remoteStoreHandleCredentialChange(
9997
onlineComponentProvider.remoteStore,
10098
user
@@ -105,8 +103,9 @@ export async function setOnlineComponentProvider(
105103
onlineComponentProviders.set(firestore, onlineComponentProvider);
106104
}
107105

108-
async function getOfflineComponentProvider(
109-
firestore: FirebaseFirestore
106+
// TODO(firestore-compat): Remove `export` once compat migration is complete.
107+
export async function getOfflineComponentProvider(
108+
firestore: FirestoreCompat
110109
): Promise<OfflineComponentProvider> {
111110
firestore._queue.verifyOperationInProgress();
112111

@@ -121,8 +120,9 @@ async function getOfflineComponentProvider(
121120
return offlineComponentProviders.get(firestore)!;
122121
}
123122

124-
async function getOnlineComponentProvider(
125-
firestore: FirebaseFirestore
123+
// TODO(firestore-compat): Remove `export` once compat migration is complete.
124+
export async function getOnlineComponentProvider(
125+
firestore: FirestoreCompat
126126
): Promise<OnlineComponentProvider> {
127127
firestore._queue.verifyOperationInProgress();
128128

@@ -183,7 +183,7 @@ export async function getLocalStore(
183183
* when the Firestore instance is terminated.
184184
*/
185185
export async function removeComponents(
186-
firestore: FirebaseFirestore
186+
firestore: FirestoreCompat
187187
): Promise<void> {
188188
const onlineComponentProviderPromise = onlineComponentProviders.get(
189189
firestore

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

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import {
5353
setOnlineComponentProvider
5454
} from './components';
5555
import { DEFAULT_HOST, DEFAULT_SSL } from '../../../lite/src/api/components';
56-
import { DatabaseInfo } from '../../../src/core/database_info';
56+
import { DatabaseId, DatabaseInfo } from '../../../src/core/database_info';
5757
import { AutoId } from '../../../src/util/misc';
5858
import { User } from '../../../src/auth/user';
5959
import { CredentialChangeListener } from '../../../src/api/credentials';
@@ -76,14 +76,29 @@ export interface Settings extends LiteSettings {
7676
cacheSizeBytes?: number;
7777
}
7878

79+
// TODO(firestore-compat): This interface exposes internal APIs that the Compat
80+
// layer implements to interact with the firestore-exp SDL. We can remove this
81+
// class once we have an actual compat class for FirebaseFirestore.
82+
export interface FirestoreCompat {
83+
readonly _initialized: boolean;
84+
readonly _terminated: boolean;
85+
readonly _databaseId: DatabaseId;
86+
readonly _persistenceKey: string;
87+
readonly _queue: AsyncQueue;
88+
_getSettings(): Settings;
89+
_getConfiguration(): Promise<ComponentConfiguration>;
90+
_delete(): Promise<void>;
91+
_setCredentialChangeListener(listener: (user: User) => void): void;
92+
}
93+
7994
/**
8095
* The Cloud Firestore service interface.
8196
*
8297
* Do not call this constructor directly. Instead, use {@link getFirestore()}.
8398
*/
8499
export class FirebaseFirestore
85100
extends LiteFirestore
86-
implements _FirebaseService {
101+
implements _FirebaseService, FirestoreCompat {
87102
readonly _queue = new AsyncQueue();
88103
readonly _persistenceKey: string;
89104
readonly _clientId = AutoId.newId();
@@ -103,7 +118,10 @@ export class FirebaseFirestore
103118
super(app, authProvider);
104119
this._persistenceKey = app.name;
105120
this._credentials.setChangeListener(user => {
106-
this._user = user;
121+
if (!this._user.isEqual(user)) {
122+
this._user = user;
123+
this._credentialListener(user);
124+
}
107125
this._receivedInitialUser.resolve();
108126
});
109127
}
@@ -250,7 +268,7 @@ export function getFirestore(app: FirebaseApp): FirebaseFirestore {
250268
* @return A promise that represents successfully enabling persistent storage.
251269
*/
252270
export function enableIndexedDbPersistence(
253-
firestore: FirebaseFirestore,
271+
firestore: FirestoreCompat,
254272
persistenceSettings?: PersistenceSettings
255273
): Promise<void> {
256274
verifyNotInitialized(firestore);
@@ -297,7 +315,7 @@ export function enableIndexedDbPersistence(
297315
* storage.
298316
*/
299317
export function enableMultiTabIndexedDbPersistence(
300-
firestore: FirebaseFirestore
318+
firestore: FirestoreCompat
301319
): Promise<void> {
302320
verifyNotInitialized(firestore);
303321

@@ -326,7 +344,7 @@ export function enableMultiTabIndexedDbPersistence(
326344
* but the client remains usable.
327345
*/
328346
function setPersistenceProviders(
329-
firestore: FirebaseFirestore,
347+
firestore: FirestoreCompat,
330348
onlineComponentProvider: OnlineComponentProvider,
331349
offlineComponentProvider: OfflineComponentProvider
332350
): Promise<void> {
@@ -415,7 +433,7 @@ export function canFallbackFromIndexedDbError(
415433
* cleared. Otherwise, the promise is rejected with an error.
416434
*/
417435
export function clearIndexedDbPersistence(
418-
firestore: FirebaseFirestore
436+
firestore: FirestoreCompat
419437
): Promise<void> {
420438
if (firestore._initialized && !firestore._terminated) {
421439
throw new FirestoreError(
@@ -531,7 +549,7 @@ export function terminate(firestore: FirebaseFirestore): Promise<void> {
531549
return firestore._delete();
532550
}
533551

534-
function verifyNotInitialized(firestore: FirebaseFirestore): void {
552+
function verifyNotInitialized(firestore: FirestoreCompat): void {
535553
if (firestore._initialized || firestore._terminated) {
536554
throw new FirestoreError(
537555
Code.FAILED_PRECONDITION,

0 commit comments

Comments
 (0)