Skip to content

Tomandersen/multi db #6518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Aug 22, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/heavy-spiders-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@firebase/firestore': minor
'@firebase/firestore-compat': patch
---

Add named DB support
11 changes: 10 additions & 1 deletion common/api-review/firestore-lite.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,16 @@ export function getDoc<T>(reference: DocumentReference<T>): Promise<DocumentSnap
export function getDocs<T>(query: Query<T>): Promise<QuerySnapshot<T>>;

// @public
export function getFirestore(app?: FirebaseApp): Firestore;
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;

// @public
export function increment(n: number): FieldValue;
Expand Down
11 changes: 10 additions & 1 deletion common/api-review/firestore.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,16 @@ export function getDocsFromCache<T>(query: Query<T>): Promise<QuerySnapshot<T>>;
export function getDocsFromServer<T>(query: Query<T>): Promise<QuerySnapshot<T>>;

// @public
export function getFirestore(app?: FirebaseApp): Firestore;
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;

// @public
export function increment(n: number): FieldValue;
Expand Down
4 changes: 2 additions & 2 deletions packages/firestore-compat/src/index.console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ export class Firestore extends FirestoreCompat {
super(
databaseIdFromFirestoreDatabase(firestoreDatabase),
new FirestoreExp(
databaseIdFromFirestoreDatabase(firestoreDatabase),
new _EmptyAuthCredentialsProvider(),
new _EmptyAppCheckTokenProvider()
new _EmptyAppCheckTokenProvider(),
databaseIdFromFirestoreDatabase(firestoreDatabase)
),
new MemoryPersistenceProvider()
);
Expand Down
11 changes: 6 additions & 5 deletions packages/firestore/lite/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -42,24 +42,25 @@ export function registerFirestore(): void {
_registerComponent(
new Component(
'firestore/lite',
(container, { options: settings }: { options?: FirestoreSettings }) => {
(container, { instanceIdentifier: databaseId, options: settings }) => {
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);
}
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__');
Expand Down
57 changes: 49 additions & 8 deletions packages/firestore/src/api/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,18 @@ export class Firestore extends LiteFirestore {

/** @hideconstructor */
constructor(
databaseIdOrApp: DatabaseId | FirebaseApp,
authCredentialsProvider: CredentialsProvider<User>,
appCheckCredentialsProvider: CredentialsProvider<string>
appCheckCredentialsProvider: CredentialsProvider<string>,
databaseId: DatabaseId,
app?: FirebaseApp
) {
super(
databaseIdOrApp,
authCredentialsProvider,
appCheckCredentialsProvider
appCheckCredentialsProvider,
databaseId,
app
);
this._persistenceKey =
'name' in databaseIdOrApp ? databaseIdOrApp.name : '[DEFAULT]';
this._persistenceKey = app?.name || '[DEFAULT]';
}

_terminate(): Promise<void> {
Expand Down Expand Up @@ -173,17 +174,57 @@ export function initializeFirestore(
return provider.initialize({ options: settings });
}

/**
* 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.
*
* @returns The {@link Firestore} instance of the provided app.
*/
export function getFirestore(): 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.
* @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
* 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 = getApp()): Firestore {
return _getProvider(app, 'firestore').getImmediate() as Firestore;
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').getImmediate({
identifier: databaseId
}) as Firestore;
}

/**
Expand Down
18 changes: 18 additions & 0 deletions packages/firestore/src/core/database_info.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { FirebaseApp } from '@firebase/app';

import { Code, FirestoreError } from '../util/error';

/**
* @license
* Copyright 2017 Google LLC
Expand Down Expand Up @@ -74,3 +78,17 @@ 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);
}
78 changes: 49 additions & 29 deletions packages/firestore/src/lite-api/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ export class Firestore implements FirestoreService {
*/
type: 'firestore-lite' | 'firestore' = 'firestore-lite';

readonly _databaseId: DatabaseId;
readonly _persistenceKey: string = '(lite)';

private _settings = new FirestoreSettingsImpl({});
Expand All @@ -71,21 +70,13 @@ export class Firestore implements FirestoreService {
// all components have shut down.
private _terminateTask?: Promise<void>;

_app?: FirebaseApp;

/** @hideconstructor */
constructor(
databaseIdOrApp: DatabaseId | FirebaseApp,
public _authCredentials: CredentialsProvider<User>,
public _appCheckCredentials: CredentialsProvider<string>
) {
if (databaseIdOrApp instanceof DatabaseId) {
this._databaseId = databaseIdOrApp;
} else {
this._app = databaseIdOrApp as FirebaseApp;
this._databaseId = databaseIdFromApp(databaseIdOrApp as FirebaseApp);
}
}
public _appCheckCredentials: CredentialsProvider<string>,
readonly _databaseId: DatabaseId,
readonly _app?: FirebaseApp
) {}

/**
* The {@link @firebase/app#FirebaseApp} associated with this `Firestore` service
Expand Down Expand Up @@ -163,17 +154,6 @@ 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
Expand Down Expand Up @@ -202,16 +182,56 @@ export function initializeFirestore(
}

/**
* Returns the existing `Firestore` instance that is associated with the
* 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.
*
* @returns The {@link Firestore} instance of the provided app.
*/
export function getFirestore(): 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.
* @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
* instance with default settings.
*
* @param app - The {@link @firebase/app#FirebaseApp} instance that the returned `Firestore`
* @param app - The {@link @firebase/app#FirebaseApp} instance that the returned {@link Firestore}
* instance is associated with.
* @returns The `Firestore` instance of the provided app.
* @param databaseId - The name of database.
* @returns The {@link Firestore} instance of the provided app.
*/
export function getFirestore(app: FirebaseApp = getApp()): Firestore {
return _getProvider(app, 'firestore/lite').getImmediate() as Firestore;
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 { EmulatorMockTokenOptions } from '@firebase/util';
Expand Down
9 changes: 5 additions & 4 deletions packages/firestore/src/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
import { setSDKVersion } from '../src/core/version';

import { Firestore } from './api/database';
import { PrivateSettings } from './lite-api/settings';
import { databaseIdFromApp } from './core/database_info';

export function registerFirestore(
variant?: string,
Expand All @@ -40,16 +40,17 @@ export function registerFirestore(
_registerComponent(
new Component(
'firestore',
(container, { options: settings }: { options?: PrivateSettings }) => {
(container, { instanceIdentifier: databaseId, options: settings }) => {
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);
Expand Down
Loading