Skip to content
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

feat(rtdb): Added firebase-admin/database module entrypoint #1143

Merged
merged 2 commits into from
Jan 27, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
67 changes: 54 additions & 13 deletions etc/firebase-admin.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@

import { Agent } from 'http';
import { Bucket } from '@google-cloud/storage';
import { DataSnapshot } from '@firebase/database-types';
import { EventType } from '@firebase/database-types';
import { FirebaseDatabase } from '@firebase/database-types';
import * as _firestore from '@google-cloud/firestore';
import { OnDisconnect } from '@firebase/database-types';
import { Query } from '@firebase/database-types';
import { Reference } from '@firebase/database-types';
import * as rtdb from '@firebase/database-types';
import { ThenableReference } from '@firebase/database-types';

// @public
export interface ActionCodeSettings {
Expand Down Expand Up @@ -274,27 +281,39 @@ export namespace credential {
const refreshToken: typeof refreshToken;
}

// @public (undocumented)
export interface Database extends FirebaseDatabase {
getRules(): Promise<string>;
getRulesJSON(): Promise<object>;
setRules(source: string | Buffer | object): Promise<void>;
}

// @public
export function database(app?: app.App): database.Database;
export function database(app?: App): database.Database;

// @public (undocumented)
export namespace database {
// (undocumented)
export interface Database extends rtdb.FirebaseDatabase {
getRules(): Promise<string>;
getRulesJSON(): Promise<object>;
setRules(source: string | Buffer | object): Promise<void>;
}
import DataSnapshot = rtdb.DataSnapshot;
import EventType = rtdb.EventType;
import OnDisconnect = rtdb.OnDisconnect;
import Query = rtdb.Query;
import Reference = rtdb.Reference;
import ThenableReference = rtdb.ThenableReference;
import enableLogging = rtdb.enableLogging;
export type Database = Database;
// (undocumented)
export type DataSnapshot = rtdb.DataSnapshot;
// (undocumented)
export type EventType = rtdb.EventType;
// (undocumented)
export type OnDisconnect = rtdb.OnDisconnect;
// (undocumented)
export type Query = rtdb.Query;
// (undocumented)
export type Reference = rtdb.Reference;
// (undocumented)
export type ThenableReference = rtdb.ThenableReference;
const // (undocumented)
enableLogging: typeof rtdb.enableLogging;
const ServerValue: rtdb.ServerValue;
}

export { DataSnapshot }

// @public
export interface DecodedIdToken {
// (undocumented)
Expand Down Expand Up @@ -344,6 +363,11 @@ export interface EmailSignInProviderConfig {
passwordRequired?: boolean;
}

// @public (undocumented)
export const enableLogging: typeof rtdb.enableLogging;

export { EventType }

// @public
export interface FirebaseArrayIndexError {
error: FirebaseError;
Expand Down Expand Up @@ -403,6 +427,12 @@ export function getApps(): App[];
// @public (undocumented)
export function getAuth(app?: App): Auth;

// @public (undocumented)
export function getDatabase(app?: App): Database;

// @public (undocumented)
export function getDatabaseWithUrl(url: string, app?: App): Database;

// @public (undocumented)
export function getInstanceId(app?: App): InstanceId;

Expand Down Expand Up @@ -866,6 +896,8 @@ export interface OIDCUpdateAuthProviderRequest {
issuer?: string;
}

export { OnDisconnect }

// @public
export interface PhoneIdentifier {
// (undocumented)
Expand Down Expand Up @@ -951,6 +983,10 @@ export interface ProviderIdentifier {
providerUid: string;
}

export { Query }

export { Reference }

// @public (undocumented)
export function refreshToken(refreshTokenPathOrObject: string | object, httpAgent?: Agent): Credential;

Expand Down Expand Up @@ -1100,6 +1136,9 @@ export namespace securityRules {
}
}

// @public (undocumented)
export const ServerValue: rtdb.ServerValue;

// @public (undocumented)
export interface ServiceAccount {
// (undocumented)
Expand Down Expand Up @@ -1163,6 +1202,8 @@ export class TenantManager {
updateTenant(tenantId: string, tenantOptions: UpdateTenantRequest): Promise<Tenant>;
}

export { ThenableReference }

// @public
export interface UidIdentifier {
// (undocumented)
Expand Down
1 change: 1 addition & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ gulp.task('compile', function() {
'lib/core.d.ts',
'lib/app/*.d.ts',
'lib/auth/*.d.ts',
'lib/database/*.d.ts',
'lib/instance-id/*.d.ts',
'!lib/utils/index.d.ts',
];
Expand Down
12 changes: 3 additions & 9 deletions src/app/firebase-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,14 @@ import { Auth } from '../auth/auth';
import { MachineLearning } from '../machine-learning/machine-learning';
import { Messaging } from '../messaging/messaging';
import { Storage } from '../storage/storage';
import { database } from '../database/index';
import { DatabaseService } from '../database/database-internal';
import { Database } from '../database/index';
import { Firestore } from '@google-cloud/firestore';
import { FirestoreService } from '../firestore/firestore-internal';
import { InstanceId } from '../instance-id/index';
import { ProjectManagement } from '../project-management/project-management';
import { SecurityRules } from '../security-rules/security-rules';
import { RemoteConfig } from '../remote-config/remote-config';

import Database = database.Database;

/**
* Type representing a callback which is called every time an app lifecycle event occurs.
*/
Expand Down Expand Up @@ -287,11 +284,8 @@ export class FirebaseApp implements app.App {
* @return The Database service instance of this app.
*/
public database(url?: string): Database {
const service: DatabaseService = this.ensureService_('database', () => {
const dbService: typeof DatabaseService = require('../database/database-internal').DatabaseService;
return new dbService(this);
});
return service.getDatabase(url);
const fn = require('../database/index').getDatabaseWithUrl;
return fn(url, this);
}

/**
Expand Down
46 changes: 36 additions & 10 deletions src/database/database-internal.ts → src/database/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,52 @@
import { URL } from 'url';
import * as path from 'path';

import { FirebaseApp } from '../app/firebase-app';
import { FirebaseDatabaseError, AppErrorCodes, FirebaseAppError } from '../utils/error';
import { Database as DatabaseImpl } from '@firebase/database';
import { database } from './index';
import { FirebaseDatabase } from '@firebase/database-types';

import { App } from '../app';
import { FirebaseApp } from '../app/firebase-app';
import { FirebaseDatabaseError, AppErrorCodes, FirebaseAppError } from '../utils/error';
import * as validator from '../utils/validator';
import { AuthorizedHttpClient, HttpRequestConfig, HttpError } from '../utils/api-request';
import { getSdkVersion } from '../utils/index';

import Database = database.Database;
export interface Database extends FirebaseDatabase {
/**
* Gets the currently applied security rules as a string. The return value consists of
* the rules source including comments.
*
* @return A promise fulfilled with the rules as a raw string.
*/
getRules(): Promise<string>;

/**
* Gets the currently applied security rules as a parsed JSON object. Any comments in
* the original source are stripped away.
*
* @return A promise fulfilled with the parsed rules object.
*/
getRulesJSON(): Promise<object>;

/**
* Sets the specified rules on the Firebase Realtime Database instance. If the rules source is
* specified as a string or a Buffer, it may include comments.
*
* @param source Source of the rules to apply. Must not be `null` or empty.
* @return Resolves when the rules are set on the Realtime Database.
*/
setRules(source: string | Buffer | object): Promise<void>;
}

export class DatabaseService {

private readonly appInternal: FirebaseApp;
private readonly appInternal: App;

private databases: {
[dbUrl: string]: Database;
} = {};

constructor(app: FirebaseApp) {
constructor(app: App) {
if (!validator.isNonNullObject(app) || !('options' in app)) {
throw new FirebaseDatabaseError({
code: 'invalid-argument',
Expand All @@ -63,9 +89,9 @@ export class DatabaseService {
/**
* Returns the app associated with this DatabaseService instance.
*
* @return {FirebaseApp} The app associated with this DatabaseService instance.
* @return The app associated with this DatabaseService instance.
*/
get app(): FirebaseApp {
get app(): App {
return this.appInternal;
}

Expand Down Expand Up @@ -122,11 +148,11 @@ class DatabaseRulesClient {
private readonly dbUrl: string;
private readonly httpClient: AuthorizedHttpClient;

constructor(app: FirebaseApp, dbUrl: string) {
constructor(app: App, dbUrl: string) {
const parsedUrl = new URL(dbUrl);
parsedUrl.pathname = path.join(parsedUrl.pathname, RULES_URL_PATH);
this.dbUrl = parsedUrl.toString();
this.httpClient = new AuthorizedHttpClient(app);
this.httpClient = new AuthorizedHttpClient(app as FirebaseApp);
}

/**
Expand Down
89 changes: 51 additions & 38 deletions src/database/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,48 @@
* limitations under the License.
*/

import { app } from '../firebase-namespace-api';
import { ServerValue as sv } from '@firebase/database';
import * as rtdb from '@firebase/database-types';
import {
enableLogging as enableLoggingFunc,
ServerValue as serverValueConst,
} from '@firebase/database';

import { App, getApp } from '../app';
import { FirebaseApp } from '../app/firebase-app';
import { Database, DatabaseService } from './database';
import { Database as TDatabase } from './database';

export { Database };
export {
DataSnapshot,
EventType,
OnDisconnect,
Query,
Reference,
ThenableReference,
} from '@firebase/database-types';

export const enableLogging: typeof rtdb.enableLogging = enableLoggingFunc;
export const ServerValue: rtdb.ServerValue = serverValueConst;

export function getDatabase(app?: App): Database {
return getDatabaseInstance({ app });
}

export function getDatabaseWithUrl(url: string, app?: App): Database {
return getDatabaseInstance({ url, app });
}

function getDatabaseInstance(options: { url?: string; app?: App }): Database {
let { app } = options;
if (typeof app === 'undefined') {
app = getApp();
}

const firebaseApp: FirebaseApp = app as FirebaseApp;
const dbService = firebaseApp.getOrInitService('database', (app) => new DatabaseService(app));
return dbService.getDatabase(options.url);
}

/**
* Gets the {@link database.Database `Database`} service for the default
Expand Down Expand Up @@ -49,49 +88,23 @@ import * as rtdb from '@firebase/database-types';
* @return The default `Database` service if no app
* is provided or the `Database` service associated with the provided app.
*/
export declare function database(app?: app.App): database.Database;
export declare function database(app?: App): database.Database;

/* eslint-disable @typescript-eslint/no-namespace */
export namespace database {
export interface Database extends rtdb.FirebaseDatabase {
/**
* Gets the currently applied security rules as a string. The return value consists of
* the rules source including comments.
*
* @return A promise fulfilled with the rules as a raw string.
*/
getRules(): Promise<string>;

/**
* Gets the currently applied security rules as a parsed JSON object. Any comments in
* the original source are stripped away.
*
* @return A promise fulfilled with the parsed rules object.
*/
getRulesJSON(): Promise<object>;

/**
* Sets the specified rules on the Firebase Realtime Database instance. If the rules source is
* specified as a string or a Buffer, it may include comments.
*
* @param source Source of the rules to apply. Must not be `null` or empty.
* @return Resolves when the rules are set on the Realtime Database.
*/
setRules(source: string | Buffer | object): Promise<void>;
}
export type Database = TDatabase;
export type DataSnapshot = rtdb.DataSnapshot;
export type EventType = rtdb.EventType;
export type OnDisconnect = rtdb.OnDisconnect;
export type Query = rtdb.Query;
export type Reference = rtdb.Reference;
export type ThenableReference = rtdb.ThenableReference;

/* eslint-disable @typescript-eslint/no-unused-vars */
export import DataSnapshot = rtdb.DataSnapshot;
export import EventType = rtdb.EventType;
export import OnDisconnect = rtdb.OnDisconnect;
export import Query = rtdb.Query;
export import Reference = rtdb.Reference;
export import ThenableReference = rtdb.ThenableReference;
export import enableLogging = rtdb.enableLogging;
export declare const enableLogging: typeof rtdb.enableLogging;

/**
* [`ServerValue`](https://firebase.google.com/docs/reference/js/firebase.database.ServerValue)
* module from the `@firebase/database` package.
*/
export const ServerValue: rtdb.ServerValue = sv;
export declare const ServerValue: rtdb.ServerValue;
}
2 changes: 1 addition & 1 deletion test/unit/auth/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ chai.use(chaiAsPromised);

const expect = chai.expect;

describe('InstanceId', () => {
describe('Auth', () => {
let mockApp: App;
let mockCredentialApp: App;

Expand Down
6 changes: 2 additions & 4 deletions test/unit/database/database.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,11 @@ import * as sinon from 'sinon';

import * as mocks from '../../resources/mocks';
import { FirebaseApp } from '../../../src/app/firebase-app';
import { DatabaseService } from '../../../src/database/database-internal';
import { database } from '../../../src/database/index';
import { DatabaseService } from '../../../src/database/database';
import { Database } from '../../../src/database/index';
import * as utils from '../utils';
import { HttpClient, HttpRequestConfig } from '../../../src/utils/api-request';

import Database = database.Database;

describe('Database', () => {
let mockApp: FirebaseApp;
let database: DatabaseService;
Expand Down
Loading