[database][ios][wip] Replicate Android changes on iOS
This commit is contained in:
parent
3504715a53
commit
a785b050db
|
@ -74,6 +74,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
|
|||
*/
|
||||
@ReactMethod
|
||||
public void keepSynced(String appName, String path, Boolean state) {
|
||||
// TODO: Needs to take into account modifiers as well as just the path
|
||||
getReferenceForAppPath(appName, path).keepSynced(state);
|
||||
}
|
||||
|
||||
|
@ -579,7 +580,7 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
|
|||
break;
|
||||
default:
|
||||
code = getCodeWithService(service, "unknown");
|
||||
message = getMessageWithService("An unknown error occurred", service, code);
|
||||
message = getMessageWithService("An unknown error occurred.", service, code);
|
||||
}
|
||||
|
||||
errorMap.putString("code", code);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
8300A7AE1F31E143001B16AB /* RNFirebaseDatabaseReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 8300A7AD1F31E143001B16AB /* RNFirebaseDatabaseReference.m */; };
|
||||
839D916C1EF3E20B0077C7C8 /* RNFirebaseAdMob.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D914F1EF3E20A0077C7C8 /* RNFirebaseAdMob.m */; };
|
||||
839D916D1EF3E20B0077C7C8 /* RNFirebaseAdMobInterstitial.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D91511EF3E20A0077C7C8 /* RNFirebaseAdMobInterstitial.m */; };
|
||||
839D916E1EF3E20B0077C7C8 /* RNFirebaseAdMobRewardedVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D91531EF3E20A0077C7C8 /* RNFirebaseAdMobRewardedVideo.m */; };
|
||||
|
@ -35,6 +36,8 @@
|
|||
|
||||
/* Begin PBXFileReference section */
|
||||
134814201AA4EA6300B7C361 /* libRNFirebase.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFirebase.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8300A7AC1F31E143001B16AB /* RNFirebaseDatabaseReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseDatabaseReference.h; sourceTree = "<group>"; };
|
||||
8300A7AD1F31E143001B16AB /* RNFirebaseDatabaseReference.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseDatabaseReference.m; sourceTree = "<group>"; };
|
||||
839D914E1EF3E20A0077C7C8 /* RNFirebaseAdMob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseAdMob.h; sourceTree = "<group>"; };
|
||||
839D914F1EF3E20A0077C7C8 /* RNFirebaseAdMob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseAdMob.m; sourceTree = "<group>"; };
|
||||
839D91501EF3E20A0077C7C8 /* RNFirebaseAdMobInterstitial.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseAdMobInterstitial.h; sourceTree = "<group>"; };
|
||||
|
@ -157,6 +160,8 @@
|
|||
839D91601EF3E20A0077C7C8 /* database */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8300A7AC1F31E143001B16AB /* RNFirebaseDatabaseReference.h */,
|
||||
8300A7AD1F31E143001B16AB /* RNFirebaseDatabaseReference.m */,
|
||||
839D91611EF3E20A0077C7C8 /* RNFirebaseDatabase.h */,
|
||||
839D91621EF3E20A0077C7C8 /* RNFirebaseDatabase.m */,
|
||||
);
|
||||
|
@ -262,6 +267,7 @@
|
|||
839D91741EF3E20B0077C7C8 /* RNFirebaseMessaging.m in Sources */,
|
||||
839D91751EF3E20B0077C7C8 /* RNFirebasePerformance.m in Sources */,
|
||||
839D916D1EF3E20B0077C7C8 /* RNFirebaseAdMobInterstitial.m in Sources */,
|
||||
8300A7AE1F31E143001B16AB /* RNFirebaseDatabaseReference.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -4,12 +4,19 @@
|
|||
#import <React/RCTBridgeModule.h>
|
||||
|
||||
#if __has_include(<FirebaseDatabase/FIRDatabase.h>)
|
||||
#import "Firebase.h"
|
||||
#import <React/RCTEventEmitter.h>
|
||||
|
||||
@interface RNFirebaseDatabase : RCTEventEmitter<RCTBridgeModule> {}
|
||||
@property NSMutableDictionary *dbReferences;
|
||||
@property NSMutableDictionary *transactions;
|
||||
@property dispatch_queue_t transactionQueue;
|
||||
|
||||
+ (void)handlePromise:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock) reject databaseError:(NSError *)databaseError;
|
||||
+ (FIRDatabase *)getDatabaseForApp:(NSString*)appName;
|
||||
+ (NSString *) getMessageWithService:(NSString *) message service:(NSString *) service fullCode:(NSString *) fullCode;
|
||||
+ (NSString *) getCodeWithService:(NSString *) service code:(NSString *) code;
|
||||
|
||||
@end
|
||||
|
||||
#else
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#if __has_include(<FirebaseDatabase/FIRDatabase.h>)
|
||||
#import "RNFirebaseDatabaseReference.h"
|
||||
#import "RNFirebaseEvents.h"
|
||||
#import "Firebase.h"
|
||||
|
||||
@implementation RNFirebaseDatabase
|
||||
RCT_EXPORT_MODULE();
|
||||
|
@ -18,206 +17,374 @@ RCT_EXPORT_MODULE();
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)sendTransactionEvent:(NSString *)type body:(id)body {
|
||||
@try {
|
||||
[self sendEventWithName:type body:body];
|
||||
} @catch (NSException *err) {
|
||||
NSLog(@"An error occurred in sendJSEvent: %@", [err debugDescription]);
|
||||
NSLog(@"Tried to send: %@ with %@", type, body);
|
||||
}
|
||||
RCT_EXPORT_METHOD(goOnline:(NSString *) appName) {
|
||||
[[RNFirebaseDatabase getDatabaseForApp:appName] goOnline];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(startTransaction:
|
||||
(NSString *) path
|
||||
identifier:
|
||||
(NSString *) identifier
|
||||
applyLocally:
|
||||
(BOOL) applyLocally) {
|
||||
RCT_EXPORT_METHOD(goOffline:(NSString *) appName) {
|
||||
[[RNFirebaseDatabase getDatabaseForApp:appName] goOffline];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(setPersistence:(NSString *) appName
|
||||
state:(BOOL) state) {
|
||||
[RNFirebaseDatabase getDatabaseForApp:appName].persistenceEnabled = state;
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(keepSynced:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
state:(BOOL) state) {
|
||||
[[self getReferenceForAppPath:appName path:path] keepSynced:state];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(transactionTryCommit:(NSString *) appName
|
||||
transactionId:(nonnull NSNumber *) transactionId
|
||||
updates:(NSDictionary *) updates) {
|
||||
__block NSMutableDictionary *transactionState;
|
||||
|
||||
dispatch_sync(_transactionQueue, ^{
|
||||
transactionState = _transactions[transactionId];
|
||||
});
|
||||
|
||||
if (!transactionState) {
|
||||
NSLog(@"tryCommitTransaction for unknown ID %@", transactionId);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_semaphore_t sema = [transactionState valueForKey:@"semaphore"];
|
||||
|
||||
BOOL abort = [[updates valueForKey:@"abort"] boolValue];
|
||||
|
||||
if (abort) {
|
||||
[transactionState setValue:@true forKey:@"abort"];
|
||||
} else {
|
||||
id newValue = [updates valueForKey:@"value"];
|
||||
[transactionState setValue:newValue forKey:@"value"];
|
||||
}
|
||||
|
||||
dispatch_semaphore_signal(sema);
|
||||
}
|
||||
|
||||
|
||||
RCT_EXPORT_METHOD(transactionStart:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
transactionId:(nonnull NSNumber *) transactionId
|
||||
applyLocally:(BOOL) applyLocally) {
|
||||
dispatch_async(_transactionQueue, ^{
|
||||
NSMutableDictionary *transactionState = [NSMutableDictionary new];
|
||||
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
transactionState[@"semaphore"] = sema;
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
|
||||
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path];
|
||||
|
||||
[ref runTransactionBlock:^FIRTransactionResult * _Nonnull(FIRMutableData *
|
||||
_Nonnull currentData) {
|
||||
dispatch_barrier_async(_transactionQueue, ^{
|
||||
[_transactions setValue:transactionState forKey:identifier];
|
||||
[self sendTransactionEvent:DATABASE_TRANSACTION_EVENT body:@{@"id": identifier, @"type": @"update", @"value": currentData.value}];
|
||||
});
|
||||
|
||||
// wait for the js event handler to call tryCommitTransaction
|
||||
// this wait occurs on the Firebase Worker Queue
|
||||
// so if the tryCommitTransaction fails to signal the semaphore
|
||||
// no further blocks will be executed by Firebase until the timeout expires
|
||||
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC);
|
||||
BOOL timedout = dispatch_semaphore_wait(sema, delayTime) != 0;
|
||||
|
||||
BOOL abort = [transactionState valueForKey:@"abort"] || timedout;
|
||||
id value = [transactionState valueForKey:@"value"];
|
||||
|
||||
dispatch_barrier_async(_transactionQueue, ^{
|
||||
[_transactions removeObjectForKey:identifier];
|
||||
});
|
||||
|
||||
if (abort) {
|
||||
return [FIRTransactionResult abort];
|
||||
} else {
|
||||
currentData.value = value;
|
||||
return [FIRTransactionResult successWithValue:currentData];
|
||||
}
|
||||
}
|
||||
andCompletionBlock:
|
||||
^(NSError *_Nullable databaseError, BOOL committed, FIRDataSnapshot *_Nullable snapshot) {
|
||||
if (databaseError != nil) {
|
||||
[self sendTransactionEvent:DATABASE_TRANSACTION_EVENT body:@{@"id": identifier, @"type": @"error", @"code": @([databaseError code]), @"message": [databaseError description]}];
|
||||
_Nonnull currentData) {
|
||||
dispatch_barrier_async(_transactionQueue, ^{
|
||||
[_transactions setValue:transactionState forKey:transactionId];
|
||||
NSDictionary *updateMap = [self createTransactionUpdateMap:appName transactionId:transactionId updatesData:currentData];
|
||||
[self sendEventWithName:DATABASE_TRANSACTION_EVENT body:updateMap];
|
||||
});
|
||||
|
||||
// wait for the js event handler to call tryCommitTransaction
|
||||
// this wait occurs on the Firebase Worker Queue
|
||||
// so if the tryCommitTransaction fails to signal the semaphore
|
||||
// no further blocks will be executed by Firebase until the timeout expires
|
||||
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC);
|
||||
BOOL timedout = dispatch_semaphore_wait(sema, delayTime) != 0;
|
||||
|
||||
BOOL abort = [transactionState valueForKey:@"abort"] || timedout;
|
||||
id value = [transactionState valueForKey:@"value"];
|
||||
|
||||
dispatch_barrier_async(_transactionQueue, ^{
|
||||
[_transactions removeObjectForKey:transactionId];
|
||||
});
|
||||
|
||||
if (abort) {
|
||||
return [FIRTransactionResult abort];
|
||||
} else {
|
||||
[self sendTransactionEvent:DATABASE_TRANSACTION_EVENT body:@{@"id": identifier, @"type": @"complete", @"committed": @(committed), @"snapshot": [RNFirebaseDatabaseReference snapshotToDict:snapshot],}];
|
||||
currentData.value = value;
|
||||
return [FIRTransactionResult successWithValue:currentData];
|
||||
}
|
||||
}
|
||||
withLocalEvents:
|
||||
applyLocally];
|
||||
andCompletionBlock:
|
||||
^(NSError *_Nullable databaseError, BOOL committed, FIRDataSnapshot *_Nullable snapshot) {
|
||||
NSDictionary *resultMap = [self createTransactionResultMap:appName transactionId:transactionId error:databaseError committed:committed snapshot:snapshot];
|
||||
[self sendEventWithName:DATABASE_TRANSACTION_EVENT body:resultMap];
|
||||
}
|
||||
withLocalEvents:
|
||||
applyLocally];
|
||||
});
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(tryCommitTransaction:
|
||||
(NSString *) identifier
|
||||
withData:
|
||||
(NSDictionary *) data) {
|
||||
__block NSMutableDictionary *transactionState;
|
||||
|
||||
dispatch_sync(_transactionQueue, ^{
|
||||
transactionState = _transactions[identifier];
|
||||
});
|
||||
|
||||
if (!transactionState) {
|
||||
NSLog(@"tryCommitTransaction for unknown ID %@", identifier);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_semaphore_t sema = [transactionState valueForKey:@"semaphore"];
|
||||
|
||||
BOOL abort = [[data valueForKey:@"abort"] boolValue];
|
||||
|
||||
if (abort) {
|
||||
[transactionState setValue:@true forKey:@"abort"];
|
||||
} else {
|
||||
id newValue = [data valueForKey:@"value"];
|
||||
[transactionState setValue:newValue forKey:@"value"];
|
||||
}
|
||||
|
||||
dispatch_semaphore_signal(sema);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(enablePersistence:
|
||||
(BOOL) enable
|
||||
callback:
|
||||
(RCTResponseSenderBlock) callback) {
|
||||
|
||||
BOOL isEnabled = [FIRDatabase database].persistenceEnabled;
|
||||
if (isEnabled != enable) {
|
||||
@try {
|
||||
[FIRDatabase database].persistenceEnabled = enable;
|
||||
} @catch (NSException *exception) {
|
||||
// do nothing - for RN packager reloads
|
||||
}
|
||||
}
|
||||
callback(@[[NSNull null], @{@"result": @"success"}]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(keepSynced:
|
||||
(NSString *) path
|
||||
withEnable:
|
||||
(BOOL) enable
|
||||
callback:
|
||||
(RCTResponseSenderBlock) callback) {
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
[ref keepSynced:enable];
|
||||
callback(@[[NSNull null], @{@"status": @"success", @"path": path}]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(set:
|
||||
(NSString *) path
|
||||
data:
|
||||
(NSDictionary *) data
|
||||
callback:
|
||||
(RCTResponseSenderBlock) callback) {
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
[ref setValue:[data valueForKey:@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
|
||||
[self handleCallback:@"set" callback:callback databaseError:error];
|
||||
RCT_EXPORT_METHOD(onDisconnectSet:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
props:(NSDictionary *) props
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path];
|
||||
[ref onDisconnectSetValue:props[@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
|
||||
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(priority:(NSString *) path
|
||||
priorityData:(NSDictionary *) priorityData
|
||||
callback:(RCTResponseSenderBlock) callback) {
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
[ref setPriority:[priorityData valueForKey:@"value"] withCompletionBlock:^(NSError * _Nullable error, FIRDatabaseReference * _Nonnull ref) {
|
||||
[self handleCallback:@"priority" callback:callback databaseError:error];
|
||||
RCT_EXPORT_METHOD(onDisconnectUpdate:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
props:(NSDictionary *) props
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path];
|
||||
[ref onDisconnectUpdateChildValues:props withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
|
||||
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(withPriority:(NSString *) path
|
||||
data:(NSDictionary *) data
|
||||
priorityData:(NSDictionary *) priorityData
|
||||
callback:(RCTResponseSenderBlock) callback) {
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
[ref setValue:[data valueForKey:@"value"] andPriority:[priorityData valueForKey:@"value"] withCompletionBlock:^(NSError * _Nullable error, FIRDatabaseReference * _Nonnull ref) {
|
||||
[self handleCallback:@"withPriority" callback:callback databaseError:error];
|
||||
RCT_EXPORT_METHOD(onDisconnectRemove:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path];
|
||||
[ref onDisconnectRemoveValueWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
|
||||
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(update:
|
||||
(NSString *) path
|
||||
value:
|
||||
(NSDictionary *) value
|
||||
callback:
|
||||
(RCTResponseSenderBlock) callback) {
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
[ref updateChildValues:value withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
|
||||
[self handleCallback:@"update" callback:callback databaseError:error];
|
||||
RCT_EXPORT_METHOD(onDisconnectCancel:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path];
|
||||
[ref cancelDisconnectOperationsWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
|
||||
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(remove:
|
||||
(NSString *) path
|
||||
callback:
|
||||
(RCTResponseSenderBlock) callback) {
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
RCT_EXPORT_METHOD(set:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
props:(NSDictionary *) props
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName 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 *) appName
|
||||
path:(NSString *) path
|
||||
priority:(NSDictionary *) priority
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName 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 *) appName
|
||||
path:(NSString *) path
|
||||
data:(NSDictionary *) data
|
||||
priority:(NSDictionary *) priority
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName 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 *) appName
|
||||
path:(NSString *) path
|
||||
props:(NSDictionary *) props
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path];
|
||||
[ref updateChildValues:props withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
|
||||
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(remove:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path];
|
||||
[ref removeValueWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
|
||||
[self handleCallback:@"remove" callback:callback databaseError:error];
|
||||
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(push:
|
||||
(NSString *) path
|
||||
data:
|
||||
(NSDictionary *) data
|
||||
callback:
|
||||
(RCTResponseSenderBlock) callback) {
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
FIRDatabaseReference *newRef = [ref childByAutoId];
|
||||
RCT_EXPORT_METHOD(once:(NSString *) appName
|
||||
refId:(nonnull NSNumber *) refId
|
||||
path:(NSString *) path
|
||||
modifiers:(NSArray *) modifiers
|
||||
eventName:(NSString *) eventName
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RNFirebaseDatabaseReference *ref = [self getInternalReferenceForApp:appName refId:refId path:path modifiers:modifiers keep:false];
|
||||
[ref addSingleEventHandler:eventName resolver:resolve rejecter:reject];
|
||||
}
|
||||
|
||||
NSURL *url = [NSURL URLWithString:newRef.URL];
|
||||
NSString *newPath = [url path];
|
||||
|
||||
if ([data count] > 0) {
|
||||
[newRef setValue:[data valueForKey:@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
|
||||
if (error != nil) {
|
||||
// Error handling
|
||||
NSDictionary *evt = @{@"code": @([error code]), @"details": [error debugDescription], @"message": [error localizedDescription], @"description": [error description]};
|
||||
|
||||
callback(@[evt]);
|
||||
} else {
|
||||
callback(@[[NSNull null], @{@"status": @"success", @"ref": newPath}]);
|
||||
}
|
||||
}];
|
||||
/*
|
||||
* INTERNALS/UTILS
|
||||
*/
|
||||
+ (void) handlePromise:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject
|
||||
databaseError:(NSError *) databaseError {
|
||||
if (databaseError != nil) {
|
||||
NSDictionary *jsError = [RNFirebaseDatabase getJSError:databaseError];
|
||||
reject([jsError valueForKey:@"code"], [jsError valueForKey:@"message"], databaseError);
|
||||
} else {
|
||||
callback(@[[NSNull null], @{@"status": @"success", @"ref": newPath}]);
|
||||
resolve([NSNull null]);
|
||||
}
|
||||
}
|
||||
|
||||
+ (FIRDatabase *) getDatabaseForApp:(NSString *) appName {
|
||||
FIRApp *app = [FIRApp appNamed:appName];
|
||||
return [FIRDatabase databaseForApp:app];
|
||||
}
|
||||
|
||||
- (FIRDatabaseReference *) getReferenceForAppPath:(NSString *) appName
|
||||
path:(NSString *) path {
|
||||
return [[RNFirebaseDatabase getDatabaseForApp:appName] referenceWithPath:path];
|
||||
}
|
||||
|
||||
- (RNFirebaseDatabaseReference *) getInternalReferenceForApp:(NSString *) appName
|
||||
refId:(NSNumber *) refId
|
||||
path:(NSString *) path
|
||||
modifiers:(NSArray *) modifiers
|
||||
keep:(BOOL) keep {
|
||||
RNFirebaseDatabaseReference *ref = _dbReferences[refId];
|
||||
|
||||
if (ref == nil) {
|
||||
ref = [[RNFirebaseDatabaseReference alloc] initWithPathAndModifiers:self app:appName refId:refId refPath:path modifiers:modifiers];
|
||||
|
||||
if (keep) {
|
||||
_dbReferences[refId] = ref;
|
||||
}
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
// TODO: Move to error util for use in other modules
|
||||
+ (NSString *) getMessageWithService:(NSString *) message
|
||||
service:(NSString *) service
|
||||
fullCode:(NSString *) fullCode {
|
||||
return [NSString stringWithFormat:@"%@: %@ (%@).", service, message, [fullCode lowercaseString]];
|
||||
}
|
||||
|
||||
+ (NSString *) getCodeWithService:(NSString *) service
|
||||
code:(NSString *) code {
|
||||
return [NSString stringWithFormat:@"%@/%@", [service uppercaseString], [code uppercaseString]];
|
||||
}
|
||||
|
||||
+ (NSDictionary *) getJSError:(NSError *) nativeError {
|
||||
NSMutableDictionary *errorMap = [[NSMutableDictionary alloc] init];
|
||||
[errorMap setValue:@(nativeError.code) forKey:@"nativeErrorCode"];
|
||||
[errorMap setValue:[nativeError localizedDescription] forKey:@"nativeErrorMessage"];
|
||||
|
||||
NSString *code;
|
||||
NSString *message;
|
||||
NSString *service = @"Database";
|
||||
|
||||
switch (nativeError.code) {
|
||||
// iOS confirmed codes
|
||||
case 1: // -3 on Android
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"permission-denied"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"Client doesn't have permission to access the desired data." service:service fullCode:code];
|
||||
break;
|
||||
case 2: // -10 on Android
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"unavailable"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"The service is unavailable." service:service fullCode:code];
|
||||
break;
|
||||
case 3: // -25 on Android
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"write-cancelled"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"The write was canceled by the user." service:service fullCode:code];
|
||||
break;
|
||||
|
||||
// TODO: Missing iOS equivalent codes
|
||||
case -1:
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"data-stale"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"The transaction needs to be run again with current data." service:service fullCode:code];
|
||||
break;
|
||||
case -2:
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"failure"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"The server indicated that this operation failed." service:service fullCode:code];
|
||||
break;
|
||||
case -4:
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"disconnected"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"The operation had to be aborted due to a network disconnect." service:service fullCode:code];
|
||||
break;
|
||||
case -6:
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"expired-token"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"The supplied auth token has expired." service:service fullCode:code];
|
||||
break;
|
||||
case -7:
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"invalid-token"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"The supplied auth token was invalid." service:service fullCode:code];
|
||||
break;
|
||||
case -8:
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"max-retries"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"The transaction had too many retries." service:service fullCode:code];
|
||||
break;
|
||||
case -9:
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"overridden-by-set"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"The transaction was overridden by a subsequent set." service:service fullCode:code];
|
||||
break;
|
||||
case -11:
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"user-code-exception"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"User code called from the Firebase Database runloop threw an exception." service:service fullCode:code];
|
||||
break;
|
||||
case -24:
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"network-error"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"The operation could not be performed due to a network error." service:service fullCode:code];
|
||||
break;
|
||||
default:
|
||||
code = [RNFirebaseDatabase getCodeWithService:service code:@"unknown"];
|
||||
message = [RNFirebaseDatabase getMessageWithService:@"An unknown error occurred." service:service fullCode:code];
|
||||
break;
|
||||
}
|
||||
|
||||
[errorMap setValue:code forKey:@"code"];
|
||||
[errorMap setValue:message forKey:@"message"];
|
||||
|
||||
return errorMap;
|
||||
}
|
||||
|
||||
- (NSDictionary *) createTransactionUpdateMap:(NSString *) appName
|
||||
transactionId:(NSNumber *) transactionId
|
||||
updatesData:(FIRMutableData *) updatesData {
|
||||
NSMutableDictionary *updatesMap = [[NSMutableDictionary alloc] init];
|
||||
[updatesMap setValue:transactionId forKey:@"id"];
|
||||
[updatesMap setValue:@"update" forKey:@"type"];
|
||||
[updatesMap setValue:appName forKey:@"appName"];
|
||||
[updatesMap setValue:updatesData.value forKey:@"value"];
|
||||
|
||||
return updatesMap;
|
||||
}
|
||||
|
||||
- (NSDictionary *) createTransactionResultMap:(NSString *) appName
|
||||
transactionId:(NSNumber *) transactionId
|
||||
error:(NSError *) error
|
||||
committed:(BOOL) committed
|
||||
snapshot:(FIRDataSnapshot *) snapshot {
|
||||
NSMutableDictionary *resultMap = [[NSMutableDictionary alloc] init];
|
||||
[resultMap setValue:transactionId forKey:@"id"];
|
||||
[resultMap setValue:appName forKey:@"appName"];
|
||||
// TODO: no timeout on iOS
|
||||
[resultMap setValue:@(committed) forKey:@"committed"];
|
||||
// TODO: no interrupted on iOS
|
||||
if (error != nil) {
|
||||
[resultMap setValue:@"error" forKey:@"type"];
|
||||
[resultMap setValue:[RNFirebaseDatabase getJSError:error] forKey:@"error"];
|
||||
// TODO: timeout error on iOS
|
||||
} else {
|
||||
[resultMap setValue:@"complete" forKey:@"type"];
|
||||
[resultMap setValue:[RNFirebaseDatabaseReference snapshotToDict:snapshot] forKey:@"snapshot"];
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
|
||||
/* TODO
|
||||
RCT_EXPORT_METHOD(on:
|
||||
(nonnull
|
||||
NSNumber *) refId
|
||||
|
@ -231,17 +398,6 @@ RCT_EXPORT_METHOD(on:
|
|||
callback(@[[NSNull null], @{@"status": @"success", @"refId": refId, @"handle": path}]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(once:
|
||||
(nonnull
|
||||
NSNumber *) refId
|
||||
path:(NSString *) path
|
||||
modifiers:(NSArray *) modifiers
|
||||
eventName:(NSString *) eventName
|
||||
callback:(RCTResponseSenderBlock) callback) {
|
||||
RNFirebaseDatabaseReference *ref = [self getDBHandle:refId path:path modifiers:modifiers];
|
||||
[ref addSingleEventHandler:eventName callback:callback];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(off:
|
||||
(nonnull
|
||||
NSNumber *) refId
|
||||
|
@ -261,60 +417,6 @@ RCT_EXPORT_METHOD(off:
|
|||
callback(@[[NSNull null], @{@"status": @"success", @"refId": refId,}]);
|
||||
}
|
||||
|
||||
// On disconnect
|
||||
RCT_EXPORT_METHOD(onDisconnectSet:
|
||||
(NSString *) path
|
||||
props:
|
||||
(NSDictionary *) props
|
||||
callback:
|
||||
(RCTResponseSenderBlock) callback) {
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
[ref onDisconnectSetValue:props[@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
|
||||
[self handleCallback:@"onDisconnectSetObject" callback:callback databaseError:error];
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(onDisconnectRemove:
|
||||
(NSString *) path
|
||||
callback:
|
||||
(RCTResponseSenderBlock) callback) {
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
[ref onDisconnectRemoveValueWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
|
||||
[self handleCallback:@"onDisconnectRemove" callback:callback databaseError:error];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
RCT_EXPORT_METHOD(onDisconnectCancel:
|
||||
(NSString *) path
|
||||
callback:
|
||||
(RCTResponseSenderBlock) callback) {
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
[ref cancelDisconnectOperationsWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
|
||||
[self handleCallback:@"onDisconnectCancel" callback:callback databaseError:error];
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(goOffline) {
|
||||
[FIRDatabase database].goOffline;
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(goOnline) {
|
||||
[FIRDatabase database].goOnline;
|
||||
}
|
||||
|
||||
- (FIRDatabaseReference *)getPathRef:(NSString *)path {
|
||||
return [[[FIRDatabase database] reference] child:path];
|
||||
}
|
||||
|
||||
- (void)handleCallback:(NSString *)methodName callback:(RCTResponseSenderBlock)callback databaseError:(NSError *)databaseError {
|
||||
if (databaseError != nil) {
|
||||
NSDictionary *evt = @{@"code": @([databaseError code]), @"details": [databaseError debugDescription], @"message": [databaseError localizedDescription], @"description": [databaseError description]};
|
||||
callback(@[evt]);
|
||||
} else {
|
||||
callback(@[[NSNull null], @{@"status": @"success", @"method": methodName}]);
|
||||
}
|
||||
}
|
||||
|
||||
- (RNFirebaseDatabaseReference *)getDBHandle:(NSNumber *)refId path:(NSString *)path modifiers:(NSArray *)modifiers {
|
||||
RNFirebaseDatabaseReference *ref = _dbReferences[refId];
|
||||
|
@ -324,7 +426,7 @@ RCT_EXPORT_METHOD(goOnline) {
|
|||
_dbReferences[refId] = ref;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
} */
|
||||
|
||||
// Not sure how to get away from this... yet
|
||||
- (NSArray<NSString *> *)supportedEvents {
|
||||
|
|
|
@ -8,13 +8,14 @@
|
|||
@interface RNFirebaseDatabaseReference : NSObject
|
||||
@property RCTEventEmitter *emitter;
|
||||
@property FIRDatabaseQuery *query;
|
||||
@property NSString *app;
|
||||
@property NSNumber *refId;
|
||||
@property NSString *path;
|
||||
@property NSMutableDictionary *listeners;
|
||||
|
||||
- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter database:(FIRDatabase *)database refId:(NSNumber *)refId path:(NSString *)path modifiers:(NSArray *)modifiers;
|
||||
- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter app:(NSString *)app refId:(NSNumber *)refId refPath:(NSString *)refPath modifiers:(NSArray *)modifiers;
|
||||
- (void)addEventHandler:(NSNumber *)listenerId eventName:(NSString *)eventName;
|
||||
- (void)addSingleEventHandler:(NSString *)eventName callback:(RCTResponseSenderBlock)callback;
|
||||
- (void)addSingleEventHandler:(NSString *)eventName resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
- (void)removeEventHandler:(NSNumber *)listenerId eventName:(NSString *)eventName;
|
||||
- (BOOL)hasListeners;
|
||||
+ (NSDictionary *)snapshotToDict:(FIRDataSnapshot *)snapshot;
|
||||
|
|
|
@ -1,18 +1,27 @@
|
|||
#import "RNFirebaseDatabaseReference.h"
|
||||
|
||||
#if __has_include(<FirebaseDatabase/FIRDatabase.h>)
|
||||
#import "RNFirebaseDatabase.h"
|
||||
#import "RNFirebaseEvents.h"
|
||||
|
||||
@implementation RNFirebaseDatabaseReference
|
||||
|
||||
- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter database:(FIRDatabase *)database refId:(NSNumber *)refId path:(NSString *)path modifiers:(NSArray *)modifiers {
|
||||
- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter
|
||||
app:(NSString *) app
|
||||
refId:(NSNumber *) refId
|
||||
refPath:(NSString *) refPath
|
||||
modifiers:(NSArray *) modifiers {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_emitter = emitter;
|
||||
_app = app;
|
||||
_refId = refId;
|
||||
_path = path;
|
||||
_query = [self buildQueryAtPathWithModifiers:database path:path modifiers:modifiers];
|
||||
_path = refPath;
|
||||
|
||||
// TODO: Only create if needed
|
||||
_listeners = [[NSMutableDictionary alloc] init];
|
||||
|
||||
_query = [self buildQueryAtPathWithModifiers:refPath modifiers:modifiers];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -36,15 +45,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (void)addSingleEventHandler:(NSString *)eventName callback:(RCTResponseSenderBlock)callback {
|
||||
- (void)addSingleEventHandler:(NSString *)eventName
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject {
|
||||
FIRDataEventType firDataEventType = (FIRDataEventType)[self eventTypeFromName:eventName];
|
||||
|
||||
[_query observeSingleEventOfType:firDataEventType andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *_Nonnull snapshot, NSString *_Nullable previousChildName) {
|
||||
NSDictionary *props = [RNFirebaseDatabaseReference snapshotToDict:snapshot];
|
||||
callback(@[[NSNull null], @{@"eventName": eventName, @"path": _path, @"refId": _refId, @"snapshot": props, @"previousChildName": previousChildName != nil ? previousChildName : [NSNull null]}]);
|
||||
NSDictionary *data = [RNFirebaseDatabaseReference snapshotToDictionary:eventName path:_path dataSnapshot:snapshot previousChildName:previousChildName refId:_refId listenerId:0];
|
||||
resolve(data);
|
||||
} withCancelBlock:^(NSError *_Nonnull error) {
|
||||
NSLog(@"Error onDBEventOnce: %@", [error debugDescription]);
|
||||
callback(@[@{@"eventName": DATABASE_ERROR_EVENT, @"path": _path, @"refId": _refId, @"code": @([error code]), @"details": [error debugDescription], @"message": [error localizedDescription], @"description": [error description]}]);
|
||||
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
|
||||
}];
|
||||
}
|
||||
|
||||
|
@ -56,6 +67,45 @@
|
|||
}
|
||||
}
|
||||
|
||||
+ (NSDictionary *) snapshotToDictionary:(NSString *) eventName
|
||||
path:(NSString *) path
|
||||
dataSnapshot:(FIRDataSnapshot *) dataSnapshot
|
||||
previousChildName:(NSString *) previousChildName
|
||||
refId:(NSNumber *) refId
|
||||
listenerId:(NSNumber *) listenerId {
|
||||
NSMutableDictionary *snapshot = [[NSMutableDictionary alloc] init];
|
||||
NSMutableDictionary *eventMap = [[NSMutableDictionary alloc] init];
|
||||
|
||||
[snapshot setValue:dataSnapshot.key forKey:@"key"];
|
||||
[snapshot setValue:@(dataSnapshot.exists) forKey:@"exists"];
|
||||
[snapshot setValue:@(dataSnapshot.hasChildren) forKey:@"hasChildren"];
|
||||
[snapshot setValue:@(dataSnapshot.childrenCount) forKey:@"childrenCount"];
|
||||
[snapshot setValue:dataSnapshot.value forKey:@"value"];
|
||||
[snapshot setValue:[RNFirebaseDatabaseReference getChildKeys:dataSnapshot] forKey:@"childKeys"];
|
||||
[snapshot setValue:dataSnapshot.priority forKey:@"priority"];
|
||||
|
||||
[eventMap setValue:refId forKey:@"refId"];
|
||||
[eventMap setValue:path forKey:@"path"];
|
||||
[eventMap setValue:snapshot forKey:@"snapshot"];
|
||||
[eventMap setValue:eventName forKey:@"eventName"];
|
||||
[eventMap setValue:listenerId forKey:@"listenerId"];
|
||||
[eventMap setValue:previousChildName forKey:@"previousChildName"];
|
||||
|
||||
return eventMap;
|
||||
}
|
||||
|
||||
+ (NSMutableArray *) getChildKeys:(FIRDataSnapshot *) snapshot {
|
||||
NSMutableArray *childKeys = [NSMutableArray array];
|
||||
if (snapshot.childrenCount > 0) {
|
||||
NSEnumerator *children = [snapshot children];
|
||||
FIRDataSnapshot *child;
|
||||
while (child = [children nextObject]) {
|
||||
[childKeys addObject:child.key];
|
||||
}
|
||||
}
|
||||
return childKeys;
|
||||
}
|
||||
|
||||
+ (NSDictionary *)snapshotToDict:(FIRDataSnapshot *)snapshot {
|
||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||
[dict setValue:snapshot.key forKey:@"key"];
|
||||
|
@ -103,8 +153,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (FIRDatabaseQuery *)buildQueryAtPathWithModifiers:(FIRDatabase *)database path:(NSString *)path modifiers:(NSArray *)modifiers {
|
||||
FIRDatabaseQuery *query = [[database reference] child:path];
|
||||
- (FIRDatabaseQuery *)buildQueryAtPathWithModifiers:(NSString *) path
|
||||
modifiers:(NSArray *)modifiers {
|
||||
FIRDatabase *firebaseDatabase = [RNFirebaseDatabase getDatabaseForApp:_app];
|
||||
FIRDatabaseQuery *query = [[firebaseDatabase reference] child:path];
|
||||
|
||||
for (NSDictionary *modifier in modifiers) {
|
||||
NSString *type = [modifier valueForKey:@"type"];
|
||||
|
|
Loading…
Reference in New Issue