From cc8799b465d1ff24da69ef0fab9e8c0b9b69de15 Mon Sep 17 00:00:00 2001 From: JinHao Chen Date: Tue, 21 Nov 2017 15:37:05 -0800 Subject: [PATCH 1/2] Implement multiple database shard support --- .../firebase/database/RNFirebaseDatabase.java | 94 ++++++++++--------- .../database/RNFirebaseDatabaseReference.java | 13 ++- .../RNFirebaseTransactionHandler.java | 6 +- ios/RNFirebase/database/RNFirebaseDatabase.h | 1 + ios/RNFirebase/database/RNFirebaseDatabase.m | 88 +++++++++++------ .../database/RNFirebaseDatabaseReference.h | 3 +- .../database/RNFirebaseDatabaseReference.m | 4 +- lib/modules/admob/index.js | 1 + lib/modules/analytics/index.js | 1 + lib/modules/auth/index.js | 1 + lib/modules/config/index.js | 1 + lib/modules/crash/index.js | 1 + lib/modules/database/Reference.js | 10 +- lib/modules/database/index.js | 41 ++++++-- lib/modules/fabric/crashlytics/index.js | 1 + lib/modules/firestore/index.js | 1 + lib/modules/links/index.js | 1 + lib/modules/messaging/index.js | 1 + lib/modules/perf/index.js | 1 + lib/modules/storage/index.js | 1 + lib/modules/utils/index.js | 1 + lib/types/index.js | 1 + lib/utils/ModuleBase.js | 6 +- lib/utils/apps.js | 33 +++++-- lib/utils/internals.js | 7 ++ lib/utils/native.js | 39 +++++--- 26 files changed, 242 insertions(+), 116 deletions(-) diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java index 59eb04d4..e628fc05 100644 --- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java +++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java @@ -53,16 +53,16 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param appName */ @ReactMethod - public void goOnline(String appName) { - getDatabaseForApp(appName).goOnline(); + public void goOnline(String appName, String dbURL) { + getDatabaseForApp(appName, dbURL).goOnline(); } /** * @param appName */ @ReactMethod - public void goOffline(String appName) { - getDatabaseForApp(appName).goOffline(); + public void goOffline(String appName, String dbURL) { + getDatabaseForApp(appName, dbURL).goOffline(); } /** @@ -70,8 +70,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param state */ @ReactMethod - public void setPersistence(String appName, Boolean state) { - getDatabaseForApp(appName).setPersistenceEnabled(state); + public void setPersistence(String appName, String dbURL, Boolean state) { + getDatabaseForApp(appName, dbURL).setPersistenceEnabled(state); } /** @@ -79,8 +79,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param size */ @ReactMethod - public void setPersistenceCacheSizeBytes(String appName, int size) { - getDatabaseForApp(appName).setPersistenceCacheSizeBytes((long) size); + public void setPersistenceCacheSizeBytes(String appName, String dbURL, int size) { + getDatabaseForApp(appName, dbURL).setPersistenceCacheSizeBytes((long) size); } @@ -116,8 +116,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param state */ @ReactMethod - public void keepSynced(String appName, String key, String path, ReadableArray modifiers, Boolean state) { - getInternalReferenceForApp(appName, key, path, modifiers).getQuery().keepSynced(state); + public void keepSynced(String appName, String dbURL, String key, String path, ReadableArray modifiers, Boolean state) { + getInternalReferenceForApp(appName, dbURL, key, path, modifiers).getQuery().keepSynced(state); } @@ -130,7 +130,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param updates */ @ReactMethod - public void transactionTryCommit(String appName, int transactionId, ReadableMap updates) { + public void transactionTryCommit(String appName, String dbURL, int transactionId, ReadableMap updates) { RNFirebaseTransactionHandler handler = transactionHandlers.get(transactionId); if (handler != null) { @@ -147,16 +147,16 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param applyLocally */ @ReactMethod - public void transactionStart(final String appName, final String path, final int transactionId, final Boolean applyLocally) { + public void transactionStart(final String appName, final String dbURL, final String path, final int transactionId, final Boolean applyLocally) { AsyncTask.execute(new Runnable() { @Override public void run() { - DatabaseReference reference = getReferenceForAppPath(appName, path); + DatabaseReference reference = getReferenceForAppPath(appName, dbURL, path); reference.runTransaction(new Transaction.Handler() { @Override public Transaction.Result doTransaction(MutableData mutableData) { - final RNFirebaseTransactionHandler transactionHandler = new RNFirebaseTransactionHandler(transactionId, appName); + final RNFirebaseTransactionHandler transactionHandler = new RNFirebaseTransactionHandler(transactionId, appName, dbURL); transactionHandlers.put(transactionId, transactionHandler); final WritableMap updatesMap = transactionHandler.createUpdateMap(mutableData); @@ -212,9 +212,9 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void onDisconnectSet(String appName, String path, ReadableMap props, final Promise promise) { + public void onDisconnectSet(String appName, String dbURL, String path, ReadableMap props, final Promise promise) { String type = props.getString("type"); - DatabaseReference ref = getReferenceForAppPath(appName, path); + DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); OnDisconnect onDisconnect = ref.onDisconnect(); DatabaseReference.CompletionListener listener = new DatabaseReference.CompletionListener() { @@ -257,8 +257,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void onDisconnectUpdate(String appName, String path, ReadableMap props, final Promise promise) { - DatabaseReference ref = getReferenceForAppPath(appName, path); + public void onDisconnectUpdate(String appName, String dbURL, String path, ReadableMap props, final Promise promise) { + DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); OnDisconnect ondDisconnect = ref.onDisconnect(); Map map = Utils.recursivelyDeconstructReadableMap(props); @@ -279,8 +279,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void onDisconnectRemove(String appName, String path, final Promise promise) { - DatabaseReference ref = getReferenceForAppPath(appName, path); + public void onDisconnectRemove(String appName, String dbURL, String path, final Promise promise) { + DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); OnDisconnect onDisconnect = ref.onDisconnect(); onDisconnect.removeValue(new DatabaseReference.CompletionListener() { @@ -299,8 +299,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void onDisconnectCancel(String appName, String path, final Promise promise) { - DatabaseReference ref = getReferenceForAppPath(appName, path); + public void onDisconnectCancel(String appName, String dbURL, String path, final Promise promise) { + DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); OnDisconnect onDisconnect = ref.onDisconnect(); onDisconnect.cancel(new DatabaseReference.CompletionListener() { @@ -318,8 +318,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void set(String appName, String path, ReadableMap props, final Promise promise) { - DatabaseReference ref = getReferenceForAppPath(appName, path); + public void set(String appName, String dbURL, String path, ReadableMap props, final Promise promise) { + DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); Object value = Utils.recursivelyDeconstructReadableMap(props).get("value"); DatabaseReference.CompletionListener listener = new DatabaseReference.CompletionListener() { @@ -339,8 +339,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void setPriority(String appName, String path, ReadableMap priority, final Promise promise) { - DatabaseReference ref = getReferenceForAppPath(appName, path); + public void setPriority(String appName, String dbURL, String path, ReadableMap priority, final Promise promise) { + DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); Object priorityValue = Utils.recursivelyDeconstructReadableMap(priority).get("value"); DatabaseReference.CompletionListener listener = new DatabaseReference.CompletionListener() { @@ -361,8 +361,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void setWithPriority(String appName, String path, ReadableMap data, ReadableMap priority, final Promise promise) { - DatabaseReference ref = getReferenceForAppPath(appName, path); + public void setWithPriority(String appName, String dbURL, String path, ReadableMap data, ReadableMap priority, final Promise promise) { + DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); Object dataValue = Utils.recursivelyDeconstructReadableMap(data).get("value"); Object priorityValue = Utils.recursivelyDeconstructReadableMap(priority).get("value"); @@ -383,8 +383,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void update(String appName, String path, ReadableMap props, final Promise promise) { - DatabaseReference ref = getReferenceForAppPath(appName, path); + public void update(String appName, String dbURL, String path, ReadableMap props, final Promise promise) { + DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); Map updates = Utils.recursivelyDeconstructReadableMap(props); DatabaseReference.CompletionListener listener = new DatabaseReference.CompletionListener() { @@ -403,8 +403,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void remove(String appName, String path, final Promise promise) { - DatabaseReference ref = getReferenceForAppPath(appName, path); + public void remove(String appName, String dbURL, String path, final Promise promise) { + DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); DatabaseReference.CompletionListener listener = new DatabaseReference.CompletionListener() { @Override @@ -428,8 +428,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void once(String appName, String key, String path, ReadableArray modifiers, String eventType, Promise promise) { - getInternalReferenceForApp(appName, key, path, modifiers).once(eventType, promise); + public void once(String appName, String dbURL, String key, String path, ReadableArray modifiers, String eventType, Promise promise) { + getInternalReferenceForApp(appName, dbURL, key, path, modifiers).once(eventType, promise); } /** @@ -439,8 +439,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param props ReadableMap */ @ReactMethod - public void on(String appName, ReadableMap props) { - getCachedInternalReferenceForApp(appName, props) + public void on(String appName, String dbURL, ReadableMap props) { + getCachedInternalReferenceForApp(appName, dbURL, props) .on( props.getString("eventType"), props.getMap("registration") @@ -496,9 +496,14 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param appName * @return */ - private FirebaseDatabase getDatabaseForApp(String appName) { - FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); - FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance(firebaseApp); + private FirebaseDatabase getDatabaseForApp(String appName, String dbURL) { + FirebaseDatabase firebaseDatabase; + if(dbURL != null && dbURL.length() > 0) { + firebaseDatabase = FirebaseDatabase.getInstance(dbURL); + } else { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + firebaseDatabase = FirebaseDatabase.getInstance(firebaseApp); + } Boolean logLevel = loggingLevelSet.get(firebaseDatabase.getApp().getName()); if (enableLogging && (logLevel == null || !logLevel)) { @@ -535,8 +540,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param path * @return */ - private DatabaseReference getReferenceForAppPath(String appName, String path) { - return getDatabaseForApp(appName).getReference(path); + private DatabaseReference getReferenceForAppPath(String appName, String dbURL, String path) { + return getDatabaseForApp(appName, dbURL).getReference(path); } /** @@ -548,10 +553,11 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param modifiers * @return */ - private RNFirebaseDatabaseReference getInternalReferenceForApp(String appName, String key, String path, ReadableArray modifiers) { + private RNFirebaseDatabaseReference getInternalReferenceForApp(String appName, String dbURL, String key, String path, ReadableArray modifiers) { return new RNFirebaseDatabaseReference( getReactApplicationContext(), appName, + dbURL, key, path, modifiers @@ -565,7 +571,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param props * @return */ - private RNFirebaseDatabaseReference getCachedInternalReferenceForApp(String appName, ReadableMap props) { + private RNFirebaseDatabaseReference getCachedInternalReferenceForApp(String appName, String dbURL, ReadableMap props) { String key = props.getString("key"); String path = props.getString("path"); ReadableArray modifiers = props.getArray("modifiers"); @@ -573,7 +579,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { RNFirebaseDatabaseReference existingRef = references.get(key); if (existingRef == null) { - existingRef = getInternalReferenceForApp(appName, key, path, modifiers); + existingRef = getInternalReferenceForApp(appName, dbURL, key, path, modifiers); references.put(key, existingRef); } diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java index 9cf197de..1e8f68cb 100644 --- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java +++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java @@ -28,6 +28,7 @@ class RNFirebaseDatabaseReference { private String key; private Query query; private String appName; + private String dbURL; private ReactContext reactContext; private static final String TAG = "RNFirebaseDBReference"; private HashMap childEventListeners = new HashMap<>(); @@ -43,10 +44,11 @@ class RNFirebaseDatabaseReference { * @param refPath * @param modifiersArray */ - RNFirebaseDatabaseReference(ReactContext context, String app, String refKey, String refPath, ReadableArray modifiersArray) { + RNFirebaseDatabaseReference(ReactContext context, String app, String url, String refKey, String refPath, ReadableArray modifiersArray) { key = refKey; query = null; appName = app; + dbURL = url; reactContext = context; buildDatabaseQueryAtPathAndModifiers(refPath, modifiersArray); } @@ -346,8 +348,13 @@ class RNFirebaseDatabaseReference { * @return */ private void buildDatabaseQueryAtPathAndModifiers(String path, ReadableArray modifiers) { - FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); - FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance(firebaseApp); + FirebaseDatabase firebaseDatabase; + if(dbURL != null && dbURL.length() > 0) { + firebaseDatabase = FirebaseDatabase.getInstance(dbURL); + } else { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + firebaseDatabase= FirebaseDatabase.getInstance(firebaseApp); + } query = firebaseDatabase.getReference(path); List modifiersList = Utils.recursivelyDeconstructReadableArray(modifiers); diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseTransactionHandler.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseTransactionHandler.java index 19022e98..3c3f9c08 100644 --- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseTransactionHandler.java +++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseTransactionHandler.java @@ -21,6 +21,7 @@ import io.invertase.firebase.Utils; public class RNFirebaseTransactionHandler { private int transactionId; private String appName; + private String dbURL; private final ReentrantLock lock; private final Condition condition; private Map data; @@ -31,8 +32,9 @@ public class RNFirebaseTransactionHandler { boolean abort = false; boolean timeout = false; - RNFirebaseTransactionHandler(int id, String app) { + RNFirebaseTransactionHandler(int id, String app, String url) { appName = app; + dbURL = url; transactionId = id; lock = new ReentrantLock(); condition = lock.newCondition(); @@ -107,6 +109,7 @@ public class RNFirebaseTransactionHandler { // all events get distributed js side based on app name updatesMap.putString("appName", appName); + updatesMap.putString("dbURL", dbURL); if (!updatesData.hasChildren()) { Utils.mapPutValue("value", updatesData.getValue(), updatesMap); @@ -129,6 +132,7 @@ public class RNFirebaseTransactionHandler { resultMap.putInt("id", transactionId); resultMap.putString("appName", appName); + resultMap.putString("dbURL", dbURL); resultMap.putBoolean("timeout", timeout); resultMap.putBoolean("committed", committed); diff --git a/ios/RNFirebase/database/RNFirebaseDatabase.h b/ios/RNFirebase/database/RNFirebaseDatabase.h index e88d5b5a..86840a2d 100644 --- a/ios/RNFirebase/database/RNFirebaseDatabase.h +++ b/ios/RNFirebase/database/RNFirebaseDatabase.h @@ -17,6 +17,7 @@ + (void)handlePromise:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject databaseError:(NSError *)databaseError; + (FIRDatabase *)getDatabaseForApp:(NSString *)appDisplayName; ++ (FIRDatabase *)getDatabaseForApp:(NSString *)appDisplayName URL:(NSString *)url; + (NSDictionary *)getJSError:(NSError *)nativeError; diff --git a/ios/RNFirebase/database/RNFirebaseDatabase.m b/ios/RNFirebase/database/RNFirebaseDatabase.m index 9d6b2730..fac42b79 100644 --- a/ios/RNFirebase/database/RNFirebaseDatabase.m +++ b/ios/RNFirebase/database/RNFirebaseDatabase.m @@ -22,22 +22,26 @@ RCT_EXPORT_MODULE(); return self; } -RCT_EXPORT_METHOD(goOnline:(NSString *)appDisplayName) { - [[RNFirebaseDatabase getDatabaseForApp:appDisplayName] goOnline]; +RCT_EXPORT_METHOD(goOnline:(NSString *)appDisplayName + dbURL:(NSString *)dbURL) { + [[RNFirebaseDatabase getDatabaseForApp:appDisplayName URL:dbURL] goOnline]; } -RCT_EXPORT_METHOD(goOffline:(NSString *)appDisplayName) { - [[RNFirebaseDatabase getDatabaseForApp:appDisplayName] goOffline]; +RCT_EXPORT_METHOD(goOffline:(NSString *)appDisplayName + dbURL:(NSString *)dbURL) { + [[RNFirebaseDatabase getDatabaseForApp:appDisplayName URL:dbURL] goOffline]; } RCT_EXPORT_METHOD(setPersistence:(NSString *)appDisplayName + dbURL:(NSString *)dbURL state:(BOOL)state) { - [RNFirebaseDatabase getDatabaseForApp:appDisplayName].persistenceEnabled = state; + [RNFirebaseDatabase getDatabaseForApp:appDisplayName URL:dbURL].persistenceEnabled = state; } RCT_EXPORT_METHOD(setPersistenceCacheSizeBytes:(NSString *)appDisplayName + dbURL:(NSString *)dbURL size:(NSInteger *)size) { - [RNFirebaseDatabase getDatabaseForApp:appDisplayName].persistenceCacheSizeBytes = (NSUInteger)size; + [RNFirebaseDatabase getDatabaseForApp:appDisplayName URL:dbURL].persistenceCacheSizeBytes = (NSUInteger)size; } RCT_EXPORT_METHOD(enableLogging:(BOOL)enabled) { @@ -45,15 +49,17 @@ RCT_EXPORT_METHOD(enableLogging:(BOOL)enabled) { } RCT_EXPORT_METHOD(keepSynced:(NSString *)appDisplayName + dbURL:(NSString *)dbURL key:(NSString *)key path:(NSString *)path modifiers:(NSArray *)modifiers state:(BOOL)state) { - FIRDatabaseQuery *query = [self getInternalReferenceForApp:appDisplayName key:key path:path modifiers:modifiers].query; + FIRDatabaseQuery *query = [self getInternalReferenceForApp:appDisplayName dbURL:dbURL key:key path:path modifiers:modifiers].query; [query keepSynced:state]; } RCT_EXPORT_METHOD(transactionTryCommit:(NSString *)appDisplayName + dbURL:(NSString *)dbURL transactionId:(nonnull NSNumber *)transactionId updates:(NSDictionary *)updates) { __block NSMutableDictionary *transactionState; @@ -83,6 +89,7 @@ RCT_EXPORT_METHOD(transactionTryCommit:(NSString *)appDisplayName RCT_EXPORT_METHOD(transactionStart:(NSString *)appDisplayName + dbURL:(NSString *)dbURL path:(NSString *)path transactionId:(nonnull NSNumber *)transactionId applyLocally:(BOOL)applyLocally) { @@ -90,12 +97,12 @@ RCT_EXPORT_METHOD(transactionStart:(NSString *)appDisplayName NSMutableDictionary *transactionState = [NSMutableDictionary new]; dispatch_semaphore_t sema = dispatch_semaphore_create(0); transactionState[@"semaphore"] = sema; - FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path]; + FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName dbURL:dbURL path:path]; [ref runTransactionBlock:^FIRTransactionResult *_Nonnull (FIRMutableData *_Nonnull currentData) { dispatch_barrier_async(_transactionQueue, ^{ [_transactions setValue:transactionState forKey:[transactionId stringValue]]; - NSDictionary *updateMap = [self createTransactionUpdateMap:appDisplayName transactionId:transactionId updatesData:currentData]; + NSDictionary *updateMap = [self createTransactionUpdateMap:appDisplayName dbURL:dbURL transactionId:transactionId updatesData:currentData]; [RNFirebaseUtil sendJSEvent:self name:DATABASE_TRANSACTION_EVENT body:updateMap]; }); @@ -120,123 +127,134 @@ RCT_EXPORT_METHOD(transactionStart:(NSString *)appDisplayName return [FIRTransactionResult successWithValue:currentData]; } } andCompletionBlock:^(NSError *_Nullable databaseError, BOOL committed, FIRDataSnapshot *_Nullable snapshot) { - NSDictionary *resultMap = [self createTransactionResultMap:appDisplayName transactionId:transactionId error:databaseError committed:committed snapshot:snapshot]; + NSDictionary *resultMap = [self createTransactionResultMap:appDisplayName dbURL:dbURL transactionId:transactionId error:databaseError committed:committed snapshot:snapshot]; [RNFirebaseUtil sendJSEvent:self name:DATABASE_TRANSACTION_EVENT body:resultMap]; } withLocalEvents:applyLocally]; }); } RCT_EXPORT_METHOD(onDisconnectSet:(NSString *)appDisplayName + dbURL:(NSString *)dbURL path:(NSString *)path props:(NSDictionary *)props resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path]; + FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName dbURL:dbURL path:path]; [ref onDisconnectSetValue:props[@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; }]; } RCT_EXPORT_METHOD(onDisconnectUpdate:(NSString *)appDisplayName + dbURL:(NSString *)dbURL path:(NSString *)path props:(NSDictionary *)props resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path]; + FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName dbURL:dbURL path:path]; [ref onDisconnectUpdateChildValues:props withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; }]; } RCT_EXPORT_METHOD(onDisconnectRemove:(NSString *)appDisplayName + dbURL:(NSString *)dbURL path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path]; + FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName dbURL:dbURL path:path]; [ref onDisconnectRemoveValueWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; }]; } RCT_EXPORT_METHOD(onDisconnectCancel:(NSString *)appDisplayName + dbURL:(NSString *)dbURL path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path]; + FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName dbURL:dbURL path:path]; [ref cancelDisconnectOperationsWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; }]; } RCT_EXPORT_METHOD(set:(NSString *)appDisplayName + dbURL:(NSString *)dbURL path:(NSString *)path props:(NSDictionary *)props resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path]; + FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName dbURL:dbURL path:path]; [ref setValue:[props valueForKey:@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; }]; } RCT_EXPORT_METHOD(setPriority:(NSString *)appDisplayName + dbURL:(NSString *)dbURL path:(NSString *)path priority:(NSDictionary *)priority resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path]; + FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName dbURL:dbURL path:path]; [ref setPriority:[priority valueForKey:@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull ref) { [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; }]; } RCT_EXPORT_METHOD(setWithPriority:(NSString *)appDisplayName + dbURL:(NSString *)dbURL path:(NSString *)path data:(NSDictionary *)data priority:(NSDictionary *)priority resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path]; + FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName dbURL:dbURL path:path]; [ref setValue:[data valueForKey:@"value"] andPriority:[priority valueForKey:@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull ref) { [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; }]; } RCT_EXPORT_METHOD(update:(NSString *)appDisplayName + dbURL:(NSString *)dbURL path:(NSString *)path props:(NSDictionary *)props resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path]; + FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName dbURL:dbURL path:path]; [ref updateChildValues:props withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; }]; } RCT_EXPORT_METHOD(remove:(NSString *)appDisplayName + dbURL:(NSString *)dbURL path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path]; + FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName dbURL:dbURL path:path]; [ref removeValueWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; }]; } RCT_EXPORT_METHOD(once:(NSString *)appDisplayName + dbURL:(NSString *)dbURL key:(NSString *)key path:(NSString *)path modifiers:(NSArray *)modifiers eventName:(NSString *)eventName resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - RNFirebaseDatabaseReference *ref = [self getInternalReferenceForApp:appDisplayName key:key path:path modifiers:modifiers]; + RNFirebaseDatabaseReference *ref = [self getInternalReferenceForApp:appDisplayName dbURL:dbURL key:key path:path modifiers:modifiers]; [ref once:eventName resolver:resolve rejecter:reject]; } RCT_EXPORT_METHOD(on:(NSString *)appDisplayName + dbURL:(NSString *)dbURL props:(NSDictionary *)props) { - RNFirebaseDatabaseReference *ref = [self getCachedInternalReferenceForApp:appDisplayName props:props]; + RNFirebaseDatabaseReference *ref = [self getCachedInternalReferenceForApp:appDisplayName dbURL:dbURL props:props]; [ref on:props[@"eventType"] registration:props[@"registration"]]; } @@ -271,23 +289,31 @@ RCT_EXPORT_METHOD(off:(NSString *)key return [FIRDatabase databaseForApp:app]; } -- (FIRDatabaseReference *)getReferenceForAppPath:(NSString *)appDisplayName path:(NSString *)path { - return [[RNFirebaseDatabase getDatabaseForApp:appDisplayName] referenceWithPath:path]; ++ (FIRDatabase *)getDatabaseForApp:(NSString *)appDisplayName URL:(NSString *)url { + if (url == nil) { + return [self getDatabaseForApp:appDisplayName]; + } + FIRApp *app = [RNFirebaseUtil getApp:appDisplayName]; + return [FIRDatabase databaseForApp:app URL:url]; } -- (RNFirebaseDatabaseReference *)getInternalReferenceForApp:(NSString *)appDisplayName key:(NSString *)key path:(NSString *)path modifiers:(NSArray *)modifiers { - return [[RNFirebaseDatabaseReference alloc] initWithPathAndModifiers:self appDisplayName:appDisplayName key:key refPath:path modifiers:modifiers]; +- (FIRDatabaseReference *)getReferenceForAppPath:(NSString *)appDisplayName dbURL:(NSString *)dbURL path:(NSString *)path { + return [[RNFirebaseDatabase getDatabaseForApp:appDisplayName URL:dbURL] referenceWithPath:path]; } -- (RNFirebaseDatabaseReference *)getCachedInternalReferenceForApp:(NSString *)appDisplayName props:(NSDictionary *)props { +- (RNFirebaseDatabaseReference *)getInternalReferenceForApp:(NSString *)appDisplayName dbURL:(NSString *)dbURL key:(NSString *)key path:(NSString *)path modifiers:(NSArray *)modifiers { + return [[RNFirebaseDatabaseReference alloc] initWithPathAndModifiers:self appDisplayName:appDisplayName dbURL:dbURL key:key refPath:path modifiers:modifiers]; +} + +- (RNFirebaseDatabaseReference *)getCachedInternalReferenceForApp:(NSString *)appDisplayName dbURL:(NSString *)dbURL props:(NSDictionary *)props { NSString *key = props[@"key"]; NSString *path = props[@"path"]; - NSDictionary *modifiers = props[@"modifiers"]; + NSArray *modifiers = props[@"modifiers"]; RNFirebaseDatabaseReference *ref = _dbReferences[key]; if (ref == nil) { - ref = [[RNFirebaseDatabaseReference alloc] initWithPathAndModifiers:self appDisplayName:appDisplayName key:key refPath:path modifiers:modifiers]; + ref = [[RNFirebaseDatabaseReference alloc] initWithPathAndModifiers:self appDisplayName:appDisplayName dbURL:dbURL key:key refPath:path modifiers:modifiers]; _dbReferences[key] = ref; } return ref; @@ -375,20 +401,22 @@ RCT_EXPORT_METHOD(off:(NSString *)key return errorMap; } -- (NSDictionary *)createTransactionUpdateMap:(NSString *)appDisplayName transactionId:(NSNumber *)transactionId updatesData:(FIRMutableData *)updatesData { +- (NSDictionary *)createTransactionUpdateMap:(NSString *)appDisplayName dbURL:(NSString *)dbURL transactionId:(NSNumber *)transactionId updatesData:(FIRMutableData *)updatesData { NSMutableDictionary *updatesMap = [[NSMutableDictionary alloc] init]; [updatesMap setValue:transactionId forKey:@"id"]; [updatesMap setValue:@"update" forKey:@"type"]; [updatesMap setValue:appDisplayName forKey:@"appName"]; + [updatesMap setValue:dbURL forKey:@"dbURL"]; [updatesMap setValue:updatesData.value forKey:@"value"]; return updatesMap; } -- (NSDictionary *)createTransactionResultMap:(NSString *)appDisplayName transactionId:(NSNumber *)transactionId error:(NSError *)error committed:(BOOL)committed snapshot:(FIRDataSnapshot *)snapshot { +- (NSDictionary *)createTransactionResultMap:(NSString *)appDisplayName dbURL:(NSString *)dbURL transactionId:(NSNumber *)transactionId error:(NSError *)error committed:(BOOL)committed snapshot:(FIRDataSnapshot *)snapshot { NSMutableDictionary *resultMap = [[NSMutableDictionary alloc] init]; [resultMap setValue:transactionId forKey:@"id"]; [resultMap setValue:appDisplayName forKey:@"appName"]; + [resultMap setValue:dbURL forKey:@"dbURL"]; // TODO: no timeout on iOS [resultMap setValue:@(committed) forKey:@"committed"]; // TODO: no interrupted on iOS diff --git a/ios/RNFirebase/database/RNFirebaseDatabaseReference.h b/ios/RNFirebase/database/RNFirebaseDatabaseReference.h index fb64295c..9bf1d18e 100644 --- a/ios/RNFirebase/database/RNFirebaseDatabaseReference.h +++ b/ios/RNFirebase/database/RNFirebaseDatabaseReference.h @@ -13,11 +13,12 @@ @property RCTEventEmitter *emitter; @property FIRDatabaseQuery *query; @property NSString *appDisplayName; +@property NSString *dbURL; @property NSString *key; @property NSString *path; @property NSMutableDictionary *listeners; -- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter appDisplayName:(NSString *)appDisplayName key:(NSString *)key refPath:(NSString *)refPath modifiers:(NSArray *)modifiers; +- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter appDisplayName:(NSString *)appDisplayName dbURL:(NSString *)dbURL key:(NSString *)key refPath:(NSString *)refPath modifiers:(NSArray *)modifiers; - (void)on:(NSString *) eventName registration:(NSDictionary *) registration; - (void)once:(NSString *) eventType resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject; - (void)removeEventListener:(NSString *)eventRegistrationKey; diff --git a/ios/RNFirebase/database/RNFirebaseDatabaseReference.m b/ios/RNFirebase/database/RNFirebaseDatabaseReference.m index 5a4a8a4b..782ec096 100644 --- a/ios/RNFirebase/database/RNFirebaseDatabaseReference.m +++ b/ios/RNFirebase/database/RNFirebaseDatabaseReference.m @@ -6,6 +6,7 @@ - (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter appDisplayName:(NSString *)appDisplayName + dbURL:(NSString *)dbURL key:(NSString *)key refPath:(NSString *)refPath modifiers:(NSArray *)modifiers { @@ -13,6 +14,7 @@ if (self) { _emitter = emitter; _appDisplayName = appDisplayName; + _dbURL = dbURL; _key = key; _path = refPath; _listeners = [[NSMutableDictionary alloc] init]; @@ -123,7 +125,7 @@ - (FIRDatabaseQuery *)buildQueryAtPathWithModifiers:(NSString *)path modifiers:(NSArray *)modifiers { - FIRDatabase *firebaseDatabase = [RNFirebaseDatabase getDatabaseForApp:_appDisplayName]; + FIRDatabase *firebaseDatabase = [RNFirebaseDatabase getDatabaseForApp:_appDisplayName URL:_dbURL]; FIRDatabaseQuery *query = [[firebaseDatabase reference] child:path]; for (NSDictionary *modifier in modifiers) { diff --git a/lib/modules/admob/index.js b/lib/modules/admob/index.js index 795099a3..063e42ea 100644 --- a/lib/modules/admob/index.js +++ b/lib/modules/admob/index.js @@ -41,6 +41,7 @@ export default class AdMob extends ModuleBase { events: NATIVE_EVENTS, moduleName: MODULE_NAME, multiApp: false, + hasShards: false, namespace: NAMESPACE, }); diff --git a/lib/modules/analytics/index.js b/lib/modules/analytics/index.js index 3cba2d47..7a0cc4bb 100644 --- a/lib/modules/analytics/index.js +++ b/lib/modules/analytics/index.js @@ -34,6 +34,7 @@ export default class Analytics extends ModuleBase { super(app, { moduleName: MODULE_NAME, multiApp: false, + hasShards: false, namespace: NAMESPACE, }); } diff --git a/lib/modules/auth/index.js b/lib/modules/auth/index.js index 4b2863e8..b4b697af 100644 --- a/lib/modules/auth/index.js +++ b/lib/modules/auth/index.js @@ -53,6 +53,7 @@ export default class Auth extends ModuleBase { events: NATIVE_EVENTS, moduleName: MODULE_NAME, multiApp: true, + hasShards: false, namespace: NAMESPACE, }); this._user = null; diff --git a/lib/modules/config/index.js b/lib/modules/config/index.js index 777ddecc..05511262 100644 --- a/lib/modules/config/index.js +++ b/lib/modules/config/index.js @@ -32,6 +32,7 @@ export default class RemoteConfig extends ModuleBase { super(app, { moduleName: MODULE_NAME, multiApp: false, + hasShards: false, namespace: NAMESPACE, }); this._developerModeEnabled = false; diff --git a/lib/modules/crash/index.js b/lib/modules/crash/index.js index e18ec36b..2d9a0a8f 100644 --- a/lib/modules/crash/index.js +++ b/lib/modules/crash/index.js @@ -16,6 +16,7 @@ export default class Crash extends ModuleBase { super(app, { moduleName: MODULE_NAME, multiApp: false, + hasShards: false, namespace: NAMESPACE, }); } diff --git a/lib/modules/database/Reference.js b/lib/modules/database/Reference.js index 67d2c9c5..ce54e645 100644 --- a/lib/modules/database/Reference.js +++ b/lib/modules/database/Reference.js @@ -497,7 +497,7 @@ export default class Reference extends ReferenceBase { * @returns {string} */ toString(): string { - return `${this._database.app.options.databaseURL}/${this.path}`; + return `${this._database.databaseUrl}/${this.path}`; } /** @@ -606,7 +606,7 @@ export default class Reference extends ReferenceBase { * @return {string} */ _getRegistrationKey(eventType: string): string { - return `$${this._database.app.name}$/${ + return `$${this._database.databaseUrl}$/${ this.path }$${this._query.queryIdentifier()}$${listeners}$${eventType}`; } @@ -618,8 +618,8 @@ export default class Reference extends ReferenceBase { * @return {string} * @private */ - _getRefKey(): string { - return `$${this._database.app.name}$/${ + _getRefKey() { + return `$${this._database.databaseUrl}$/${ this.path }$${this._query.queryIdentifier()}`; } @@ -758,6 +758,7 @@ export default class Reference extends ReferenceBase { path: this.path, key: this._getRefKey(), appName: this._database.app.name, + dbURL: this._database.databaseUrl, eventRegistrationKey, }; @@ -776,6 +777,7 @@ export default class Reference extends ReferenceBase { path: this.path, key: this._getRefKey(), appName: this._database.app.name, + dbURL: this._database.databaseUrl, eventType: `${eventType}$cancelled`, eventRegistrationKey: registrationCancellationKey, listener: _context diff --git a/lib/modules/database/index.js b/lib/modules/database/index.js index 4967e0e8..66dc05fc 100644 --- a/lib/modules/database/index.js +++ b/lib/modules/database/index.js @@ -10,6 +10,7 @@ import ModuleBase from '../../utils/ModuleBase'; import { getNativeModule } from '../../utils/native'; import type App from '../core/app'; +import firebase from '../core/firebase'; const NATIVE_EVENTS = [ 'database_transaction_event', @@ -26,14 +27,32 @@ export default class Database extends ModuleBase { _offsetRef: Reference; _serverTimeOffset: number; _transactionHandler: TransactionHandler; + _serviceUrl: string; - constructor(app: App, options: Object = {}) { - super(app, { - events: NATIVE_EVENTS, - moduleName: MODULE_NAME, - multiApp: true, - namespace: NAMESPACE, - }); + constructor(appOrUrl: App | string, options: Object = {}) { + let app; + let serviceUrl; + if (typeof appOrUrl === 'string') { + app = firebase.app(); + serviceUrl = appOrUrl; + } else { + app = appOrUrl; + serviceUrl = app.options.databaseURL; + } + + super( + app, + { + events: NATIVE_EVENTS, + moduleName: MODULE_NAME, + multiApp: true, + hasShards: true, + namespace: NAMESPACE, + }, + serviceUrl + ); + + this._serviceUrl = serviceUrl; this._transactionHandler = new TransactionHandler(this); if (options.persistence) { @@ -83,6 +102,14 @@ export default class Database extends ModuleBase { ref(path: string): Reference { return new Reference(this, path); } + + /** + * Returns the database url + * @returns {string} + */ + get databaseUrl(): string { + return this._serviceUrl; + } } export const statics = { diff --git a/lib/modules/fabric/crashlytics/index.js b/lib/modules/fabric/crashlytics/index.js index 6b8a4484..7e797774 100644 --- a/lib/modules/fabric/crashlytics/index.js +++ b/lib/modules/fabric/crashlytics/index.js @@ -15,6 +15,7 @@ export default class Crashlytics extends ModuleBase { super(app, { moduleName: MODULE_NAME, multiApp: false, + hasShards: false, namespace: NAMESPACE, }); } diff --git a/lib/modules/firestore/index.js b/lib/modules/firestore/index.js index 35ee7047..e8047894 100644 --- a/lib/modules/firestore/index.js +++ b/lib/modules/firestore/index.js @@ -58,6 +58,7 @@ export default class Firestore extends ModuleBase { events: NATIVE_EVENTS, moduleName: MODULE_NAME, multiApp: true, + hasShards: false, namespace: NAMESPACE, }); diff --git a/lib/modules/links/index.js b/lib/modules/links/index.js index 28c31879..95908922 100644 --- a/lib/modules/links/index.js +++ b/lib/modules/links/index.js @@ -80,6 +80,7 @@ export default class Links extends ModuleBase { events: NATIVE_EVENTS, moduleName: MODULE_NAME, multiApp: false, + hasShards: false, namespace: NAMESPACE, }); } diff --git a/lib/modules/messaging/index.js b/lib/modules/messaging/index.js index 9eaf649f..4d7fc40d 100644 --- a/lib/modules/messaging/index.js +++ b/lib/modules/messaging/index.js @@ -42,6 +42,7 @@ export default class Messaging extends ModuleBase { events: NATIVE_EVENTS, moduleName: MODULE_NAME, multiApp: false, + hasShards: false, namespace: NAMESPACE, }); diff --git a/lib/modules/perf/index.js b/lib/modules/perf/index.js index e394d370..c22ed35e 100644 --- a/lib/modules/perf/index.js +++ b/lib/modules/perf/index.js @@ -16,6 +16,7 @@ export default class PerformanceMonitoring extends ModuleBase { super(app, { moduleName: MODULE_NAME, multiApp: false, + hasShards: false, namespace: NAMESPACE, }); } diff --git a/lib/modules/storage/index.js b/lib/modules/storage/index.js index 3803feb9..457de361 100644 --- a/lib/modules/storage/index.js +++ b/lib/modules/storage/index.js @@ -30,6 +30,7 @@ export default class Storage extends ModuleBase { events: NATIVE_EVENTS, moduleName: MODULE_NAME, multiApp: true, + hasShards: false, namespace: NAMESPACE, }); diff --git a/lib/modules/utils/index.js b/lib/modules/utils/index.js index 7215f2b1..ce48a2ad 100644 --- a/lib/modules/utils/index.js +++ b/lib/modules/utils/index.js @@ -23,6 +23,7 @@ export default class RNFirebaseUtils extends ModuleBase { super(app, { moduleName: MODULE_NAME, multiApp: false, + hasShards: false, namespace: NAMESPACE, }); } diff --git a/lib/types/index.js b/lib/types/index.js index f48b3a5c..87d95701 100644 --- a/lib/types/index.js +++ b/lib/types/index.js @@ -48,6 +48,7 @@ export type FirebaseModuleConfig = { events?: string[], moduleName: FirebaseModuleName, multiApp: boolean, + hasShards: boolean, namespace: FirebaseNamespace, }; diff --git a/lib/utils/ModuleBase.js b/lib/utils/ModuleBase.js index 83dd5f48..ffa78088 100644 --- a/lib/utils/ModuleBase.js +++ b/lib/utils/ModuleBase.js @@ -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', '')}` diff --git a/lib/utils/apps.js b/lib/utils/apps.js index 75f7778a..57ac16ea 100644 --- a/lib/utils/apps.js +++ b/lib/utils/apps.js @@ -49,9 +49,16 @@ export default { namespace: FirebaseNamespace, InstanceClass: Class ): () => 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 { - 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, { diff --git a/lib/utils/internals.js b/lib/utils/internals.js index de46d40a..fc656c04 100644 --- a/lib/utils/internals.js +++ b/lib/utils/internals.js @@ -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} */ diff --git a/lib/utils/native.js b/lib/utils/native.js index 248130c7..1b8ddd66 100644 --- a/lib/utils/native.js +++ b/lib/utils/native.js @@ -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 +): 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; } From a9470e78c5b1a25bb1c51bcd5d26ef029c36a4ff Mon Sep 17 00:00:00 2001 From: Akshet Pandey Date: Wed, 21 Mar 2018 13:08:46 -0700 Subject: [PATCH 2/2] CR Changes --- .../firebase/database/RNFirebaseDatabase.java | 26 ++++++++++++++----- .../database/RNFirebaseDatabaseReference.java | 9 +------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java index e628fc05..c9e5a41a 100644 --- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java +++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java @@ -54,7 +54,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { */ @ReactMethod public void goOnline(String appName, String dbURL) { - getDatabaseForApp(appName, dbURL).goOnline(); + getDatabaseForAppAndSetLogging(appName, dbURL).goOnline(); } /** @@ -62,7 +62,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { */ @ReactMethod public void goOffline(String appName, String dbURL) { - getDatabaseForApp(appName, dbURL).goOffline(); + getDatabaseForAppAndSetLogging(appName, dbURL).goOffline(); } /** @@ -71,7 +71,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { */ @ReactMethod public void setPersistence(String appName, String dbURL, Boolean state) { - getDatabaseForApp(appName, dbURL).setPersistenceEnabled(state); + getDatabaseForAppAndSetLogging(appName, dbURL).setPersistenceEnabled(state); } /** @@ -80,7 +80,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { */ @ReactMethod public void setPersistenceCacheSizeBytes(String appName, String dbURL, int size) { - getDatabaseForApp(appName, dbURL).setPersistenceCacheSizeBytes((long) size); + getDatabaseForAppAndSetLogging(appName, dbURL).setPersistenceCacheSizeBytes((long) size); } @@ -494,9 +494,10 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * Get a database instance for a specific firebase app instance * * @param appName + * @param dbURL * @return */ - private FirebaseDatabase getDatabaseForApp(String appName, String dbURL) { + public static FirebaseDatabase getDatabaseForApp(String appName, String dbURL) { FirebaseDatabase firebaseDatabase; if(dbURL != null && dbURL.length() > 0) { firebaseDatabase = FirebaseDatabase.getInstance(dbURL); @@ -504,6 +505,19 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); firebaseDatabase = FirebaseDatabase.getInstance(firebaseApp); } + + return firebaseDatabase; + } + + /** + * Get a database instance for a specific firebase app instance and enable/disable logging + * + * @param appName + * @param dbURL + * @return + */ + private FirebaseDatabase getDatabaseForAppAndSetLogging(String appName, String dbURL) { + FirebaseDatabase firebaseDatabase = RNFirebaseDatabase.getDatabaseForApp(appName, dbURL); Boolean logLevel = loggingLevelSet.get(firebaseDatabase.getApp().getName()); if (enableLogging && (logLevel == null || !logLevel)) { @@ -541,7 +555,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @return */ private DatabaseReference getReferenceForAppPath(String appName, String dbURL, String path) { - return getDatabaseForApp(appName, dbURL).getReference(path); + return getDatabaseForAppAndSetLogging(appName, dbURL).getReference(path); } /** diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java index 1e8f68cb..bbf51038 100644 --- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java +++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java @@ -348,14 +348,7 @@ class RNFirebaseDatabaseReference { * @return */ private void buildDatabaseQueryAtPathAndModifiers(String path, ReadableArray modifiers) { - FirebaseDatabase firebaseDatabase; - if(dbURL != null && dbURL.length() > 0) { - firebaseDatabase = FirebaseDatabase.getInstance(dbURL); - } else { - FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); - firebaseDatabase= FirebaseDatabase.getInstance(firebaseApp); - } - + FirebaseDatabase firebaseDatabase = RNFirebaseDatabase.getDatabaseForApp(appName, dbURL); query = firebaseDatabase.getReference(path); List modifiersList = Utils.recursivelyDeconstructReadableArray(modifiers);