Skip to content

Commit bc64fd0

Browse files
Cleanup
1 parent a5e59b9 commit bc64fd0

File tree

6 files changed

+112
-80
lines changed

6 files changed

+112
-80
lines changed

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

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,20 @@ import {
2626
ComponentProvider,
2727
MemoryComponentProvider
2828
} from '../../../src/core/component_provider';
29+
import { DEFAULT_HOST, DEFAULT_SSL } from '../../../lite/src/api/components';
2930

31+
/**
32+
* An instance map that ensures only one FirestoreClient exists per Firestore
33+
* instance.
34+
*/
3035
const firestoreClientInstances = new Map<Firestore, Promise<FirestoreClient>>();
3136

32-
// settings() defaults:
33-
export const DEFAULT_HOST = 'firestore.googleapis.com';
34-
export const DEFAULT_SSL = true;
35-
37+
/**
38+
* Returns the initialized and started FirestoreClient for the given Firestore
39+
* instance. If none exists, creates a new FirestoreClient with memory
40+
* persistence. Callers must invoke removeFirestoreClient() when the Firestore
41+
* instance is terminated.
42+
*/
3643
export function getFirestoreClient(
3744
firestore: Firestore
3845
): Promise<FirestoreClient> {
@@ -42,7 +49,6 @@ export function getFirestoreClient(
4249
'The client has already been terminated.'
4350
);
4451
}
45-
4652
if (!firestoreClientInstances.has(firestore)) {
4753
// eslint-disable-next-line @typescript-eslint/no-floating-promises
4854
initializeFirestoreClient(firestore, new MemoryComponentProvider(), {
@@ -52,12 +58,21 @@ export function getFirestoreClient(
5258
return firestoreClientInstances.get(firestore)!;
5359
}
5460

61+
/**
62+
* Creates a new FirestoreClient for the given Firestore instance. Throws if the
63+
* instance exists.
64+
*
65+
* @param firestore The Firestore instance for which to create the
66+
* FirestoreClient.
67+
* @param componentProvider The component provider to use.
68+
* @param persistenceSettings Settings for the component provider.
69+
*/
5570
export function initializeFirestoreClient(
5671
firestore: Firestore,
5772
componentProvider: ComponentProvider,
5873
persistenceSettings: PersistenceSettings
5974
): Promise<void> {
60-
if (firestore._terminated || hasFirestoreClient(firestore)) {
75+
if (firestore._initialized) {
6176
throw new FirestoreError(
6277
Code.FAILED_PRECONDITION,
6378
'Firestore has already been started and persistence can no longer ' +
@@ -69,7 +84,7 @@ export function initializeFirestoreClient(
6984
const settings = firestore._getSettings();
7085
const databaseInfo = new DatabaseInfo(
7186
firestore._databaseId,
72-
/* persistenceKey= */ firestore._persistenceKey,
87+
firestore._persistenceKey,
7388
settings.host ?? DEFAULT_HOST,
7489
settings.ssl ?? DEFAULT_SSL,
7590
/** forceLongPolling= */ false
@@ -90,10 +105,10 @@ export function initializeFirestoreClient(
90105
return initializationPromise;
91106
}
92107

93-
export function hasFirestoreClient(firestore: Firestore): boolean {
94-
return firestoreClientInstances.has(firestore);
95-
}
96-
108+
/**
109+
* Removes and terminates the FirestoreClient for the given instance if it has
110+
* been started.
111+
*/
97112
export async function removeFirestoreClient(
98113
firestore: Firestore
99114
): Promise<void> {

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

Lines changed: 27 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,12 @@ import { Code, FirestoreError } from '../../../src/util/error';
3434
import { Deferred } from '../../../src/util/promise';
3535
import { LruParams } from '../../../src/local/lru_garbage_collector';
3636
import { CACHE_SIZE_UNLIMITED } from '../../../src/api/database';
37-
import { DatabaseId } from '../../../src/core/database_info';
3837
import {
3938
indexedDbClearPersistence,
4039
indexedDbStoragePrefix
4140
} from '../../../src/local/indexeddb_persistence';
4241
import {
4342
getFirestoreClient,
44-
hasFirestoreClient,
4543
initializeFirestoreClient,
4644
removeFirestoreClient
4745
} from './components';
@@ -74,36 +72,6 @@ export class Firestore extends LiteFirestore
7472
return this._settings;
7573
}
7674

77-
/**
78-
* Verifies that the client is not running and clears persistence by invoking
79-
* `delegate` on the async queue.
80-
*
81-
* @param delegate A function that clears the clients
82-
* backing storage.
83-
*/
84-
_clearPersistence(
85-
delegate: (databaseId: DatabaseId, persistenceKey: string) => Promise<void>
86-
): Promise<void> {
87-
if (hasFirestoreClient(this)) {
88-
throw new FirestoreError(
89-
Code.FAILED_PRECONDITION,
90-
'Persistence can only be cleared before a Firestore instance is ' +
91-
'initialized or after it is terminated.'
92-
);
93-
}
94-
95-
const deferred = new Deferred<void>();
96-
this._queue.enqueueAndForgetEvenAfterShutdown(async () => {
97-
try {
98-
await delegate(this._databaseId, this._persistenceKey);
99-
deferred.resolve();
100-
} catch (e) {
101-
deferred.reject(e);
102-
}
103-
});
104-
return deferred.promise;
105-
}
106-
10775
async _terminate(): Promise<void> {
10876
await super._terminate();
10977
await removeFirestoreClient(this);
@@ -148,8 +116,10 @@ export function enableIndexedDbPersistence(
148116
new IndexedDbComponentProvider(),
149117
{
150118
durable: true,
119+
synchronizeTabs: false,
151120
cacheSizeBytes:
152-
settings.cacheSizeBytes || LruParams.DEFAULT_CACHE_SIZE_BYTES
121+
settings.cacheSizeBytes || LruParams.DEFAULT_CACHE_SIZE_BYTES,
122+
forceOwningTab: false
153123
}
154124
);
155125
}
@@ -166,20 +136,39 @@ export function enableMultiTabIndexedDbPersistence(
166136
durable: true,
167137
synchronizeTabs: true,
168138
cacheSizeBytes:
169-
settings.cacheSizeBytes || LruParams.DEFAULT_CACHE_SIZE_BYTES
139+
settings.cacheSizeBytes || LruParams.DEFAULT_CACHE_SIZE_BYTES,
140+
forceOwningTab: false
170141
}
171-
).then(() => {});
142+
);
172143
}
173144

174145
export function clearIndexedDbPersistence(
175146
firestore: firestore.FirebaseFirestore
176147
): Promise<void> {
177148
const firestoreImpl = cast(firestore, Firestore);
178-
return firestoreImpl._clearPersistence((databaseId, persistenceKey) => {
179-
return indexedDbClearPersistence(
180-
indexedDbStoragePrefix(databaseId, persistenceKey)
149+
if (firestoreImpl._initialized && !firestoreImpl._terminated) {
150+
throw new FirestoreError(
151+
Code.FAILED_PRECONDITION,
152+
'Persistence can only be cleared before a Firestore instance is ' +
153+
'initialized or after it is terminated.'
181154
);
155+
}
156+
157+
const deferred = new Deferred<void>();
158+
firestoreImpl._queue.enqueueAndForgetEvenAfterShutdown(async () => {
159+
try {
160+
await indexedDbClearPersistence(
161+
indexedDbStoragePrefix(
162+
firestoreImpl._databaseId,
163+
firestoreImpl._persistenceKey
164+
)
165+
);
166+
deferred.resolve();
167+
} catch (e) {
168+
deferred.reject(e);
169+
}
182170
});
171+
return deferred.promise;
183172
}
184173

185174
export function waitForPendingWrites(

packages/firestore/lite/index.node.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import { Component, ComponentType } from '@firebase/component';
2323
export {
2424
Firestore as FirebaseFirestore,
2525
initializeFirestore,
26-
getFirestore
26+
getFirestore,
27+
terminate
2728
} from './src/api/database';
2829

2930
export {
@@ -94,4 +95,3 @@ export function registerFirestore(): void {
9495
}
9596

9697
registerFirestore();
97-
export { terminate } from './src/api/database';

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

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,25 @@ import { newSerializer } from '../../../src/platform/serializer';
2525
import { Firestore } from './database';
2626
import { DatabaseInfo } from '../../../src/core/database_info';
2727

28-
const datastoreInstances = new Map<Firestore, Promise<Datastore>>();
29-
3028
// settings() defaults:
3129
export const DEFAULT_HOST = 'firestore.googleapis.com';
3230
export const DEFAULT_SSL = true;
3331

32+
// The components module manages the lifetime of dependencies of the Firestore
33+
// client. Dependencies can be lazily constructed and only one exists per
34+
// Firestore instance.
35+
36+
/**
37+
* An instance map that ensures only one Datastore exists per Firestore
38+
* instance.
39+
*/
40+
const datastoreInstances = new Map<Firestore, Promise<Datastore>>();
41+
42+
/**
43+
* Returns an initialized and started Datastore for the given Firestore
44+
* instance. Callers must invoke removeDatastore() when the Firestore
45+
* instance is terminated.
46+
*/
3447
export function getDatastore(firestore: Firestore): Promise<Datastore> {
3548
if (!datastoreInstances.has(firestore)) {
3649
const settings = firestore._getSettings();
@@ -50,6 +63,10 @@ export function getDatastore(firestore: Firestore): Promise<Datastore> {
5063
return datastoreInstances.get(firestore)!;
5164
}
5265

66+
/**
67+
* Removes and terminates the Datastore for the given instance if it has
68+
* been started.
69+
*/
5370
export async function removeDatastore(firestore: Firestore): Promise<void> {
5471
const datastore = await datastoreInstances.get(firestore);
5572
if (datastore) {

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

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717

1818
import * as firestore from '../../';
19-
import { Settings } from '../../';
2019

2120
import { _getProvider, _removeServiceInstance } from '@firebase/app-exp';
2221
import { FirebaseApp, _FirebaseService } from '@firebase/app-types-exp';
@@ -41,44 +40,49 @@ export class Firestore
4140
readonly _databaseId: DatabaseId;
4241
readonly _credentials: CredentialsProvider;
4342
readonly _persistenceKey: string = '(lite)';
44-
private readonly _firebaseApp: FirebaseApp;
45-
46-
// docs
47-
_terminated?: Promise<void>;
4843

4944
// Assigned via _configureClient()
5045
protected _settings?: firestore.Settings;
46+
private _settingsFrozen = false;
47+
48+
// A task that is assigned when the terminate() is invoked and resolved when
49+
// all components have shut down.
50+
private _terminateTask?: Promise<void>;
5151

5252
constructor(
53-
app: FirebaseApp,
53+
readonly app: FirebaseApp,
5454
authProvider: Provider<FirebaseAuthInternalName>
5555
) {
56-
this._firebaseApp = app;
5756
this._databaseId = Firestore.databaseIdFromApp(app);
5857
this._credentials = new FirebaseCredentialsProvider(authProvider);
5958
}
6059

61-
get app(): FirebaseApp {
62-
return this._firebaseApp;
60+
get _initialized(): boolean {
61+
return this._settingsFrozen;
62+
}
63+
64+
get _terminated(): boolean {
65+
return !this._terminateTask;
6366
}
6467

6568
_configureClient(settings: firestore.Settings): void {
66-
if (this._settings) {
69+
if (this._settingsFrozen) {
6770
throw new FirestoreError(
6871
Code.FAILED_PRECONDITION,
6972
'Firestore has already been started and its settings can no longer ' +
7073
'be changed. initializeFirestore() cannot be called after calling ' +
7174
'getFirestore().'
7275
);
7376
}
77+
this._settingsFrozen = true;
7478
this._settings = settings;
7579
}
7680

77-
_getSettings(): Settings {
81+
_getSettings(): firestore.Settings {
7882
if (!this._settings) {
79-
this._settings = {};
83+
this._configureClient({});
8084
}
81-
return this._settings;
85+
return this._settings!;
8286
}
8387

8488
private static databaseIdFromApp(app: FirebaseApp): DatabaseId {
@@ -93,26 +97,25 @@ export class Firestore
9397
}
9498

9599
delete(): Promise<void> {
96-
if (!this._terminated) {
97-
this._terminated = this._terminate();
100+
if (!this._terminateTask) {
101+
this._terminateTask = this._terminate();
98102
}
99-
return this._terminated;
103+
return this._terminateTask;
100104
}
101105

106+
/**
107+
* Terminates all components used by this client. Subclasses can override
108+
* this method to clean up their own dependencies, but must also call this
109+
* method.
110+
*
111+
* Only ever called once.
112+
*/
102113
protected _terminate(): Promise<void> {
103-
debugAssert(!this._terminated, 'fff');
114+
debugAssert(!this._terminated, 'Cannot invoke _terminate() more than once');
104115
return removeDatastore(this);
105116
}
106117
}
107118

108-
export function terminate(
109-
firestore: firestore.FirebaseFirestore
110-
): Promise<void> {
111-
_removeServiceInstance(firestore.app, 'firestore/lite');
112-
const firestoreClient = cast(firestore, Firestore);
113-
return firestoreClient.delete();
114-
}
115-
116119
export function initializeFirestore(
117120
app: FirebaseApp,
118121
settings: firestore.Settings
@@ -128,3 +131,11 @@ export function initializeFirestore(
128131
export function getFirestore(app: FirebaseApp): Firestore {
129132
return _getProvider(app, 'firestore/lite').getImmediate() as Firestore;
130133
}
134+
135+
export function terminate(
136+
firestore: firestore.FirebaseFirestore
137+
): Promise<void> {
138+
_removeServiceInstance(firestore.app, 'firestore/lite');
139+
const firestoreClient = cast(firestore, Firestore);
140+
return firestoreClient.delete();
141+
}

packages/firestore/src/core/firestore_client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ export type PersistenceSettings =
6565
| {
6666
readonly durable: true;
6767
readonly cacheSizeBytes: number;
68-
readonly synchronizeTabs?: boolean;
69-
readonly forceOwningTab?: boolean;
68+
readonly synchronizeTabs: boolean;
69+
readonly forceOwningTab: boolean;
7070
};
7171

7272
/**

0 commit comments

Comments
 (0)