Skip to content

Commit edad44d

Browse files
authored
feat(database): enable database multi-resource support (#159)
* feat(database): enable database multi-resource support * refactor(database): fix property names
1 parent c4d6e20 commit edad44d

File tree

4 files changed

+82
-17
lines changed

4 files changed

+82
-17
lines changed

src/database.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export function registerDatabase(instance: FirebaseNamespace) {
2929
// Register the Database Service with the 'firebase' namespace.
3030
const namespace = instance.INTERNAL.registerService(
3131
'database',
32-
app => RepoManager.getInstance().databaseFromApp(app),
32+
(app, unused, url) => RepoManager.getInstance().databaseFromApp(app, url),
3333
// firebase.database namespace properties
3434
{
3535
Reference,
@@ -39,7 +39,9 @@ export function registerDatabase(instance: FirebaseNamespace) {
3939
INTERNAL,
4040
ServerValue: Database.ServerValue,
4141
TEST_ACCESS
42-
}
42+
},
43+
null,
44+
true
4345
);
4446

4547
if (isNodeSdk()) {

src/database/core/Repo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export class Repo {
8484
* @param {!FirebaseApp} app
8585
*/
8686
constructor(
87-
private repoInfo_: RepoInfo,
87+
public repoInfo_: RepoInfo,
8888
forceRestClient: boolean,
8989
public app: FirebaseApp
9090
) {

src/database/core/RepoManager.ts

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ let _staticInstance: RepoManager;
3434
*/
3535
export class RepoManager {
3636
/**
37-
* @private {!Object.<string, !Repo>}
37+
* @private {!Object.<string, Object<string, !fb.core.Repo>>}
3838
*/
3939
private repos_: {
40-
[name: string]: Repo;
40+
[appName: string]: {
41+
[dbUrl: string]: Repo;
42+
};
4143
} = {};
4244

4345
/**
@@ -55,14 +57,18 @@ export class RepoManager {
5557

5658
// TODO(koss): Remove these functions unless used in tests?
5759
interrupt() {
58-
for (const repo in this.repos_) {
59-
this.repos_[repo].interrupt();
60+
for (const appName in this.repos_) {
61+
for (const dbUrl in this.repos_[appName]) {
62+
this.repos_[appName][dbUrl].interrupt();
63+
}
6064
}
6165
}
6266

6367
resume() {
64-
for (const repo in this.repos_) {
65-
this.repos_[repo].resume();
68+
for (const appName in this.repos_) {
69+
for (const dbUrl in this.repos_[appName]) {
70+
this.repos_[appName][dbUrl].resume();
71+
}
6672
}
6773
}
6874

@@ -72,8 +78,8 @@ export class RepoManager {
7278
* @param {!FirebaseApp} app
7379
* @return {!Database}
7480
*/
75-
databaseFromApp(app: FirebaseApp): Database {
76-
const dbUrl: string = app.options[DATABASE_URL_OPTION];
81+
databaseFromApp(app: FirebaseApp, url?: string): Database {
82+
const dbUrl: string = url || app.options[DATABASE_URL_OPTION];
7783
if (dbUrl === undefined) {
7884
fatal(
7985
"Can't determine Firebase Database URL. Be sure to include " +
@@ -104,12 +110,15 @@ export class RepoManager {
104110
* @param {!Repo} repo
105111
*/
106112
deleteRepo(repo: Repo) {
113+
const appRepos = safeGet(this.repos_, repo.app.name);
107114
// This should never happen...
108-
if (safeGet(this.repos_, repo.app.name) !== repo) {
109-
fatal('Database ' + repo.app.name + ' has already been deleted.');
115+
if (!appRepos || safeGet(appRepos, repo.repoInfo_.toURLString()) !== repo) {
116+
fatal(
117+
`Database ${repo.app.name}(${repo.repoInfo_}) has already been deleted.`
118+
);
110119
}
111120
repo.interrupt();
112-
delete this.repos_[repo.app.name];
121+
delete appRepos[repo.repoInfo_.toURLString()];
113122
}
114123

115124
/**
@@ -121,12 +130,21 @@ export class RepoManager {
121130
* @return {!Repo} The Repo object for the specified server / repoName.
122131
*/
123132
createRepo(repoInfo: RepoInfo, app: FirebaseApp): Repo {
124-
let repo = safeGet(this.repos_, app.name);
133+
let appRepos = safeGet(this.repos_, app.name);
134+
135+
if (!appRepos) {
136+
appRepos = {};
137+
this.repos_[app.name] = appRepos;
138+
}
139+
140+
let repo = safeGet(appRepos, repoInfo.toURLString());
125141
if (repo) {
126-
fatal('FIREBASE INTERNAL ERROR: Database initialized multiple times.');
142+
fatal(
143+
'Database initialized multiple times. Please make sure the format of the database URL matches with each database() call.'
144+
);
127145
}
128146
repo = new Repo(repoInfo, this.useRestClient_, app);
129-
this.repos_[app.name] = repo;
147+
appRepos[repoInfo.toURLString()] = repo;
130148

131149
return repo;
132150
}

tests/database/database.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,51 @@ describe('Database Tests', function() {
4545
}).to.throw(/don't call new Database/i);
4646
});
4747

48+
it('Can get database with custom URL', function() {
49+
var db = defaultApp.database('http://foo.bar.com');
50+
expect(db).to.be.ok;
51+
// The URL is assumed to be secure if no port is specified.
52+
expect(db.ref().toString()).to.equal('https://foo.bar.com/');
53+
});
54+
55+
it('Can get database with custom URL and port', function() {
56+
var db = defaultApp.database('http://foo.bar.com:80');
57+
expect(db).to.be.ok;
58+
expect(db.ref().toString()).to.equal('http://foo.bar.com:80/');
59+
});
60+
61+
it('Can get database with https URL', function() {
62+
var db = defaultApp.database('https://foo.bar.com');
63+
expect(db).to.be.ok;
64+
expect(db.ref().toString()).to.equal('https://foo.bar.com/');
65+
});
66+
67+
it('Different instances for different URLs', function() {
68+
var db1 = defaultApp.database('http://foo1.bar.com');
69+
var db2 = defaultApp.database('http://foo2.bar.com');
70+
expect(db1.ref().toString()).to.equal('https://foo1.bar.com/');
71+
expect(db2.ref().toString()).to.equal('https://foo2.bar.com/');
72+
});
73+
74+
it('Cannot use same URL twice', function() {
75+
defaultApp.database('http://foo.bar.com');
76+
expect(function() {
77+
defaultApp.database('http://foo.bar.com/');
78+
}).to.throw(/Database initialized multiple times/i);
79+
});
80+
81+
it('Databases with invalid custom URLs', function() {
82+
expect(function() {
83+
defaultApp.database('not-a-url');
84+
}).to.throw(/Cannot parse Firebase url/i);
85+
expect(function() {
86+
defaultApp.database('http://fblocal.com');
87+
}).to.throw(/Cannot parse Firebase url/i);
88+
expect(function() {
89+
defaultApp.database('http://x.fblocal.com:9000/paths/are/bad');
90+
}).to.throw(/Database URL must point to the root of a Firebase Database/i);
91+
});
92+
4893
it('Can get app', function() {
4994
const db = firebase.database();
5095
expect(db.app).to.not.be.undefined;

0 commit comments

Comments
 (0)