diff --git a/.changeset/heavy-spiders-fry.md b/.changeset/heavy-spiders-fry.md deleted file mode 100644 index f10664373c2..00000000000 --- a/.changeset/heavy-spiders-fry.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@firebase/firestore': minor -'@firebase/firestore-compat': patch ---- - -Add named DB support diff --git a/common/api-review/firestore-lite.api.md b/common/api-review/firestore-lite.api.md index c220ad0810f..a96f3ada5cb 100644 --- a/common/api-review/firestore-lite.api.md +++ b/common/api-review/firestore-lite.api.md @@ -176,22 +176,13 @@ export function getDoc(reference: DocumentReference): Promise(query: Query): Promise>; // @public -export function getFirestore(): Firestore; - -// @public -export function getFirestore(app: FirebaseApp): Firestore; - -// @public -export function getFirestore(databaseId: string): Firestore; - -// @public -export function getFirestore(app: FirebaseApp, databaseId: string): Firestore; +export function getFirestore(app?: FirebaseApp): Firestore; // @public export function increment(n: number): FieldValue; // @public -export function initializeFirestore(app: FirebaseApp, settings: Settings, databaseId?: string): Firestore; +export function initializeFirestore(app: FirebaseApp, settings: Settings): Firestore; // @public export function limit(limit: number): QueryConstraint; diff --git a/common/api-review/firestore.api.md b/common/api-review/firestore.api.md index 4e6e29b883b..db36b60482c 100644 --- a/common/api-review/firestore.api.md +++ b/common/api-review/firestore.api.md @@ -228,22 +228,13 @@ export function getDocsFromCache(query: Query): Promise>; export function getDocsFromServer(query: Query): Promise>; // @public -export function getFirestore(): Firestore; - -// @public -export function getFirestore(app: FirebaseApp): Firestore; - -// @public -export function getFirestore(databaseId: string): Firestore; - -// @public -export function getFirestore(app: FirebaseApp, databaseId: string): Firestore; +export function getFirestore(app?: FirebaseApp): Firestore; // @public export function increment(n: number): FieldValue; // @public -export function initializeFirestore(app: FirebaseApp, settings: FirestoreSettings, databaseId?: string): Firestore; +export function initializeFirestore(app: FirebaseApp, settings: FirestoreSettings): Firestore; // @public export function limit(limit: number): QueryConstraint; diff --git a/integration/firestore/firebase_export.ts b/integration/firestore/firebase_export.ts index 4646e11fe2c..31371b34552 100644 --- a/integration/firestore/firebase_export.ts +++ b/integration/firestore/firebase_export.ts @@ -27,25 +27,19 @@ import { let appCount = 0; -export function newTestApp(projectId: string, appName?: string): FirebaseApp { - if (appName === undefined) { - appName = 'test-app-' + appCount++; - } - return initializeApp( - { - apiKey: 'fake-api-key', - projectId - }, - appName - ); -} - export function newTestFirestore( - app: FirebaseApp, - settings?: FirestoreSettings, - dbName?: string + projectId: string, + nameOrApp?: string | FirebaseApp, + settings?: FirestoreSettings ): Firestore { - return initializeFirestore(app, settings || {}, dbName); + if (nameOrApp === undefined) { + nameOrApp = 'test-app-' + appCount++; + } + const app = + typeof nameOrApp === 'string' + ? initializeApp({ apiKey: 'fake-api-key', projectId }, nameOrApp) + : nameOrApp; + return initializeFirestore(app, settings || {}); } export * from '@firebase/firestore'; diff --git a/packages/firestore-compat/src/index.console.ts b/packages/firestore-compat/src/index.console.ts index 9adfdefdfd2..7c9a7fc63a2 100644 --- a/packages/firestore-compat/src/index.console.ts +++ b/packages/firestore-compat/src/index.console.ts @@ -91,9 +91,9 @@ export class Firestore extends FirestoreCompat { super( databaseIdFromFirestoreDatabase(firestoreDatabase), new FirestoreExp( + databaseIdFromFirestoreDatabase(firestoreDatabase), new _EmptyAuthCredentialsProvider(), - new _EmptyAppCheckTokenProvider(), - databaseIdFromFirestoreDatabase(firestoreDatabase) + new _EmptyAppCheckTokenProvider() ), new MemoryPersistenceProvider() ); diff --git a/packages/firestore/lite/register.ts b/packages/firestore/lite/register.ts index 9bd7b014fa2..8409aad6aaf 100644 --- a/packages/firestore/lite/register.ts +++ b/packages/firestore/lite/register.ts @@ -27,9 +27,9 @@ import { LiteAppCheckTokenProvider, LiteAuthCredentialsProvider } from '../src/api/credentials'; -import { databaseIdFromApp } from '../src/core/database_info'; import { setSDKVersion } from '../src/core/version'; import { Firestore } from '../src/lite-api/database'; +import { FirestoreSettings } from '../src/lite-api/settings'; declare module '@firebase/component' { interface NameServiceMapping { @@ -42,17 +42,16 @@ export function registerFirestore(): void { _registerComponent( new Component( 'firestore/lite', - (container, { instanceIdentifier: databaseId, options: settings }) => { + (container, { options: settings }: { options?: FirestoreSettings }) => { const app = container.getProvider('app').getImmediate()!; const firestoreInstance = new Firestore( + app, new LiteAuthCredentialsProvider( container.getProvider('auth-internal') ), new LiteAppCheckTokenProvider( container.getProvider('app-check-internal') - ), - databaseIdFromApp(app, databaseId), - app + ) ); if (settings) { firestoreInstance._setSettings(settings); @@ -60,7 +59,7 @@ export function registerFirestore(): void { return firestoreInstance; }, 'PUBLIC' as ComponentType.PUBLIC - ).setMultipleInstances(true) + ) ); // RUNTIME_ENV and BUILD_TARGET are replaced by real values during the compilation registerVersion('firestore-lite', version, '__RUNTIME_ENV__'); diff --git a/packages/firestore/src/api/database.ts b/packages/firestore/src/api/database.ts index 5194cfcd462..7a71071b54b 100644 --- a/packages/firestore/src/api/database.ts +++ b/packages/firestore/src/api/database.ts @@ -31,7 +31,7 @@ import { OfflineComponentProvider, OnlineComponentProvider } from '../core/component_provider'; -import { DatabaseId, DEFAULT_DATABASE_NAME } from '../core/database_info'; +import { DatabaseId } from '../core/database_info'; import { FirestoreClient, firestoreClientDisableNetwork, @@ -103,18 +103,17 @@ export class Firestore extends LiteFirestore { /** @hideconstructor */ constructor( + databaseIdOrApp: DatabaseId | FirebaseApp, authCredentialsProvider: CredentialsProvider, - appCheckCredentialsProvider: CredentialsProvider, - databaseId: DatabaseId, - app?: FirebaseApp + appCheckCredentialsProvider: CredentialsProvider ) { super( + databaseIdOrApp, authCredentialsProvider, - appCheckCredentialsProvider, - databaseId, - app + appCheckCredentialsProvider ); - this._persistenceKey = app?.name || '[DEFAULT]'; + this._persistenceKey = + 'name' in databaseIdOrApp ? databaseIdOrApp.name : '[DEFAULT]'; } _terminate(): Promise { @@ -136,26 +135,17 @@ export class Firestore extends LiteFirestore { * @param app - The {@link @firebase/app#FirebaseApp} with which the {@link Firestore} instance will * be associated. * @param settings - A settings object to configure the {@link Firestore} instance. - * @param databaseId - The name of database. * @returns A newly initialized {@link Firestore} instance. */ export function initializeFirestore( app: FirebaseApp, - settings: FirestoreSettings, - databaseId?: string + settings: FirestoreSettings ): Firestore { - if (!databaseId) { - databaseId = DEFAULT_DATABASE_NAME; - } const provider = _getProvider(app, 'firestore'); - if (provider.isInitialized(databaseId)) { - const existingInstance = provider.getImmediate({ - identifier: databaseId - }); - const initialSettings = provider.getOptions( - databaseId - ) as FirestoreSettings; + if (provider.isInitialized()) { + const existingInstance = provider.getImmediate(); + const initialSettings = provider.getOptions() as FirestoreSettings; if (deepEqual(initialSettings, settings)) { return existingInstance; } else { @@ -180,39 +170,9 @@ export function initializeFirestore( ); } - return provider.initialize({ - options: settings, - instanceIdentifier: databaseId - }); + return provider.initialize({ options: settings }); } -/** - * Returns the existing default {@link Firestore} instance that is associated with the - * default {@link @firebase/app#FirebaseApp}. If no instance exists, initializes a new - * instance with default settings. - * - * @returns The {@link Firestore} instance of the provided app. - */ -export function getFirestore(): Firestore; -/** - * Returns the existing default {@link Firestore} instance that is associated with the - * provided {@link @firebase/app#FirebaseApp}. If no instance exists, initializes a new - * instance with default settings. - * - * @param app - The {@link @firebase/app#FirebaseApp} instance that the returned {@link Firestore} - * instance is associated with. - * @returns The {@link Firestore} instance of the provided app. - */ -export function getFirestore(app: FirebaseApp): Firestore; -/** - * Returns the existing {@link Firestore} instance that is associated with the - * default {@link @firebase/app#FirebaseApp}. If no instance exists, initializes a new - * instance with default settings. - * - * @param databaseId - The name of database. - * @returns The {@link Firestore} instance of the provided app. - */ -export function getFirestore(databaseId: string): Firestore; /** * Returns the existing {@link Firestore} instance that is associated with the * provided {@link @firebase/app#FirebaseApp}. If no instance exists, initializes a new @@ -220,23 +180,10 @@ export function getFirestore(databaseId: string): Firestore; * * @param app - The {@link @firebase/app#FirebaseApp} instance that the returned {@link Firestore} * instance is associated with. - * @param databaseId - The name of database. * @returns The {@link Firestore} instance of the provided app. */ -export function getFirestore(app: FirebaseApp, databaseId: string): Firestore; -export function getFirestore( - appOrDatabaseId?: FirebaseApp | string, - optionalDatabaseId?: string -): Firestore { - const app: FirebaseApp = - typeof appOrDatabaseId === 'object' ? appOrDatabaseId : getApp(); - const databaseId = - typeof appOrDatabaseId === 'string' - ? appOrDatabaseId - : optionalDatabaseId || DEFAULT_DATABASE_NAME; - return _getProvider(app, 'firestore').getImmediate({ - identifier: databaseId - }) as Firestore; +export function getFirestore(app: FirebaseApp = getApp()): Firestore { + return _getProvider(app, 'firestore').getImmediate() as Firestore; } /** @@ -551,11 +498,7 @@ export function disableNetwork(firestore: Firestore): Promise { * terminated. */ export function terminate(firestore: Firestore): Promise { - _removeServiceInstance( - firestore.app, - 'firestore', - firestore._databaseId.database - ); + _removeServiceInstance(firestore.app, 'firestore'); return firestore._delete(); } diff --git a/packages/firestore/src/core/database_info.ts b/packages/firestore/src/core/database_info.ts index 306a9920ea9..c03afb84ac6 100644 --- a/packages/firestore/src/core/database_info.ts +++ b/packages/firestore/src/core/database_info.ts @@ -1,7 +1,3 @@ -import { FirebaseApp } from '@firebase/app'; - -import { Code, FirestoreError } from '../util/error'; - /** * @license * Copyright 2017 Google LLC @@ -50,7 +46,7 @@ export class DatabaseInfo { } /** The default database name for a project. */ -export const DEFAULT_DATABASE_NAME = '(default)'; +const DEFAULT_DATABASE_NAME = '(default)'; /** * Represents the database ID a Firestore client is associated with. @@ -78,17 +74,3 @@ export class DatabaseId { ); } } - -export function databaseIdFromApp( - app: FirebaseApp, - database?: string -): DatabaseId { - if (!Object.prototype.hasOwnProperty.apply(app.options, ['projectId'])) { - throw new FirestoreError( - Code.INVALID_ARGUMENT, - '"projectId" not provided in firebase.initializeApp.' - ); - } - - return new DatabaseId(app.options.projectId!, database); -} diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index 8cfd6577943..07db0a3c868 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -31,7 +31,7 @@ import { OAuthToken } from '../api/credentials'; import { User } from '../auth/user'; -import { DatabaseId, DEFAULT_DATABASE_NAME } from '../core/database_info'; +import { DatabaseId } from '../core/database_info'; import { Code, FirestoreError } from '../util/error'; import { cast } from '../util/input_validation'; import { logWarn } from '../util/log'; @@ -61,6 +61,7 @@ export class Firestore implements FirestoreService { */ type: 'firestore-lite' | 'firestore' = 'firestore-lite'; + readonly _databaseId: DatabaseId; readonly _persistenceKey: string = '(lite)'; private _settings = new FirestoreSettingsImpl({}); @@ -70,13 +71,21 @@ export class Firestore implements FirestoreService { // all components have shut down. private _terminateTask?: Promise; + _app?: FirebaseApp; + /** @hideconstructor */ constructor( + databaseIdOrApp: DatabaseId | FirebaseApp, public _authCredentials: CredentialsProvider, - public _appCheckCredentials: CredentialsProvider, - readonly _databaseId: DatabaseId, - readonly _app?: FirebaseApp - ) {} + public _appCheckCredentials: CredentialsProvider + ) { + if (databaseIdOrApp instanceof DatabaseId) { + this._databaseId = databaseIdOrApp; + } else { + this._app = databaseIdOrApp as FirebaseApp; + this._databaseId = databaseIdFromApp(databaseIdOrApp as FirebaseApp); + } + } /** * The {@link @firebase/app#FirebaseApp} associated with this `Firestore` service @@ -154,6 +163,17 @@ export class Firestore implements FirestoreService { } } +function databaseIdFromApp(app: FirebaseApp): DatabaseId { + if (!Object.prototype.hasOwnProperty.apply(app.options, ['projectId'])) { + throw new FirestoreError( + Code.INVALID_ARGUMENT, + '"projectId" not provided in firebase.initializeApp.' + ); + } + + return new DatabaseId(app.options.projectId!); +} + /** * Initializes a new instance of Cloud Firestore with the provided settings. * Can only be called before any other functions, including @@ -163,83 +183,35 @@ export class Firestore implements FirestoreService { * @param app - The {@link @firebase/app#FirebaseApp} with which the `Firestore` instance will * be associated. * @param settings - A settings object to configure the `Firestore` instance. - * @param databaseId - The name of database. * @returns A newly initialized `Firestore` instance. */ export function initializeFirestore( app: FirebaseApp, - settings: FirestoreSettings, - databaseId?: string + settings: FirestoreSettings ): Firestore { - if (!databaseId) { - databaseId = DEFAULT_DATABASE_NAME; - } const provider = _getProvider(app, 'firestore/lite'); - if (provider.isInitialized(databaseId)) { + if (provider.isInitialized()) { throw new FirestoreError( Code.FAILED_PRECONDITION, 'Firestore can only be initialized once per app.' ); } - return provider.initialize({ - options: settings, - instanceIdentifier: databaseId - }); + return provider.initialize({ options: settings }); } /** - * Returns the existing default {@link Firestore} instance that is associated with the - * default {@link @firebase/app#FirebaseApp}. If no instance exists, initializes a new - * instance with default settings. - * - * @returns The {@link Firestore} instance of the provided app. - */ -export function getFirestore(): Firestore; -/** - * Returns the existing default {@link Firestore} instance that is associated with the + * Returns the existing `Firestore` instance that is associated with the * provided {@link @firebase/app#FirebaseApp}. If no instance exists, initializes a new * instance with default settings. * - * @param app - The {@link @firebase/app#FirebaseApp} instance that the returned {@link Firestore} + * @param app - The {@link @firebase/app#FirebaseApp} instance that the returned `Firestore` * instance is associated with. - * @returns The {@link Firestore} instance of the provided app. + * @returns The `Firestore` instance of the provided app. */ -export function getFirestore(app: FirebaseApp): Firestore; -/** - * Returns the existing {@link Firestore} instance that is associated with the - * default {@link @firebase/app#FirebaseApp}. If no instance exists, initializes a new - * instance with default settings. - * - * @param databaseId - The name of database. - * @returns The {@link Firestore} instance of the provided app. - */ -export function getFirestore(databaseId: string): Firestore; -/** - * Returns the existing {@link Firestore} instance that is associated with the - * provided {@link @firebase/app#FirebaseApp}. If no instance exists, initializes a new - * instance with default settings. - * - * @param app - The {@link @firebase/app#FirebaseApp} instance that the returned {@link Firestore} - * instance is associated with. - * @param databaseId - The name of database. - * @returns The {@link Firestore} instance of the provided app. - */ -export function getFirestore(app: FirebaseApp, databaseId: string): Firestore; -export function getFirestore( - appOrDatabaseId?: FirebaseApp | string, - optionalDatabaseId?: string -): Firestore { - const app: FirebaseApp = - typeof appOrDatabaseId === 'object' ? appOrDatabaseId : getApp(); - const databaseId = - typeof appOrDatabaseId === 'string' - ? appOrDatabaseId - : optionalDatabaseId || '(default)'; - return _getProvider(app, 'firestore/lite').getImmediate({ - identifier: databaseId - }) as Firestore; +export function getFirestore(app: FirebaseApp = getApp()): Firestore { + return _getProvider(app, 'firestore/lite').getImmediate() as Firestore; } export { EmulatorMockTokenOptions } from '@firebase/util'; diff --git a/packages/firestore/src/register.ts b/packages/firestore/src/register.ts index 3abb38c9d86..cf4cb83632a 100644 --- a/packages/firestore/src/register.ts +++ b/packages/firestore/src/register.ts @@ -30,7 +30,7 @@ import { import { setSDKVersion } from '../src/core/version'; import { Firestore } from './api/database'; -import { databaseIdFromApp } from './core/database_info'; +import { PrivateSettings } from './lite-api/settings'; export function registerFirestore( variant?: string, @@ -40,24 +40,23 @@ export function registerFirestore( _registerComponent( new Component( 'firestore', - (container, { instanceIdentifier: databaseId, options: settings }) => { + (container, { options: settings }: { options?: PrivateSettings }) => { const app = container.getProvider('app').getImmediate()!; const firestoreInstance = new Firestore( + app, new FirebaseAuthCredentialsProvider( container.getProvider('auth-internal') ), new FirebaseAppCheckTokenProvider( container.getProvider('app-check-internal') - ), - databaseIdFromApp(app, databaseId), - app + ) ); settings = { useFetchStreams, ...settings }; firestoreInstance._setSettings(settings); return firestoreInstance; }, 'PUBLIC' as ComponentType.PUBLIC - ).setMultipleInstances(true) + ) ); registerVersion(name, version, variant); // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation diff --git a/packages/firestore/test/integration/api/database.test.ts b/packages/firestore/test/integration/api/database.test.ts index 5f3e2dc6c61..5609d86a8b4 100644 --- a/packages/firestore/test/integration/api/database.test.ts +++ b/packages/firestore/test/integration/api/database.test.ts @@ -62,8 +62,7 @@ import { Timestamp, FieldPath, newTestFirestore, - SnapshotOptions, - newTestApp + SnapshotOptions } from '../util/firebase_export'; import { apiDescribe, @@ -72,8 +71,7 @@ import { withTestDb, withTestDbs, withTestDoc, - withTestDocAndInitialData, - withNamedTestDbsOrSkipUnlessUsingEmulator + withTestDocAndInitialData } from '../util/helpers'; import { DEFAULT_SETTINGS, DEFAULT_PROJECT_ID } from '../util/settings'; @@ -1108,7 +1106,8 @@ apiDescribe('Database', (persistence: boolean) => { await deleteApp(app); const firestore2 = newTestFirestore( - newTestApp(options.projectId!, name), + options.projectId!, + name, DEFAULT_SETTINGS ); await enableIndexedDbPersistence(firestore2); @@ -1150,9 +1149,7 @@ apiDescribe('Database', (persistence: boolean) => { await deleteApp(app); - const firestore2 = newTestFirestore( - newTestApp(options.projectId!, name) - ); + const firestore2 = newTestFirestore(options.projectId!, name); await enableIndexedDbPersistence(firestore2); const docRef2 = doc(firestore2, docRef.path); const docSnap2 = await getDocFromCache(docRef2); @@ -1173,9 +1170,7 @@ apiDescribe('Database', (persistence: boolean) => { await deleteApp(app); await clearIndexedDbPersistence(firestore); - const firestore2 = newTestFirestore( - newTestApp(options.projectId!, name) - ); + const firestore2 = newTestFirestore(options.projectId!, name); await enableIndexedDbPersistence(firestore2); const docRef2 = doc(firestore2, docRef.path); await expect(getDocFromCache(docRef2)).to.eventually.be.rejectedWith( @@ -1196,9 +1191,7 @@ apiDescribe('Database', (persistence: boolean) => { const options = app.options; await deleteApp(app); - const firestore2 = newTestFirestore( - newTestApp(options.projectId!, name) - ); + const firestore2 = newTestFirestore(options.projectId!, name); await clearIndexedDbPersistence(firestore2); await enableIndexedDbPersistence(firestore2); const docRef2 = doc(firestore2, docRef.path); @@ -1708,47 +1701,4 @@ apiDescribe('Database', (persistence: boolean) => { } ); }); - - it('can keep docs separate with multi-db when online', () => { - return withNamedTestDbsOrSkipUnlessUsingEmulator( - persistence, - ['db1', 'db2'], - async ([db1, db2]) => { - const data = { name: 'Rafi', email: 'abc@xyz.com' }; - - const ref1 = await doc(collection(db1, 'users'), 'doc1'); - await setDoc(ref1, data); - const snapshot1 = await getDoc(ref1); - expect(snapshot1.exists()).to.be.ok; - expect(snapshot1.data()).to.be.deep.equals(data); - - const ref2 = await doc(collection(db2, 'users'), 'doc1'); - const snapshot2 = await getDocFromServer(ref2); - expect(snapshot2.exists()).to.not.be.ok; - } - ); - }); - - it('can keep docs separate with multi-db when offline', () => { - return withNamedTestDbsOrSkipUnlessUsingEmulator( - persistence, - ['db1', 'db2'], - async ([db1, db2]) => { - await disableNetwork(db1); - await disableNetwork(db2); - const data = { name: 'Rafi', email: 'abc@xyz.com' }; - - const ref1 = await doc(collection(db1, 'users')); - void setDoc(ref1, data); - const snapshot = await getDocFromCache(ref1); - expect(snapshot.exists()).to.be.ok; - expect(snapshot.data()).to.be.deep.equals(data); - - const ref2 = await doc(collection(db2, 'users')); - await expect(getDocFromCache(ref2)).to.eventually.rejectedWith( - 'Failed to get document from cache.' - ); - } - ); - }); }); diff --git a/packages/firestore/test/integration/api/provider.test.ts b/packages/firestore/test/integration/api/provider.test.ts deleted file mode 100644 index ffcd0e7f350..00000000000 --- a/packages/firestore/test/integration/api/provider.test.ts +++ /dev/null @@ -1,161 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { initializeApp } from '@firebase/app'; -import { expect, use } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; - -import { - doc, - getFirestore, - initializeFirestore, - Firestore, - terminate, - getDoc -} from '../util/firebase_export'; -import { DEFAULT_SETTINGS } from '../util/settings'; - -use(chaiAsPromised); - -describe('Firestore Provider', () => { - it('can provide setting', () => { - const app = initializeApp( - { apiKey: 'fake-api-key', projectId: 'test-project' }, - 'test-app-initializeFirestore' - ); - const fs1 = initializeFirestore(app, { host: 'localhost', ssl: false }); - expect(fs1).to.be.an.instanceOf(Firestore); - }); - - it('returns same default instance from named app', () => { - const app = initializeApp( - { apiKey: 'fake-api-key', projectId: 'test-project' }, - 'test-app-getFirestore' - ); - const fs1 = getFirestore(app); - const fs2 = getFirestore(app); - const fs3 = getFirestore(app, '(default)'); - expect(fs1).to.be.equal(fs2).and.equal(fs3); - }); - - it('returns different instance from named app', () => { - const app = initializeApp( - { apiKey: 'fake-api-key', projectId: 'test-project' }, - 'test-app-getFirestore' - ); - const fs1 = initializeFirestore(app, DEFAULT_SETTINGS, 'init1'); - const fs2 = initializeFirestore(app, DEFAULT_SETTINGS, 'init2'); - const fs3 = getFirestore(app); - const fs4 = getFirestore(app, 'name1'); - const fs5 = getFirestore(app, 'name2'); - expect(fs1).to.not.be.equal(fs2); - expect(fs1).to.not.be.equal(fs3); - expect(fs1).to.not.be.equal(fs4); - expect(fs1).to.not.be.equal(fs5); - expect(fs2).to.not.be.equal(fs3); - expect(fs2).to.not.be.equal(fs4); - expect(fs2).to.not.be.equal(fs5); - expect(fs3).to.not.be.equal(fs4); - expect(fs3).to.not.be.equal(fs5); - expect(fs4).to.not.be.equal(fs5); - }); - - it('returns same default instance from default app', () => { - const app = initializeApp({ - apiKey: 'fake-api-key', - projectId: 'test-project' - }); - const fs1 = initializeFirestore(app, DEFAULT_SETTINGS); - const fs2 = initializeFirestore(app, DEFAULT_SETTINGS); - const fs3 = getFirestore(); - const fs4 = getFirestore(app); - const fs5 = getFirestore('(default)'); - const fs6 = getFirestore(app, '(default)'); - expect(fs1).to.be.equal(fs2); - expect(fs1).to.be.equal(fs3); - expect(fs1).to.be.equal(fs4); - expect(fs1).to.be.equal(fs5); - expect(fs1).to.be.equal(fs6); - }); - - it('returns different instance from different named app', () => { - initializeApp({ apiKey: 'fake-api-key', projectId: 'test-project' }); - const app1 = initializeApp( - { apiKey: 'fake-api-key', projectId: 'test-project' }, - 'test-app-getFirestore-1' - ); - const app2 = initializeApp( - { apiKey: 'fake-api-key', projectId: 'test-project' }, - 'test-app-getFirestore-2' - ); - const fs1 = getFirestore(); - const fs2 = getFirestore(app1); - const fs3 = getFirestore(app2); - expect(fs1).to.not.be.equal(fs2); - expect(fs1).to.not.be.equal(fs3); - expect(fs2).to.not.be.equal(fs3); - }); - - it('can call initializeFirestore() twice if settings are same', () => { - const app = initializeApp( - { apiKey: 'fake-api-key', projectId: 'test-project' }, - 'test-app-initializeFirestore-twice' - ); - const fs1 = initializeFirestore(app, DEFAULT_SETTINGS); - const fs2 = initializeFirestore(app, DEFAULT_SETTINGS); - expect(fs1).to.be.equal(fs2); - }); - - it('cannot use once terminated', () => { - const app = initializeApp( - { apiKey: 'fake-api-key', projectId: 'test-project' }, - 'test-app-terminated' - ); - const firestore = initializeFirestore(app, { - host: 'localhost', - ssl: false - }); - - // We don't await the Promise. Any operation enqueued after should be - // rejected. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - terminate(firestore); - - try { - // eslint-disable-next-line @typescript-eslint/no-floating-promises - getDoc(doc(firestore, 'coll/doc')); - expect.fail(); - } catch (e) { - expect((e as Error)?.message).to.equal( - 'The client has already been terminated.' - ); - } - }); - - it('can call terminate() multiple times', () => { - const app = initializeApp( - { apiKey: 'fake-api-key', projectId: 'test-project' }, - 'test-app-multi-terminate' - ); - const firestore = initializeFirestore(app, { - host: 'localhost', - ssl: false - }); - - return terminate(firestore).then(() => terminate(firestore)); - }); -}); diff --git a/packages/firestore/test/integration/api/validation.test.ts b/packages/firestore/test/integration/api/validation.test.ts index 2943a8b0c06..a61b5595ec0 100644 --- a/packages/firestore/test/integration/api/validation.test.ts +++ b/packages/firestore/test/integration/api/validation.test.ts @@ -49,8 +49,7 @@ import { serverTimestamp, setDoc, updateDoc, - where, - newTestApp + where } from '../util/firebase_export'; import { apiDescribe, @@ -157,19 +156,19 @@ apiDescribe('Validation:', (persistence: boolean) => { validationIt(persistence, 'enforces minimum cache size', () => { expect(() => - newTestFirestore(newTestApp('test-project'), { cacheSizeBytes: 1 }) + newTestFirestore('test-project', undefined, { cacheSizeBytes: 1 }) ).to.throw('cacheSizeBytes must be at least 1048576'); }); validationIt(persistence, 'garbage collection can be disabled', () => { // Verify that this doesn't throw. - newTestFirestore(newTestApp('test-project'), { + newTestFirestore('test-project', undefined, { cacheSizeBytes: /* CACHE_SIZE_UNLIMITED= */ -1 }); }); validationIt(persistence, 'useEmulator can set host and port', () => { - const db = newTestFirestore(newTestApp('test-project')); + const db = newTestFirestore('test-project'); // Verify that this doesn't throw. connectFirestoreEmulator(db, 'localhost', 9000); }); @@ -192,7 +191,7 @@ apiDescribe('Validation:', (persistence: boolean) => { persistence, 'useEmulator can set mockUserToken object', () => { - const db = newTestFirestore(newTestApp('test-project')); + const db = newTestFirestore('test-project'); // Verify that this doesn't throw. connectFirestoreEmulator(db, 'localhost', 9000, { mockUserToken: { sub: 'foo' } @@ -204,7 +203,7 @@ apiDescribe('Validation:', (persistence: boolean) => { persistence, 'useEmulator can set mockUserToken string', () => { - const db = newTestFirestore(newTestApp('test-project')); + const db = newTestFirestore('test-project'); // Verify that this doesn't throw. connectFirestoreEmulator(db, 'localhost', 9000, { mockUserToken: 'my-mock-user-token' diff --git a/packages/firestore/test/integration/util/firebase_export.ts b/packages/firestore/test/integration/util/firebase_export.ts index f58b3ce045b..ab52cb2e1db 100644 --- a/packages/firestore/test/integration/util/firebase_export.ts +++ b/packages/firestore/test/integration/util/firebase_export.ts @@ -29,25 +29,27 @@ import { PrivateSettings } from '../../../src/lite-api/settings'; // every test and never clean them up. We may need to revisit. let appCount = 0; -export function newTestApp(projectId: string, appName?: string): FirebaseApp { - if (appName === undefined) { - appName = 'test-app-' + appCount++; - } - return initializeApp( - { - apiKey: 'fake-api-key', - projectId - }, - appName - ); -} - export function newTestFirestore( - app: FirebaseApp, - settings?: PrivateSettings, - dbName?: string + projectId: string, + nameOrApp?: string | FirebaseApp, + settings?: PrivateSettings ): Firestore { - return initializeFirestore(app, settings || {}, dbName); + if (nameOrApp === undefined) { + nameOrApp = 'test-app-' + appCount++; + } + + const app = + typeof nameOrApp === 'string' + ? initializeApp( + { + apiKey: 'fake-api-key', + projectId + }, + nameOrApp + ) + : nameOrApp; + + return initializeFirestore(app, settings || {}); } export * from '../../../src'; diff --git a/packages/firestore/test/integration/util/helpers.ts b/packages/firestore/test/integration/util/helpers.ts index f2584916daf..0a8dd3a5108 100644 --- a/packages/firestore/test/integration/util/helpers.ts +++ b/packages/firestore/test/integration/util/helpers.ts @@ -31,14 +31,12 @@ import { setDoc, PrivateSettings, SnapshotListenOptions, - newTestFirestore, - newTestApp + newTestFirestore } from './firebase_export'; import { ALT_PROJECT_ID, DEFAULT_PROJECT_ID, - DEFAULT_SETTINGS, - USE_EMULATOR + DEFAULT_SETTINGS } from './settings'; /* eslint-disable no-restricted-globals */ @@ -184,41 +182,7 @@ export async function withTestDbsSettings( const dbs: Firestore[] = []; for (let i = 0; i < numDbs; i++) { - const db = newTestFirestore(newTestApp(projectId), settings); - if (persistence) { - await enableIndexedDbPersistence(db); - } - dbs.push(db); - } - - try { - await fn(dbs); - } finally { - for (const db of dbs) { - await terminate(db); - if (persistence) { - await clearIndexedDbPersistence(db); - } - } - } -} - -export async function withNamedTestDbsOrSkipUnlessUsingEmulator( - persistence: boolean, - dbNames: string[], - fn: (db: Firestore[]) => Promise -): Promise { - // Tests with named DBs can only run on emulator for now. This is because the - // emulator does not require DB to be created before use. - // TODO: Design ability to run named DB tests on backend. Maybe create DBs - // TODO: beforehand, or create DBs as part of test setup. - if (!USE_EMULATOR) { - return Promise.resolve(); - } - const app = newTestApp(DEFAULT_PROJECT_ID); - const dbs: Firestore[] = []; - for (const dbName of dbNames) { - const db = newTestFirestore(app, DEFAULT_SETTINGS, dbName); + const db = newTestFirestore(projectId, /* name =*/ undefined, settings); if (persistence) { await enableIndexedDbPersistence(db); } diff --git a/packages/firestore/test/lite/integration.test.ts b/packages/firestore/test/lite/integration.test.ts index 262a0489b05..deaa9a0236f 100644 --- a/packages/firestore/test/lite/integration.test.ts +++ b/packages/firestore/test/lite/integration.test.ts @@ -106,71 +106,14 @@ describe('Firestore', () => { expect(fs1).to.be.an.instanceOf(Firestore); }); - it('returns same default instance from named app', () => { + it('returns same instance', () => { const app = initializeApp( { apiKey: 'fake-api-key', projectId: 'test-project' }, 'test-app-getFirestore' ); const fs1 = getFirestore(app); const fs2 = getFirestore(app); - const fs3 = getFirestore(app, '(default)'); - expect(fs1).to.be.equal(fs2).and.equal(fs3); - }); - - it('returns different instance from named app', () => { - const app = initializeApp( - { apiKey: 'fake-api-key', projectId: 'test-project' }, - 'test-app-getFirestore' - ); - const fs1 = initializeFirestore(app, DEFAULT_SETTINGS, 'init1'); - const fs2 = initializeFirestore(app, DEFAULT_SETTINGS, 'init2'); - const fs3 = getFirestore(app); - const fs4 = getFirestore(app, 'name1'); - const fs5 = getFirestore(app, 'name2'); - expect(fs1).to.not.be.equal(fs2); - expect(fs1).to.not.be.equal(fs3); - expect(fs1).to.not.be.equal(fs4); - expect(fs1).to.not.be.equal(fs5); - expect(fs2).to.not.be.equal(fs3); - expect(fs2).to.not.be.equal(fs4); - expect(fs2).to.not.be.equal(fs5); - expect(fs3).to.not.be.equal(fs4); - expect(fs3).to.not.be.equal(fs5); - expect(fs4).to.not.be.equal(fs5); - }); - - it('returns same default instance from default app', () => { - const app = initializeApp({ - apiKey: 'fake-api-key', - projectId: 'test-project' - }); - const fs1 = initializeFirestore(app, DEFAULT_SETTINGS); - const fs2 = getFirestore(); - const fs3 = getFirestore(app); - const fs4 = getFirestore('(default)'); - const fs5 = getFirestore(app, '(default)'); - expect(fs1).to.be.equal(fs2); - expect(fs1).to.be.equal(fs3); - expect(fs1).to.be.equal(fs4); - expect(fs1).to.be.equal(fs5); - }); - - it('returns different instance from different named app', () => { - initializeApp({ apiKey: 'fake-api-key', projectId: 'test-project' }); - const app1 = initializeApp( - { apiKey: 'fake-api-key', projectId: 'test-project' }, - 'test-app-getFirestore-1' - ); - const app2 = initializeApp( - { apiKey: 'fake-api-key', projectId: 'test-project' }, - 'test-app-getFirestore-2' - ); - const fs1 = getFirestore(); - const fs2 = getFirestore(app1); - const fs3 = getFirestore(app2); - expect(fs1).to.not.be.equal(fs2); - expect(fs1).to.not.be.equal(fs3); - expect(fs2).to.not.be.equal(fs3); + expect(fs1 === fs2).to.be.true; }); it('cannot call initializeFirestore() twice', () => { diff --git a/packages/firestore/test/util/api_helpers.ts b/packages/firestore/test/util/api_helpers.ts index 2dd8a6199e0..81d01132087 100644 --- a/packages/firestore/test/util/api_helpers.ts +++ b/packages/firestore/test/util/api_helpers.ts @@ -58,9 +58,9 @@ export function firestore(): Firestore { export function newTestFirestore(projectId = 'new-project'): Firestore { return new Firestore( + new DatabaseId(projectId), new EmptyAuthCredentialsProvider(), - new EmptyAppCheckTokenProvider(), - new DatabaseId(projectId) + new EmptyAppCheckTokenProvider() ); }