Implement multiple database shard support

This commit is contained in:
JinHao Chen
2017-11-21 15:37:05 -08:00
committed by Akshet Pandey
parent 213f03737b
commit cc8799b465
26 changed files with 242 additions and 116 deletions

View File

@@ -9,6 +9,7 @@ import type { FirebaseModuleConfig, FirebaseNamespace } from '../types';
export default class ModuleBase {
_app: App;
_serviceUrl: ?string;
namespace: FirebaseNamespace;
/**
@@ -16,7 +17,7 @@ export default class ModuleBase {
* @param app
* @param config
*/
constructor(app: App, config: FirebaseModuleConfig) {
constructor(app: App, config: FirebaseModuleConfig, serviceUrl: ?string) {
if (!config.moduleName) {
throw new Error('Missing module name');
}
@@ -25,10 +26,11 @@ export default class ModuleBase {
}
const { moduleName } = config;
this._app = app;
this._serviceUrl = serviceUrl;
this.namespace = config.namespace;
// check if native module exists as all native
initialiseNativeModule(this, config);
initialiseNativeModule(this, config, serviceUrl);
initialiseLogger(
this,
`${app.name}:${moduleName.replace('RNFirebase', '')}`

View File

@@ -49,9 +49,16 @@ export default {
namespace: FirebaseNamespace,
InstanceClass: Class<M>
): () => FirebaseModule {
return (): M => {
if (!APP_MODULES[app._name]) {
APP_MODULES[app._name] = {};
return (serviceUrl: ?string = null): M => {
if (serviceUrl && namespace !== 'database') {
throw new Error(
INTERNALS.STRINGS.ERROR_INIT_SERVICE_URL_UNSUPPORTED(namespace)
);
}
const appOrShardName = serviceUrl || app.name;
if (!APP_MODULES[appOrShardName]) {
APP_MODULES[appOrShardName] = {};
}
if (
@@ -63,11 +70,14 @@ export default {
app.utils().checkPlayServicesAvailability();
}
if (!APP_MODULES[app._name][namespace]) {
APP_MODULES[app._name][namespace] = new InstanceClass(app, app.options);
if (!APP_MODULES[appOrShardName][namespace]) {
APP_MODULES[appOrShardName][namespace] = new InstanceClass(
serviceUrl || app,
app.options
);
}
return APP_MODULES[app._name][namespace];
return APP_MODULES[appOrShardName][namespace];
};
},
@@ -163,8 +173,13 @@ export default {
statics: S,
moduleName: FirebaseModuleName
): FirebaseModuleAndStatics<M, S> {
const getModule = (app?: App): FirebaseModule => {
let _app = app;
const getModule = (appOrUrl?: App | string): FirebaseModule => {
let _app = appOrUrl;
let _serviceUrl: ?string = null;
if (typeof appOrUrl === 'string' && namespace === 'database') {
_app = null;
_serviceUrl = appOrUrl;
}
// throw an error if it's not a valid app instance
if (_app && !(_app instanceof App))
@@ -178,7 +193,7 @@ export default {
}
// $FlowExpectedError: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323
const module = _app[namespace];
return module();
return module(_serviceUrl);
};
return Object.assign(getModule, statics, {

View File

@@ -98,6 +98,13 @@ export default {
ERROR_INIT_STRING_NAME:
'Firebase.initializeApp(options, name <-- requires a valid string value.',
/**
* @return {string}
*/
ERROR_INIT_SERVICE_URL_UNSUPPORTED(namespace: string) {
return `${namespace} does not support URL as a param, please pass in an app.`;
},
/**
* @return {string}
*/

View File

@@ -11,37 +11,40 @@ import type { FirebaseModuleConfig } from '../types';
const NATIVE_MODULES: { [string]: Object } = {};
/**
* Prepends appName arg to all native method calls
* @param appName
* Prepends all arguments in prependArgs to all native method calls
* @param NativeModule
* @param argToPrepend
*/
const nativeWithApp = (appName: string, NativeModule: Object): Object => {
const nativeWithArgs = (
NativeModule: Object,
argToPrepend: Array<mixed>
): Object => {
const native = {};
const methods = Object.keys(NativeModule);
for (let i = 0, len = methods.length; i < len; i++) {
const method = methods[i];
native[method] = (...args) => NativeModule[method](...[appName, ...args]);
native[method] = (...args) =>
NativeModule[method](...[...argToPrepend, ...args]);
}
return native;
};
const getModuleKey = (module: ModuleBase): string =>
`${module.app.name}:${module.namespace}`;
const nativeModuleKey = (module: ModuleBase): string =>
`${module._serviceUrl || module.app.name}:${module.namespace}`;
export const getNativeModule = (module: ModuleBase): Object => {
const key = getModuleKey(module);
return NATIVE_MODULES[key];
};
export const getNativeModule = (module: ModuleBase): Object =>
NATIVE_MODULES[nativeModuleKey(module)];
export const initialiseNativeModule = (
module: ModuleBase,
config: FirebaseModuleConfig
config: FirebaseModuleConfig,
serviceUrl: ?string
): Object => {
const { moduleName, multiApp, namespace } = config;
const { moduleName, multiApp, hasShards, namespace } = config;
const nativeModule = NativeModules[moduleName];
const key = getModuleKey(module);
const key = nativeModuleKey(module);
if (!nativeModule && namespace !== 'utils') {
throw new Error(
@@ -51,8 +54,16 @@ export const initialiseNativeModule = (
// used by the modules that extend ModuleBase
// to access their native module counterpart
const argToPrepend = [];
if (multiApp) {
NATIVE_MODULES[key] = nativeWithApp(module.app.name, nativeModule);
argToPrepend.push(module.app.name);
}
if (hasShards) {
argToPrepend.push(serviceUrl);
}
if (argToPrepend.length) {
NATIVE_MODULES[key] = nativeWithArgs(nativeModule, argToPrepend);
} else {
NATIVE_MODULES[key] = nativeModule;
}