Skip to content

Commit bb80d31

Browse files
authored
refactor(database): Add typescript database implementation [Part 2/3] (#62)
* refactor(database): add typescript implementation * refactor(database): update build process to include database.ts All integration tests pass at this point * refactor(*): refactor environment builds to be based on separate .ts files * WIP: patch database code in nodeJS * refactor(database): classes for typescript database implementation (#55) * refactor(database): classes for typescript database implementation * refactor(database): requested changes & other improvements * fix(database): Add missing "typeof" (#74) https://github.com/firebase/firebase-js-sdk/blob/fd0728138d88c454f8e38a78f35d831d6365070c/src/database/js-client/core/Repo.js#L86 * WIP: fixes from @schmidt-sebastian's review * WIP: fix: TS Build error * fix(database): fix issue with missing repo method * WIP: review adjustments #1 * WIP: review comments #2
1 parent bbd86c1 commit bb80d31

File tree

107 files changed

+17934
-111
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+17934
-111
lines changed

gulp/config.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ module.exports = {
4545
babel: {
4646
plugins: [
4747
require('babel-plugin-add-module-exports'),
48-
require('babel-plugin-minify-dead-code-elimination')
4948
],
5049
presets: [
5150
[require('babel-preset-env'), {

gulp/tasks/build.js

Lines changed: 12 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ function compileIndvES2015ModulesToBrowser() {
134134
'firebase-app': './src/app.ts',
135135
'firebase-storage': './src/storage.ts',
136136
'firebase-messaging': './src/messaging.ts',
137+
'firebase-database': './src/database.ts',
137138
},
138139
output: {
139140
path: path.resolve(__dirname, './dist/browser'),
@@ -192,27 +193,6 @@ function compileIndvES2015ModulesToBrowser() {
192193
.pipe(gulp.dest(`${config.paths.outDir}/browser`));
193194
}
194195

195-
function compileSDKES2015ToBrowser() {
196-
return gulp.src('./dist/es2015/firebase.js')
197-
.pipe(webpackStream({
198-
plugins: [
199-
new webpack.DefinePlugin({
200-
TARGET_ENVIRONMENT: JSON.stringify('browser')
201-
})
202-
]
203-
}, webpack))
204-
.pipe(sourcemaps.init({ loadMaps: true }))
205-
.pipe(through.obj(function(file, enc, cb) {
206-
// Dont pipe through any source map files as it will be handled
207-
// by gulp-sourcemaps
208-
var isSourceMap = /\.map$/.test(file.path);
209-
if (!isSourceMap) this.push(file);
210-
cb();
211-
}))
212-
.pipe(sourcemaps.write('.'))
213-
.pipe(gulp.dest(`${config.paths.outDir}/browser`));
214-
}
215-
216196
function buildBrowserFirebaseJs() {
217197
return gulp.src('./dist/browser/*.js')
218198
.pipe(sourcemaps.init({ loadMaps: true }))
@@ -222,32 +202,18 @@ function buildBrowserFirebaseJs() {
222202
}
223203

224204
function buildAltEnvFirebaseJs() {
225-
const envs = [
226-
'browser',
227-
'node',
228-
'react-native'
229-
];
230-
231-
const streams = envs.map(env => {
232-
const babelConfig = Object.assign({}, config.babel, {
233-
plugins: [
234-
['inline-replace-variables', {
235-
'TARGET_ENVIRONMENT': env
236-
}],
237-
...config.babel.plugins
238-
]
239-
});
240-
return gulp.src('./dist/es2015/firebase.js')
241-
.pipe(sourcemaps.init({ loadMaps: true }))
242-
.pipe(babel(babelConfig))
243-
.pipe(rename({
244-
suffix: `-${env}`
245-
}))
246-
.pipe(sourcemaps.write('.'))
247-
.pipe(gulp.dest(`${config.paths.outDir}/cjs`));
205+
const babelConfig = Object.assign({}, config.babel, {
206+
plugins: config.babel.plugins
248207
});
249-
250-
return merge(streams);
208+
return gulp.src([
209+
'./dist/es2015/firebase-browser.js',
210+
'./dist/es2015/firebase-node.js',
211+
'./dist/es2015/firebase-react-native.js',
212+
])
213+
.pipe(sourcemaps.init({ loadMaps: true }))
214+
.pipe(babel(babelConfig))
215+
.pipe(sourcemaps.write('.'))
216+
.pipe(gulp.dest(`${config.paths.outDir}/cjs`));
251217
}
252218

253219
function copyPackageContents() {

src/database.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Copyright 2017 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import firebase from './app';
18+
import { FirebaseApp, FirebaseNamespace } from "./app/firebase_app";
19+
import { Database } from "./database/api/Database";
20+
import { Query } from "./database/api/Query";
21+
import { Reference } from "./database/api/Reference";
22+
import { enableLogging } from "./database/core/util/util";
23+
import { RepoManager } from "./database/core/RepoManager";
24+
import * as INTERNAL from './database/api/internal';
25+
import * as TEST_ACCESS from './database/api/test_access';
26+
import { isNodeSdk } from "./utils/environment";
27+
28+
export function registerDatabase(instance) {
29+
// Register the Database Service with the 'firebase' namespace.
30+
const namespace = instance.INTERNAL.registerService(
31+
'database',
32+
app => RepoManager.getInstance().databaseFromApp(app),
33+
// firebase.database namespace properties
34+
{
35+
Reference,
36+
Query,
37+
Database,
38+
enableLogging,
39+
INTERNAL,
40+
ServerValue: Database.ServerValue,
41+
TEST_ACCESS
42+
}
43+
);
44+
45+
if (isNodeSdk()) {
46+
module.exports = namespace;
47+
}
48+
}
49+
50+
/**
51+
* Extensions to the FirebaseApp and FirebaseNamespaces interfaces
52+
*/
53+
declare module './app/firebase_app' {
54+
interface FirebaseApp {
55+
database?(): Database
56+
}
57+
}
58+
59+
declare module './app/firebase_app' {
60+
interface FirebaseNamespace {
61+
database?(app: FirebaseApp): Database
62+
}
63+
}
64+
65+
registerDatabase(firebase);

src/database/api/DataSnapshot.ts

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import { validateArgCount, validateCallback } from '../../utils/validation';
2+
import { validatePathString } from '../core/util/validation';
3+
import { Path } from '../core/util/Path';
4+
import { PRIORITY_INDEX } from '../core/snap/indexes/PriorityIndex';
5+
import { Node } from '../core/snap/Node';
6+
import { Reference } from './Reference';
7+
import { Index } from '../core/snap/indexes/Index';
8+
import { ChildrenNode } from '../core/snap/ChildrenNode';
9+
10+
/**
11+
* Class representing a firebase data snapshot. It wraps a SnapshotNode and
12+
* surfaces the public methods (val, forEach, etc.) we want to expose.
13+
*/
14+
export class DataSnapshot {
15+
/**
16+
* @param {!Node} node_ A SnapshotNode to wrap.
17+
* @param {!Reference} ref_ The ref of the location this snapshot came from.
18+
* @param {!Index} index_ The iteration order for this snapshot
19+
*/
20+
constructor(private readonly node_: Node,
21+
private readonly ref_: Reference,
22+
private readonly index_: Index) {
23+
}
24+
25+
/**
26+
* Retrieves the snapshot contents as JSON. Returns null if the snapshot is
27+
* empty.
28+
*
29+
* @return {*} JSON representation of the DataSnapshot contents, or null if empty.
30+
*/
31+
val(): any {
32+
validateArgCount('DataSnapshot.val', 0, 0, arguments.length);
33+
return this.node_.val();
34+
}
35+
36+
/**
37+
* Returns the snapshot contents as JSON, including priorities of node. Suitable for exporting
38+
* the entire node contents.
39+
* @return {*} JSON representation of the DataSnapshot contents, or null if empty.
40+
*/
41+
exportVal(): any {
42+
validateArgCount('DataSnapshot.exportVal', 0, 0, arguments.length);
43+
return this.node_.val(true);
44+
}
45+
46+
// Do not create public documentation. This is intended to make JSON serialization work but is otherwise unnecessary
47+
// for end-users
48+
toJSON(): any {
49+
// Optional spacer argument is unnecessary because we're depending on recursion rather than stringifying the content
50+
validateArgCount('DataSnapshot.toJSON', 0, 1, arguments.length);
51+
return this.exportVal();
52+
}
53+
54+
/**
55+
* Returns whether the snapshot contains a non-null value.
56+
*
57+
* @return {boolean} Whether the snapshot contains a non-null value, or is empty.
58+
*/
59+
exists(): boolean {
60+
validateArgCount('DataSnapshot.exists', 0, 0, arguments.length);
61+
return !this.node_.isEmpty();
62+
}
63+
64+
/**
65+
* Returns a DataSnapshot of the specified child node's contents.
66+
*
67+
* @param {!string} childPathString Path to a child.
68+
* @return {!DataSnapshot} DataSnapshot for child node.
69+
*/
70+
child(childPathString: string): DataSnapshot {
71+
validateArgCount('DataSnapshot.child', 0, 1, arguments.length);
72+
// Ensure the childPath is a string (can be a number)
73+
childPathString = String(childPathString);
74+
validatePathString('DataSnapshot.child', 1, childPathString, false);
75+
76+
const childPath = new Path(childPathString);
77+
const childRef = this.ref_.child(childPath);
78+
return new DataSnapshot(this.node_.getChild(childPath), childRef, PRIORITY_INDEX);
79+
}
80+
81+
/**
82+
* Returns whether the snapshot contains a child at the specified path.
83+
*
84+
* @param {!string} childPathString Path to a child.
85+
* @return {boolean} Whether the child exists.
86+
*/
87+
hasChild(childPathString: string): boolean {
88+
validateArgCount('DataSnapshot.hasChild', 1, 1, arguments.length);
89+
validatePathString('DataSnapshot.hasChild', 1, childPathString, false);
90+
91+
const childPath = new Path(childPathString);
92+
return !this.node_.getChild(childPath).isEmpty();
93+
}
94+
95+
/**
96+
* Returns the priority of the object, or null if no priority was set.
97+
*
98+
* @return {string|number|null} The priority.
99+
*/
100+
getPriority(): string | number | null {
101+
validateArgCount('DataSnapshot.getPriority', 0, 0, arguments.length);
102+
103+
// typecast here because we never return deferred values or internal priorities (MAX_PRIORITY)
104+
return /**@type {string|number|null} */ <string | number | null>(this.node_.getPriority().val());
105+
}
106+
107+
/**
108+
* Iterates through child nodes and calls the specified action for each one.
109+
*
110+
* @param {function(!DataSnapshot)} action Callback function to be called
111+
* for each child.
112+
* @return {boolean} True if forEach was canceled by action returning true for
113+
* one of the child nodes.
114+
*/
115+
forEach(action: (d: DataSnapshot) => any): boolean {
116+
validateArgCount('DataSnapshot.forEach', 1, 1, arguments.length);
117+
validateCallback('DataSnapshot.forEach', 1, action, false);
118+
119+
if (this.node_.isLeafNode())
120+
return false;
121+
122+
const childrenNode = /**@type {ChildrenNode} */ <ChildrenNode>(this.node_);
123+
// Sanitize the return value to a boolean. ChildrenNode.forEachChild has a weird return type...
124+
return !!childrenNode.forEachChild(this.index_, (key, node) => {
125+
return action(new DataSnapshot(node, this.ref_.child(key), PRIORITY_INDEX));
126+
});
127+
}
128+
129+
/**
130+
* Returns whether this DataSnapshot has children.
131+
* @return {boolean} True if the DataSnapshot contains 1 or more child nodes.
132+
*/
133+
hasChildren(): boolean {
134+
validateArgCount('DataSnapshot.hasChildren', 0, 0, arguments.length);
135+
136+
if (this.node_.isLeafNode())
137+
return false;
138+
else
139+
return !this.node_.isEmpty();
140+
}
141+
142+
get key() {
143+
return this.ref_.getKey();
144+
}
145+
146+
/**
147+
* Returns the number of children for this DataSnapshot.
148+
* @return {number} The number of children that this DataSnapshot contains.
149+
*/
150+
numChildren(): number {
151+
validateArgCount('DataSnapshot.numChildren', 0, 0, arguments.length);
152+
153+
return this.node_.numChildren();
154+
}
155+
156+
/**
157+
* @return {Reference} The Firebase reference for the location this snapshot's data came from.
158+
*/
159+
getRef(): Reference {
160+
validateArgCount('DataSnapshot.ref', 0, 0, arguments.length);
161+
162+
return this.ref_;
163+
}
164+
165+
get ref() {
166+
return this.getRef();
167+
}
168+
}

0 commit comments

Comments
 (0)