diff --git a/lib/firebase-app.js b/lib/firebase-app.js
index 822616a8..6efc1f0c 100644
--- a/lib/firebase-app.js
+++ b/lib/firebase-app.js
@@ -26,15 +26,15 @@ export default class FirebaseApp {
this._nativeInitialized = false;
// modules
- this.admob = this._staticsOrModuleInstance('admob', AdMobStatics, AdMob);
- this.auth = this._staticsOrModuleInstance('auth', AuthStatics, Auth);
- this.analytics = this._staticsOrModuleInstance('analytics', {}, Analytics);
- this.config = this._staticsOrModuleInstance('config', {}, RemoteConfig);
- this.crash = this._staticsOrModuleInstance('crash', {}, Crash);
- this.database = this._staticsOrModuleInstance('database', DatabaseStatics, Database);
- this.messaging = this._staticsOrModuleInstance('messaging', MessagingStatics, Messaging);
- this.perf = this._staticsOrModuleInstance('perf', {}, Performance);
- this.storage = this._staticsOrModuleInstance('storage', StorageStatics, Storage);
+ this.admob = this._staticsOrModuleInstance(AdMobStatics, AdMob);
+ this.auth = this._staticsOrModuleInstance(AuthStatics, Auth);
+ this.analytics = this._staticsOrModuleInstance({}, Analytics);
+ this.config = this._staticsOrModuleInstance({}, RemoteConfig);
+ this.crash = this._staticsOrModuleInstance({}, Crash);
+ this.database = this._staticsOrModuleInstance(DatabaseStatics, Database);
+ this.messaging = this._staticsOrModuleInstance(MessagingStatics, Messaging);
+ this.perf = this._staticsOrModuleInstance({}, Performance);
+ this.storage = this._staticsOrModuleInstance(StorageStatics, Storage);
}
/**
@@ -117,9 +117,9 @@ export default class FirebaseApp {
* @return {function()}
* @private
*/
- _staticsOrModuleInstance(name, statics = {}, InstanceClass): Function {
+ _staticsOrModuleInstance(statics = {}, InstanceClass): Function {
const getInstance = () => {
- const _name = `_${name}`;
+ const _name = `_${InstanceClass._NAMESPACE}`;
if (!this._namespaces[_name]) {
this._namespaces[_name] = new InstanceClass(this);
@@ -129,7 +129,7 @@ export default class FirebaseApp {
};
Object.assign(getInstance, statics, {
- nativeModuleExists: !!NativeModules[`RNFirebase${InstanceClass._NATIVE_MODULE || capitalizeFirstLetter(name)}`],
+ nativeModuleExists: !!NativeModules[InstanceClass._NATIVE_MODULE],
});
return getInstance;
diff --git a/lib/firebase.js b/lib/firebase.js
index 7c7f1569..5dc4882c 100644
--- a/lib/firebase.js
+++ b/lib/firebase.js
@@ -37,15 +37,15 @@ class FirebaseCore {
}
// modules
- this.admob = this._appNamespaceOrStatics('admob', AdMobStatics, AdMob);
- this.auth = this._appNamespaceOrStatics('auth', AuthStatics, Auth);
- this.analytics = this._appNamespaceOrStatics('analytics', {}, Analytics);
- this.config = this._appNamespaceOrStatics('config', {}, RemoteConfig);
- this.crash = this._appNamespaceOrStatics('crash', {}, Crash);
- this.database = this._appNamespaceOrStatics('database', DatabaseStatics, Database);
- this.messaging = this._appNamespaceOrStatics('messaging', MessagingStatics, Messaging);
- this.perf = this._appNamespaceOrStatics('perf', DatabaseStatics, Performance);
- this.storage = this._appNamespaceOrStatics('storage', StorageStatics, Storage);
+ this.admob = this._appNamespaceOrStatics(AdMobStatics, AdMob);
+ this.auth = this._appNamespaceOrStatics(AuthStatics, Auth);
+ this.analytics = this._appNamespaceOrStatics({}, Analytics);
+ this.config = this._appNamespaceOrStatics({}, RemoteConfig);
+ this.crash = this._appNamespaceOrStatics({}, Crash);
+ this.database = this._appNamespaceOrStatics(DatabaseStatics, Database);
+ this.messaging = this._appNamespaceOrStatics(MessagingStatics, Messaging);
+ this.perf = this._appNamespaceOrStatics(DatabaseStatics, Performance);
+ this.storage = this._appNamespaceOrStatics(StorageStatics, Storage);
}
/**
@@ -205,7 +205,8 @@ class FirebaseCore {
* @return {function(FirebaseApp=)}
* @private
*/
- _appNamespaceOrStatics(namespace, statics = {}, InstanceClass): Function {
+ _appNamespaceOrStatics(statics = {}, InstanceClass): Function {
+ const namespace = InstanceClass._NAMESPACE;
const getNamespace = (app?: FirebaseApp) => {
let _app = app;
// throw an error if it's not a valid app instance
@@ -218,7 +219,7 @@ class FirebaseCore {
};
Object.assign(getNamespace, statics, {
- nativeModuleExists: !!NativeModules[`RNFirebase${InstanceClass._NATIVE_MODULE || capitalizeFirstLetter(namespace)}`],
+ nativeModuleExists: !!NativeModules[InstanceClass._NATIVE_MODULE],
});
return getNamespace;
}
diff --git a/lib/modules/admob/index.js b/lib/modules/admob/index.js
index 1961cc42..c2eb4a68 100644
--- a/lib/modules/admob/index.js
+++ b/lib/modules/admob/index.js
@@ -9,10 +9,11 @@ import NativeExpress from './NativeExpress';
export default class AdMob extends ModuleBase {
- static _NATIVE_MODULE = 'AdMob';
+ static _NAMESPACE = 'admob';
+ static _NATIVE_MODULE = 'RNFirebaseAdMob';
constructor(firebaseApp: Object, options: Object = {}) {
- super(firebaseApp, options, AdMob._NATIVE_MODULE, true);
+ super(firebaseApp, options, true);
this._initialized = false;
this._appId = null;
diff --git a/lib/modules/analytics/index.js b/lib/modules/analytics/index.js
index 278b2f0e..f468759f 100644
--- a/lib/modules/analytics/index.js
+++ b/lib/modules/analytics/index.js
@@ -20,8 +20,11 @@ const ReservedEventNames = [
];
export default class Analytics extends ModuleBase {
+ static _NAMESPACE = 'analytics';
+ static _NATIVE_MODULE = 'RNFirebaseAnalytics';
+
constructor(firebaseApp: Object, options: Object = {}) {
- super(firebaseApp, options, 'Analytics');
+ super(firebaseApp, options);
}
/**
diff --git a/lib/modules/auth/index.js b/lib/modules/auth/index.js
index ff96797e..3adcbb9e 100644
--- a/lib/modules/auth/index.js
+++ b/lib/modules/auth/index.js
@@ -12,12 +12,15 @@ import TwitterAuthProvider from './providers/Twitter';
import FacebookAuthProvider from './providers/Facebook';
export default class Auth extends ModuleBase {
+ static _NAMESPACE = 'auth';
+ static _NATIVE_MODULE = 'RNFirebaseAuth';
+
_user: User | null;
_authResult: AuthResultType | null;
authenticated: boolean;
constructor(firebaseApp: Object, options: Object = {}) {
- super(firebaseApp, options, 'Auth', true);
+ super(firebaseApp, options, true);
this._user = null;
this._authResult = null;
this.authenticated = false;
diff --git a/lib/modules/config/index.js b/lib/modules/config/index.js
index 28f7f6c8..a78f6a1d 100644
--- a/lib/modules/config/index.js
+++ b/lib/modules/config/index.js
@@ -7,9 +7,11 @@ import ModuleBase from './../../utils/ModuleBase';
* @class Config
*/
export default class RemoteConfig extends ModuleBase {
- static _NATIVE_MODULE = 'RemoteConfig';
+ static _NAMESPACE = 'config';
+ static _NATIVE_MODULE = 'RNFirebaseRemoteConfig';
+
constructor(firebaseApp: Object, options: Object = {}) {
- super(firebaseApp, options, RemoteConfig._NATIVE_MODULE);
+ super(firebaseApp, options);
this.developerModeEnabled = false;
}
diff --git a/lib/modules/crash/index.js b/lib/modules/crash/index.js
index 7ed078db..2fa2ad74 100644
--- a/lib/modules/crash/index.js
+++ b/lib/modules/crash/index.js
@@ -2,8 +2,11 @@
import ModuleBase from './../../utils/ModuleBase';
export default class Crash extends ModuleBase {
+ static _NAMESPACE = 'crash';
+ static _NATIVE_MODULE = 'RNFirebaseCrash';
+
constructor(firebaseApp: Object, options: Object = {}) {
- super(firebaseApp, options, 'Crash');
+ super(firebaseApp, options);
}
/**
diff --git a/lib/modules/database/index.js b/lib/modules/database/index.js
index a89c655e..eb90dcc5 100644
--- a/lib/modules/database/index.js
+++ b/lib/modules/database/index.js
@@ -12,8 +12,11 @@ import ModuleBase from './../../utils/ModuleBase';
* @class Database
*/
export default class Database extends ModuleBase {
+ static _NAMESPACE = 'database';
+ static _NATIVE_MODULE = 'RNFirebaseDatabase';
+
constructor(firebaseApp: Object, options: Object = {}) {
- super(firebaseApp, options, 'Database', true);
+ super(firebaseApp, options, true);
this._transactionHandler = new TransactionHandler(this);
if (this._options.persistence) {
diff --git a/lib/modules/messaging/index.js b/lib/modules/messaging/index.js
index 0b36e133..64307d9e 100644
--- a/lib/modules/messaging/index.js
+++ b/lib/modules/messaging/index.js
@@ -70,8 +70,11 @@ function finish(data) {
* @class Messaging
*/
export default class Messaging extends ModuleBase {
+ static _NAMESPACE = 'messaging';
+ static _NATIVE_MODULE = 'RNFirebaseMessaging';
+
constructor(firebaseApp: Object, options: Object = {}) {
- super(firebaseApp, options, 'Messaging', true);
+ super(firebaseApp, options, true);
}
get EVENT_TYPE() {
diff --git a/lib/modules/perf/index.js b/lib/modules/perf/index.js
index 43e42c8f..48f8c619 100644
--- a/lib/modules/perf/index.js
+++ b/lib/modules/perf/index.js
@@ -3,8 +3,11 @@ import Trace from './Trace';
import ModuleBase from '../../utils/ModuleBase';
export default class PerformanceMonitoring extends ModuleBase {
+ static _NAMESPACE = 'perf';
+ static _NATIVE_MODULE = 'RNFirebasePerformance';
+
constructor(firebaseApp: Object, options: Object = {}) {
- super(firebaseApp, options, 'Performance');
+ super(firebaseApp, options);
}
/**
diff --git a/lib/modules/storage/index.js b/lib/modules/storage/index.js
index 5cc4fb0a..eccfa45a 100644
--- a/lib/modules/storage/index.js
+++ b/lib/modules/storage/index.js
@@ -7,13 +7,15 @@ import ModuleBase from './../../utils/ModuleBase';
const FirebaseStorage = NativeModules.RNFirebaseStorage;
export default class Storage extends ModuleBase {
+ static _NAMESPACE = 'storage';
+ static _NATIVE_MODULE = 'RNFirebaseStorage';
/**
*
* @param firebaseApp
* @param options
*/
constructor(firebaseApp: Object, options: Object = {}) {
- super(firebaseApp, options, 'Storage', true);
+ super(firebaseApp, options, true);
this._subscriptions = {};
this.addListener(
diff --git a/lib/utils/ModuleBase.js b/lib/utils/ModuleBase.js
index 0473c0c2..2cda6291 100644
--- a/lib/utils/ModuleBase.js
+++ b/lib/utils/ModuleBase.js
@@ -46,31 +46,31 @@ export default class ModuleBase {
* @param moduleName
* @param withEventEmitter
*/
- constructor(firebaseApp, options, moduleName, withEventEmitter = false) {
- this._module = moduleName;
+ constructor(firebaseApp, options, withEventEmitter = false) {
+ this._module = this.constructor._NATIVE_MODULE.replace('RNFirebase', '');
this._firebaseApp = firebaseApp;
this._appName = firebaseApp._name;
this._namespace = `${this._appName}:${this._module}`;
- this._options = Object.assign({}, DEFAULTS[moduleName] || {}, options);
+ this._options = Object.assign({}, DEFAULTS[this._module] || {}, options);
// check if native module exists as all native
// modules are now optionally part of build
- const nativeModule = NativeModules[`RNFirebase${moduleName}`];
+ const nativeModule = NativeModules[this.constructor._NATIVE_MODULE];
if (!nativeModule) {
- throw new Error(INTERNALS.STRINGS.ERROR_MISSING_MODULE(moduleName));
+ throw new Error(INTERNALS.STRINGS.ERROR_MISSING_MODULE(this.constructor._NATIVE_MODULE));
}
// used by the modules that extend ModuleBase
// to access their native module counterpart
- if (!MULTI_APP_MODULES.includes(moduleName.toLowerCase())) {
+ if (!MULTI_APP_MODULES.includes(this._module.toLowerCase())) {
this._native = nativeModule;
} else {
this._native = nativeWithApp(this._appName, nativeModule);
}
if (withEventEmitter) {
- this._setupEventEmitter(nativeModule, moduleName);
+ this._setupEventEmitter(nativeModule, this._module);
}
}
diff --git a/tests/src/bench.js b/tests/src/bench.js
new file mode 100644
index 00000000..87085425
--- /dev/null
+++ b/tests/src/bench.js
@@ -0,0 +1,92 @@
+import React, { Component } from 'react';
+import { View, Button, Text } from 'react-native';
+import sinon from 'sinon';
+import 'should-sinon';
+import Promise from 'bluebird';
+
+import firebase from './firebase';
+import DatabaseContents from './tests/support/DatabaseContents';
+
+
+export default class HomeScreen extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ timeTaken: '',
+ };
+ }
+
+ clickMe = () => {
+ this.setState({ timeTaken: 'Running...' });
+ let start = null;
+ Promise.all([
+ firebase.native.database().ref('tests/types').set(DatabaseContents.DEFAULT),
+ firebase.native.database().ref('tests/priority').setWithPriority({
+ foo: 'bar',
+ }, 666),
+ firebase.native.database().ref('tests/query').set(DatabaseContents.QUERY),
+ ]).then(() => {
+ start = Date.now();
+ return Promise.each(Object.keys(DatabaseContents.DEFAULT), async (dataRef) => {
+ // Setup
+ const ref = firebase.native.database().ref(`tests/types/${dataRef}`);
+ const currentDataValue = DatabaseContents.DEFAULT[dataRef];
+
+ const callbackA = sinon.spy();
+ const callbackB = sinon.spy();
+
+ // Test
+
+ await new Promise((resolve) => {
+ ref.on('value', (snapshot) => {
+ callbackA(snapshot.val());
+ resolve();
+ });
+ });
+
+ await new Promise((resolve) => {
+ ref.on('value', (snapshot) => {
+ callbackB(snapshot.val());
+ resolve();
+ });
+ });
+
+ callbackA.should.be.calledWith(currentDataValue);
+ callbackA.should.be.calledOnce();
+
+ callbackB.should.be.calledWith(currentDataValue);
+ callbackB.should.be.calledOnce();
+
+ const newDataValue = DatabaseContents.NEW[dataRef];
+ await ref.set(newDataValue);
+
+ await new Promise((resolve) => {
+ setTimeout(() => resolve(), 5);
+ });
+
+ callbackA.should.be.calledWith(newDataValue);
+ callbackB.should.be.calledWith(newDataValue);
+
+ callbackA.should.be.calledTwice();
+ callbackB.should.be.calledTwice();
+
+ // Tear down
+
+ ref.off('value');
+ return Promise.resolve();
+ });
+ }).then(() => {
+ this.setState({ timeTaken: `Took ${Date.now() - start}` });
+ }).catch(console.error);
+ };
+
+ render() {
+ return (
+
+
+ {this.state.timeTaken || ''}
+
+ );
+ }
+}
diff --git a/tests/src/playground.js b/tests/src/playground.js
index fbe2e3bf..b79c20f6 100644
--- a/tests/src/playground.js
+++ b/tests/src/playground.js
@@ -1,5 +1,5 @@
import React, { Component } from 'react';
-import { View, Text, Button } from 'react-native';
+import { View, SectionList, Text, Button } from 'react-native';
export default class HomeScreen extends Component {
@@ -28,3 +28,132 @@ export default class HomeScreen extends Component {
);
}
}
+
+const sampleData = {
+ somePostId1: {
+ title: 'today now',
+ timestamp: Date.now(),
+ startOfDay: 1502838000,
+ },
+
+ somePostId3: {
+ title: 'today but older',
+ timestamp: Date.now() - 10000000,
+ startOfDay: 1502838000,
+ },
+
+ somePostId4: {
+ title: 'today but even older',
+ timestamp: Date.now() - 60000000,
+ startOfDay: 1502838000,
+ },
+
+ somePostId2: {
+ title: 'hello yesterday',
+ timestamp: Date.now() - 82000000, // minus 23 hours - just to make it yesterday ;p
+ startOfDay: 1502751600, // yesterday ;p
+ },
+
+ somePostId5: {
+ title: 'hello yesterday but older',
+ timestamp: Date.now() - 82800000, // minus 23 hours - just to make it yesterday ;p
+ startOfDay: 1502751600, // yesterday ;p
+ },
+};
+
+// export default class PostsScreen extends Component {
+// constructor(props) {
+// super(props);
+// this.ref = null;
+// this.state = {
+// postSections: [],
+// };
+// }
+//
+// componentDidMount() {
+// // this.ref = firebase.database().ref('posts');
+// // this.ref.on('value', this._onPostsUpdate);
+// // just fake it to test
+// this._onPostsUpdate({
+// val() {
+// return sampleData;
+// },
+// });
+// }
+//
+// componentWillUnmount() {
+// // always unsubscribe from realtime events when component unmounts
+// // if (this.ref) {
+// // this.ref.off('value', this._onPostsUpdate);
+// // }
+// }
+//
+// _onPostsUpdate(snapshot) {
+// const value = snapshot.val() || {};
+// const keys = Object.keys(value);
+// const sections = {};
+//
+// // we'll group them now by date
+// for (let i = 0, len = keys.length; i < len; i++) {
+// const key = keys[i];
+// const post = value[key];
+//
+// // assuming post will have a 'timestamp' field and a `startOfDay` field
+// // start of day can be calculated as above `startOfToday`
+//
+// if (!sections[post.startOfDay]) {
+// sections[post.startOfDay] = {
+// title: 'Header - I will leave this up to you', // todo today/yesterday/3 days ago etc
+// // will use this later to sort the sections so today is on top
+// key: post.startOfDay,
+// data: [],
+// };
+// }
+//
+// const data = Object.assign({ key }, post);
+// // add a post to a specific section date
+// // we'll push/unshift depending on the date, so they' appear in order
+// if (!sections[post.startOfDay].data.length) {
+// // array is empty so nothing to compare sort, just push it
+// sections[post.startOfDay].data.push(data);
+// } else {
+// const previousTimestamp = sections[post.startOfDay].data[sections[post.startOfDay].data.length - 1].timestamp;
+// if (previousTimestamp < data.timestamp) sections[post.startOfDay].data.unshift(data);
+// else sections[post.startOfDay].data.push(data);
+// }
+// }
+//
+// this.setState({
+// postSections: Object.values(sections).sort((a, b) => a.key > b.key).reverse(),
+// });
+// }
+//
+// _renderSectionItem = ({ item }) => {
+// // todo your custom section item component
+// // return (
+// //
+// // );
+//
+// return {`${item.title} - ${item.timestamp}`};
+// };
+//
+// _renderSectionHeader = ({ section }) => {
+// // todo your custom section header
+// return (
+// {section.title}
+// );
+// };
+//
+// render() {
+// return (
+//
+// );
+// }
+// }