Skip to content

Commit f650ee0

Browse files
LocalStore-only queries
1 parent cde5600 commit f650ee0

File tree

11 files changed

+920
-603
lines changed

11 files changed

+920
-603
lines changed

packages/firestore/exp/dependencies.json

+315-417
Large diffs are not rendered by default.

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

+140-95
Original file line numberDiff line numberDiff line change
@@ -16,138 +16,183 @@
1616
*/
1717

1818
import { Firestore } from './database';
19-
import { DatabaseInfo } from '../../../src/core/database_info';
20-
import {
21-
FirestoreClient,
22-
PersistenceSettings
23-
} from '../../../src/core/firestore_client';
19+
import { PersistenceSettings } from '../../../src/core/firestore_client';
2420
import { Code, FirestoreError } from '../../../src/util/error';
2521
import {
2622
MemoryOfflineComponentProvider,
2723
OfflineComponentProvider,
2824
OnlineComponentProvider
2925
} from '../../../src/core/component_provider';
30-
import { DEFAULT_HOST, DEFAULT_SSL } from '../../../lite/src/api/components';
26+
import { LocalStore } from '../../../src/local/local_store';
27+
import { Deferred } from '../../../src/util/promise';
3128
import { logDebug } from '../../../src/util/log';
32-
29+
import { SyncEngine } from '../../../src/core/sync_engine';
30+
import { RemoteStore } from '../../../src/remote/remote_store';
31+
import { Persistence } from '../../../src/local/persistence';
32+
import { EventManager } from '../../../src/core/event_manager';
33+
import { debugAssert } from '../../../src/util/assert';
3334
export const LOG_TAG = 'ComponentProvider';
3435

3536
// The components module manages the lifetime of dependencies of the Firestore
3637
// client. Dependencies can be lazily constructed and only one exists per
3738
// Firestore instance.
3839

39-
/**
40-
* An instance map that ensures only one FirestoreClient exists per Firestore
41-
* instance.
42-
*/
43-
const firestoreClientInstances = new Map<Firestore, Promise<FirestoreClient>>();
40+
// Instance maps that ensures only one offline component provider exists per
41+
// Firestore instance.
42+
const offlineComponentProviders = new Map<
43+
Firestore,
44+
Promise<OfflineComponentProvider>
45+
>();
46+
const onlineComponentProviders = new Map<
47+
Firestore,
48+
Promise<OnlineComponentProvider>
49+
>();
4450

45-
/**
46-
* Returns the initialized and started FirestoreClient for the given Firestore
47-
* instance. If none exists, creates a new FirestoreClient with memory
48-
* persistence. Callers must invoke removeFirestoreClient() when the Firestore
49-
* instance is terminated.
50-
*/
51-
export function getFirestoreClient(
51+
export async function setOfflineComponentProvider(
52+
firestore: Firestore,
53+
persistenceSettings: PersistenceSettings,
54+
offlineComponentProvider: OfflineComponentProvider
55+
): Promise<void> {
56+
debugAssert(
57+
!onlineComponentProviders.has(firestore),
58+
'The offline component ' +
59+
'provider must be registered before the online component provider.'
60+
);
61+
const configuration = await firestore._getConfiguration();
62+
configuration.persistenceSettings = persistenceSettings;
63+
64+
const offlineDeferred = new Deferred<OfflineComponentProvider>();
65+
offlineComponentProviders.set(firestore, offlineDeferred.promise);
66+
67+
logDebug(LOG_TAG, 'Initializing OfflineComponentProvider');
68+
await offlineComponentProvider.initialize(configuration);
69+
firestore._setCredentialChangeListener(user =>
70+
// TODO(firestorexp): This should be a retryable IndexedDB operation
71+
firestore._queue.enqueueAndForget(() =>
72+
offlineComponentProvider.localStore.handleUserChange(user)
73+
)
74+
);
75+
// When a user calls clearPersistence() in one client, all other clients
76+
// need to be terminated to allow the delete to succeed.
77+
offlineComponentProvider.persistence.setDatabaseDeletedListener(() =>
78+
firestore.delete()
79+
);
80+
offlineDeferred.resolve(offlineComponentProvider);
81+
}
82+
83+
export async function setOnlineComponentProvider(
84+
firestore: Firestore,
85+
onlineComponentProvider: OnlineComponentProvider
86+
): Promise<void> {
87+
const onlineDeferred = new Deferred<OnlineComponentProvider>();
88+
onlineComponentProviders.set(firestore, onlineDeferred.promise);
89+
90+
logDebug(LOG_TAG, 'Initializing OnlineComponentProvider');
91+
const configuration = await firestore._getConfiguration();
92+
const offlineComponentProvider = await getOfflineComponentProvider(firestore);
93+
await onlineComponentProvider.initialize(
94+
offlineComponentProvider,
95+
configuration
96+
);
97+
// The CredentialChangeListener of the online component provider takes
98+
// precedence over the offline component provider.
99+
firestore._setCredentialChangeListener(user =>
100+
firestore._queue.enqueueAndForget(() =>
101+
onlineComponentProvider.remoteStore.handleCredentialChange(user)
102+
)
103+
);
104+
onlineDeferred.resolve(onlineComponentProvider);
105+
}
106+
107+
function getOfflineComponentProvider(
52108
firestore: Firestore
53-
): Promise<FirestoreClient> {
54-
if (firestore._terminated) {
55-
throw new FirestoreError(
56-
Code.FAILED_PRECONDITION,
57-
'The client has already been terminated.'
58-
);
59-
}
60-
if (!firestoreClientInstances.has(firestore)) {
109+
): Promise<OfflineComponentProvider> {
110+
verifyNotTerminated(firestore);
111+
112+
if (!offlineComponentProviders.has(firestore)) {
113+
logDebug(LOG_TAG, 'Using default OfflineComponentProvider');
61114
// eslint-disable-next-line @typescript-eslint/no-floating-promises
62-
initializeFirestoreClient(
115+
setOfflineComponentProvider(
63116
firestore,
64-
new MemoryOfflineComponentProvider(),
65-
new OnlineComponentProvider(),
66-
{
67-
durable: false
68-
}
117+
{ durable: false },
118+
new MemoryOfflineComponentProvider()
69119
);
70120
}
71-
return firestoreClientInstances.get(firestore)!;
121+
return offlineComponentProviders.get(firestore)!;
72122
}
73123

74-
/**
75-
* Creates a new FirestoreClient for the given Firestore instance. Throws if the
76-
* instance exists.
77-
*
78-
* @param firestore The Firestore instance for which to create the
79-
* FirestoreClient.
80-
* @param offlineComponentProvider Provider that returns all components required
81-
* for memory-only or IndexedDB persistence.
82-
* @param onlineComponentProvider Provider that returns all components required
83-
* for online support.
84-
* @param persistenceSettings Settings for the component provider.
85-
*/
86-
export function initializeFirestoreClient(
87-
firestore: Firestore,
88-
offlineComponentProvider: OfflineComponentProvider,
89-
onlineComponentProvider: OnlineComponentProvider,
90-
persistenceSettings: PersistenceSettings
91-
): Promise<void> {
92-
if (firestoreClientInstances.has(firestore)) {
124+
function getOnlineComponentProvider(
125+
firestore: Firestore
126+
): Promise<OnlineComponentProvider> {
127+
verifyNotTerminated(firestore);
128+
129+
if (!onlineComponentProviders.has(firestore)) {
130+
logDebug(LOG_TAG, 'Using default OnlineComponentProvider');
131+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
132+
setOnlineComponentProvider(firestore, new OnlineComponentProvider());
133+
}
134+
return onlineComponentProviders.get(firestore)!;
135+
}
136+
137+
function verifyNotTerminated(firestore: Firestore): void {
138+
if (firestore._terminated) {
93139
throw new FirestoreError(
94140
Code.FAILED_PRECONDITION,
95-
'Firestore has already been started and persistence can no longer ' +
96-
'be enabled. You can only enable persistence before calling ' +
97-
'any other methods on a Firestore object.'
141+
'The client has already been terminated.'
98142
);
99143
}
100-
logDebug(LOG_TAG, 'Initializing FirestoreClient');
101-
const settings = firestore._getSettings();
102-
const databaseInfo = new DatabaseInfo(
103-
firestore._databaseId,
104-
firestore._persistenceKey,
105-
settings.host ?? DEFAULT_HOST,
106-
settings.ssl ?? DEFAULT_SSL,
107-
/** forceLongPolling= */ false
144+
}
145+
146+
export function getSyncEngine(firestore: Firestore): Promise<SyncEngine> {
147+
return getOnlineComponentProvider(firestore).then(
148+
components => components.syncEngine
108149
);
109-
const firestoreClient = new FirestoreClient(
110-
firestore._credentials,
111-
firestore._queue
150+
}
151+
152+
export function getRemoteStore(firestore: Firestore): Promise<RemoteStore> {
153+
return getOnlineComponentProvider(firestore).then(
154+
components => components.remoteStore
112155
);
113-
const initializationPromise = firestoreClient.start(
114-
databaseInfo,
115-
offlineComponentProvider,
116-
onlineComponentProvider,
117-
persistenceSettings
156+
}
157+
158+
export function getEventManager(firestore: Firestore): Promise<EventManager> {
159+
return getOnlineComponentProvider(firestore).then(
160+
components => components.eventManager
118161
);
119-
firestoreClientInstances.set(
120-
firestore,
121-
initializationPromise.then(() => firestoreClient)
162+
}
163+
164+
export function getPersistence(firestore: Firestore): Promise<Persistence> {
165+
return getOfflineComponentProvider(firestore).then(
166+
components => components.persistence
122167
);
123-
return initializationPromise;
124168
}
125169

126-
/**
127-
* Removes and terminates the FirestoreClient for the given instance if it has
128-
* been started.
129-
*/
130-
export async function removeFirestoreClient(
131-
firestore: Firestore
132-
): Promise<void> {
133-
const firestoreClientPromise = firestoreClientInstances.get(firestore);
134-
if (firestoreClientPromise) {
135-
firestoreClientInstances.delete(firestore);
136-
return firestoreClientPromise.then(firestoreClient =>
137-
firestoreClient.terminate()
138-
);
139-
}
170+
export function getLocalStore(firestore: Firestore): Promise<LocalStore> {
171+
return getOfflineComponentProvider(firestore).then(
172+
provider => provider.localStore
173+
);
140174
}
141175

142176
/**
143177
* Removes all components associated with the provided instance. Must be called
144178
* when the Firestore instance is terminated.
145179
*/
146180
export async function removeComponents(firestore: Firestore): Promise<void> {
147-
const firestoreClientPromise = firestoreClientInstances.get(firestore);
148-
if (firestoreClientPromise) {
149-
logDebug(LOG_TAG, 'Removing FirestoreClient');
150-
firestoreClientInstances.delete(firestore);
151-
return (await firestoreClientPromise).terminate();
181+
const onlineComponentProviderPromise = onlineComponentProviders.get(
182+
firestore
183+
);
184+
if (onlineComponentProviderPromise) {
185+
logDebug(LOG_TAG, 'Removing OnlineComponentProvider');
186+
onlineComponentProviders.delete(firestore);
187+
await (await onlineComponentProviderPromise).terminate();
188+
}
189+
190+
const offlineComponentProviderPromise = offlineComponentProviders.get(
191+
firestore
192+
);
193+
if (offlineComponentProviderPromise) {
194+
logDebug(LOG_TAG, 'Removing OfflineComponentProvider');
195+
offlineComponentProviders.delete(firestore);
196+
await (await offlineComponentProviderPromise).terminate();
152197
}
153198
}

0 commit comments

Comments
 (0)