Skip to content

Commit 8305a4f

Browse files
Compat Layer for Firestore
1 parent 6ef39d4 commit 8305a4f

23 files changed

+452
-645
lines changed

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

+11-11
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
} from '../../../src/core/component_provider';
3838
import {
3939
FirebaseFirestore as LiteFirestore,
40+
FirestoreDatabase,
4041
Settings as LiteSettings
4142
} from '../../../lite/src/api/database';
4243
import { Code, FirestoreError } from '../../../src/util/error';
@@ -45,8 +46,7 @@ import { LRU_MINIMUM_CACHE_SIZE_BYTES } from '../../../src/local/lru_garbage_col
4546
import {
4647
CACHE_SIZE_UNLIMITED,
4748
configureFirestore,
48-
ensureFirestoreConfigured,
49-
FirestoreCompat
49+
ensureFirestoreConfigured
5050
} from '../../../src/api/database';
5151
import {
5252
indexedDbClearPersistence,
@@ -70,18 +70,18 @@ export interface Settings extends LiteSettings {
7070
*/
7171
export class FirebaseFirestore
7272
extends LiteFirestore
73-
implements _FirebaseService, FirestoreCompat {
73+
implements _FirebaseService {
7474
readonly _queue = new AsyncQueue();
7575
readonly _persistenceKey: string;
7676

7777
_firestoreClient: FirestoreClient | undefined;
7878

7979
constructor(
80-
app: FirebaseApp,
80+
app: FirestoreDatabase | FirebaseApp,
8181
authProvider: Provider<FirebaseAuthInternalName>
8282
) {
8383
super(app, authProvider);
84-
this._persistenceKey = app.name;
84+
this._persistenceKey = 'name' in app ? app.name : '[DEFAULT]';
8585
}
8686

8787
_terminate(): Promise<void> {
@@ -165,13 +165,13 @@ export function getFirestore(app: FirebaseApp): FirebaseFirestore {
165165
* @return A promise that represents successfully enabling persistent storage.
166166
*/
167167
export function enableIndexedDbPersistence(
168-
firestore: FirestoreCompat,
168+
firestore: FirebaseFirestore,
169169
persistenceSettings?: PersistenceSettings
170170
): Promise<void> {
171171
verifyNotInitialized(firestore);
172172

173173
const client = ensureFirestoreConfigured(firestore);
174-
const settings = firestore._getSettings();
174+
const settings = firestore._freezeSettings();
175175

176176
const onlineComponentProvider = new OnlineComponentProvider();
177177
const offlineComponentProvider = new IndexedDbOfflineComponentProvider(
@@ -209,12 +209,12 @@ export function enableIndexedDbPersistence(
209209
* storage.
210210
*/
211211
export function enableMultiTabIndexedDbPersistence(
212-
firestore: FirestoreCompat
212+
firestore: FirebaseFirestore
213213
): Promise<void> {
214214
verifyNotInitialized(firestore);
215215

216216
const client = ensureFirestoreConfigured(firestore);
217-
const settings = firestore._getSettings();
217+
const settings = firestore._freezeSettings();
218218

219219
const onlineComponentProvider = new OnlineComponentProvider();
220220
const offlineComponentProvider = new MultiTabOfflineComponentProvider(
@@ -322,7 +322,7 @@ function canFallbackFromIndexedDbError(
322322
* cleared. Otherwise, the promise is rejected with an error.
323323
*/
324324
export function clearIndexedDbPersistence(
325-
firestore: FirestoreCompat
325+
firestore: FirebaseFirestore
326326
): Promise<void> {
327327
if (firestore._initialized && !firestore._terminated) {
328328
throw new FirestoreError(
@@ -420,7 +420,7 @@ export function terminate(firestore: FirebaseFirestore): Promise<void> {
420420
return firestore._delete();
421421
}
422422

423-
function verifyNotInitialized(firestore: FirestoreCompat): void {
423+
function verifyNotInitialized(firestore: FirebaseFirestore): void {
424424
if (firestore._initialized || firestore._terminated) {
425425
throw new FirestoreError(
426426
Code.FAILED_PRECONDITION,

packages/firestore/exp/test/shim.ts

+22-144
Original file line numberDiff line numberDiff line change
@@ -15,44 +15,29 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { FirebaseApp as FirebaseAppLegacy } from '@firebase/app-types';
19-
import { FirebaseApp as FirebaseAppExp } from '@firebase/app-types-exp';
20-
import { deleteApp } from '@firebase/app-exp';
2118
import * as legacy from '@firebase/firestore-types';
2219
import * as exp from '../index';
2320

2421
import {
2522
addDoc,
26-
clearIndexedDbPersistence,
2723
collection,
28-
collectionGroup,
2924
deleteDoc,
30-
disableNetwork,
3125
doc,
3226
DocumentReference as DocumentReferenceExp,
33-
enableIndexedDbPersistence,
34-
enableMultiTabIndexedDbPersistence,
35-
enableNetwork,
3627
FieldPath as FieldPathExp,
3728
getDoc,
3829
getDocFromCache,
3930
getDocFromServer,
4031
getDocs,
4132
getDocsFromCache,
4233
getDocsFromServer,
43-
initializeFirestore,
4434
onSnapshot,
45-
onSnapshotsInSync,
4635
query,
4736
queryEqual,
4837
refEqual,
49-
runTransaction,
5038
setDoc,
5139
snapshotEqual,
52-
terminate,
5340
updateDoc,
54-
waitForPendingWrites,
55-
writeBatch,
5641
endAt,
5742
endBefore,
5843
startAfter,
@@ -70,115 +55,21 @@ import {
7055
validateSetOptions
7156
} from '../../src/util/input_validation';
7257
import { Compat } from '../../src/compat/compat';
58+
import { Firestore } from '../../src/api/database';
7359

7460
export { GeoPoint, Timestamp } from '../index';
75-
export { FieldValue } from '../../src/compat/field_value';
7661

7762
/* eslint-disable @typescript-eslint/no-explicit-any */
7863

7964
// This module defines a shim layer that implements the legacy API on top
8065
// of the experimental SDK. This shim is used to run integration tests against
8166
// both SDK versions.
8267

83-
export class FirebaseApp
84-
extends Compat<FirebaseAppExp>
85-
implements FirebaseAppLegacy {
86-
name = this._delegate.name;
87-
options = this._delegate.options;
88-
automaticDataCollectionEnabled = this._delegate
89-
.automaticDataCollectionEnabled;
90-
91-
delete(): Promise<void> {
92-
return deleteApp(this._delegate);
93-
}
94-
}
95-
96-
export class FirebaseFirestore
97-
extends Compat<exp.FirebaseFirestore>
98-
implements legacy.FirebaseFirestore {
99-
app = new FirebaseApp(this._delegate.app);
100-
101-
settings(settings: legacy.Settings): void {
102-
initializeFirestore(this.app._delegate, settings);
103-
}
104-
105-
useEmulator(host: string, port: number): void {
106-
this.settings({ host: `${host}:${port}`, ssl: false, merge: true });
107-
}
108-
109-
enablePersistence(settings?: legacy.PersistenceSettings): Promise<void> {
110-
return settings?.synchronizeTabs
111-
? enableMultiTabIndexedDbPersistence(this._delegate)
112-
: enableIndexedDbPersistence(this._delegate);
113-
}
114-
115-
collection(collectionPath: string): CollectionReference<legacy.DocumentData> {
116-
return new CollectionReference(
117-
this,
118-
collection(this._delegate, collectionPath)
119-
);
120-
}
121-
122-
doc(documentPath: string): DocumentReference<legacy.DocumentData> {
123-
return new DocumentReference(this, doc(this._delegate, documentPath));
124-
}
125-
126-
collectionGroup(collectionId: string): Query<legacy.DocumentData> {
127-
return new Query(this, collectionGroup(this._delegate, collectionId));
128-
}
129-
130-
runTransaction<T>(
131-
updateFunction: (transaction: legacy.Transaction) => Promise<T>
132-
): Promise<T> {
133-
return runTransaction(this._delegate, t =>
134-
updateFunction(new Transaction(this, t))
135-
);
136-
}
137-
138-
batch(): legacy.WriteBatch {
139-
return new WriteBatch(writeBatch(this._delegate));
140-
}
141-
142-
clearPersistence(): Promise<void> {
143-
return clearIndexedDbPersistence(this._delegate);
144-
}
145-
146-
enableNetwork(): Promise<void> {
147-
return enableNetwork(this._delegate);
148-
}
149-
150-
disableNetwork(): Promise<void> {
151-
return disableNetwork(this._delegate);
152-
}
153-
154-
waitForPendingWrites(): Promise<void> {
155-
return waitForPendingWrites(this._delegate);
156-
}
157-
158-
onSnapshotsInSync(observer: {
159-
next?: (value: void) => void;
160-
error?: (error: legacy.FirestoreError) => void;
161-
complete?: () => void;
162-
}): () => void;
163-
onSnapshotsInSync(onSync: () => void): () => void;
164-
onSnapshotsInSync(arg: any): () => void {
165-
return onSnapshotsInSync(this._delegate, arg);
166-
}
167-
168-
terminate(): Promise<void> {
169-
return terminate(this._delegate);
170-
}
171-
172-
INTERNAL = {
173-
delete: () => terminate(this._delegate)
174-
};
175-
}
176-
17768
export class Transaction
17869
extends Compat<exp.Transaction>
17970
implements legacy.Transaction {
18071
constructor(
181-
private readonly _firestore: FirebaseFirestore,
72+
private readonly _firestore: Firestore,
18273
delegate: exp.Transaction
18374
) {
18475
super(delegate);
@@ -301,7 +192,7 @@ export class DocumentReference<T = legacy.DocumentData>
301192
extends Compat<exp.DocumentReference<T>>
302193
implements legacy.DocumentReference<T> {
303194
constructor(
304-
readonly firestore: FirebaseFirestore,
195+
readonly firestore: Firestore,
305196
delegate: exp.DocumentReference<T>
306197
) {
307198
super(delegate);
@@ -424,7 +315,7 @@ export class DocumentSnapshot<T = legacy.DocumentData>
424315
extends Compat<exp.DocumentSnapshot<T>>
425316
implements legacy.DocumentSnapshot<T> {
426317
constructor(
427-
private readonly _firestore: FirebaseFirestore,
318+
private readonly _firestore: Firestore,
428319
delegate: exp.DocumentSnapshot<T>
429320
) {
430321
super(delegate);
@@ -439,11 +330,14 @@ export class DocumentSnapshot<T = legacy.DocumentData>
439330
}
440331

441332
data(options?: legacy.SnapshotOptions): T | undefined {
442-
return wrap(this._delegate.data(options));
333+
return wrap(this._firestore, this._delegate.data(options));
443334
}
444335

445336
get(fieldPath: string | FieldPath, options?: legacy.SnapshotOptions): any {
446-
return wrap(this._delegate.get(unwrap(fieldPath), options));
337+
return wrap(
338+
this._firestore,
339+
this._delegate.get(unwrap(fieldPath), options)
340+
);
447341
}
448342

449343
isEqual(other: DocumentSnapshot<T>): boolean {
@@ -454,22 +348,15 @@ export class DocumentSnapshot<T = legacy.DocumentData>
454348
export class QueryDocumentSnapshot<T = legacy.DocumentData>
455349
extends DocumentSnapshot<T>
456350
implements legacy.QueryDocumentSnapshot<T> {
457-
constructor(
458-
firestore: FirebaseFirestore,
459-
readonly _delegate: exp.QueryDocumentSnapshot<T>
460-
) {
461-
super(firestore, _delegate);
462-
}
463-
464351
data(options?: legacy.SnapshotOptions): T {
465-
return this._delegate.data(options);
352+
return this._delegate.data(options)!;
466353
}
467354
}
468355

469356
export class Query<T = legacy.DocumentData>
470357
extends Compat<exp.Query<T>>
471358
implements legacy.Query<T> {
472-
constructor(readonly firestore: FirebaseFirestore, delegate: exp.Query<T>) {
359+
constructor(readonly firestore: Firestore, delegate: exp.Query<T>) {
473360
super(delegate);
474361
}
475362

@@ -592,7 +479,7 @@ export class Query<T = legacy.DocumentData>
592479
export class QuerySnapshot<T = legacy.DocumentData>
593480
implements legacy.QuerySnapshot<T> {
594481
constructor(
595-
readonly _firestore: FirebaseFirestore,
482+
readonly _firestore: Firestore,
596483
readonly _delegate: exp.QuerySnapshot<T>
597484
) {}
598485

@@ -633,7 +520,7 @@ export class QuerySnapshot<T = legacy.DocumentData>
633520
export class DocumentChange<T = legacy.DocumentData>
634521
implements legacy.DocumentChange<T> {
635522
constructor(
636-
private readonly _firestore: FirebaseFirestore,
523+
private readonly _firestore: Firestore,
637524
private readonly _delegate: exp.DocumentChange<T>
638525
) {}
639526
readonly type = this._delegate.type;
@@ -649,7 +536,7 @@ export class CollectionReference<T = legacy.DocumentData>
649536
extends Query<T>
650537
implements legacy.CollectionReference<T> {
651538
constructor(
652-
firestore: FirebaseFirestore,
539+
readonly firestore: Firestore,
653540
readonly _delegate: exp.CollectionReference<T>
654541
) {
655542
super(firestore, _delegate);
@@ -698,15 +585,11 @@ export class CollectionReference<T = legacy.DocumentData>
698585
}
699586
}
700587

701-
export class FieldPath implements legacy.FieldPath {
702-
private readonly fieldNames: string[];
703-
588+
export class FieldPath
589+
extends Compat<FieldPathExp>
590+
implements legacy.FieldPath {
704591
constructor(...fieldNames: string[]) {
705-
this.fieldNames = fieldNames;
706-
}
707-
708-
get _delegate(): FieldPathExp {
709-
return new FieldPathExp(...this.fieldNames);
592+
super(new FieldPathExp(...fieldNames));
710593
}
711594

712595
static documentId(): FieldPath {
@@ -744,25 +627,20 @@ export class Blob extends Compat<BytesExp> implements legacy.Blob {
744627
* Takes document data that uses the firestore-exp API types and replaces them
745628
* with the API types defined in this shim.
746629
*/
747-
function wrap(value: any): any {
630+
function wrap(firestore: Firestore, value: any): any {
748631
if (Array.isArray(value)) {
749-
return value.map(v => wrap(v));
632+
return value.map(v => wrap(firestore, v));
750633
} else if (value instanceof FieldPathExp) {
751634
return new FieldPath(...value._internalPath.toArray());
752635
} else if (value instanceof BytesExp) {
753636
return new Blob(value);
754637
} else if (value instanceof DocumentReferenceExp) {
755-
// TODO(mrschmidt): Ideally, we should use an existing instance of
756-
// FirebaseFirestore here rather than instantiating a new instance
757-
return new DocumentReference(
758-
new FirebaseFirestore(value.firestore as exp.FirebaseFirestore),
759-
value
760-
);
638+
return new DocumentReference(firestore, value);
761639
} else if (isPlainObject(value)) {
762640
const obj: any = {};
763641
for (const key in value) {
764642
if (value.hasOwnProperty(key)) {
765-
obj[key] = wrap(value[key]);
643+
obj[key] = wrap(firestore, value[key]);
766644
}
767645
}
768646
return obj;

0 commit comments

Comments
 (0)