From 7459b68403d1586a2d740856de743e5918ff3445 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Fri, 4 Dec 2020 21:54:41 -0500 Subject: [PATCH 01/16] Implement RTDB Query get --- .../Sources/Api/FIRDatabaseQuery.m | 5 ++ .../Sources/Api/Private/FTypedefs_Private.h | 3 + .../Sources/Constants/FConstants.h | 3 + .../Sources/Constants/FConstants.m | 3 + .../Sources/Core/FPersistentConnection.h | 3 + .../Sources/Core/FPersistentConnection.m | 87 +++++++++++++++++++ FirebaseDatabase/Sources/Core/FRepo.h | 5 ++ FirebaseDatabase/Sources/Core/FRepo.m | 55 ++++++++++++ .../FirebaseDatabase/FIRDatabaseQuery.h | 4 + 9 files changed, 168 insertions(+) diff --git a/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m b/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m index 7a79d97ff53..ffb5dc2ff16 100644 --- a/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m +++ b/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m @@ -581,6 +581,11 @@ - (void)keepSynced:(BOOL)keepSynced { }); } +- (void)getDataWithCompletionBlock:(void (^)(NSError *__nullable error, + FIRDataSnapshot *snapshot))block { + [self.repo getValue:self withCompletionBlock:block]; +} + - (void)observeSingleEventOfType:(FIRDataEventType)eventType withBlock:(fbt_void_datasnapshot)block { diff --git a/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h b/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h index dac55bccb2a..0e60834444c 100644 --- a/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h +++ b/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h @@ -46,6 +46,9 @@ typedef BOOL (^fbt_bool_nsstring_node)(NSString *, id); typedef void (^fbt_void_path_node_marray)(FPath *, id, NSMutableArray *); typedef BOOL (^fbt_bool_void)(void); typedef void (^fbt_void_nsstring_nsstring)(NSString *str1, NSString *str2); +typedef void (^fbt_void_nsstring_nsstring_nsstring)(NSString *str1, + NSString *dict1, + NSString *str2); typedef void (^fbt_void_nsstring_nserror)(NSString *str, NSError *error); typedef BOOL (^fbt_bool_path)(FPath *str); typedef void (^fbt_void_id)(id data); diff --git a/FirebaseDatabase/Sources/Constants/FConstants.h b/FirebaseDatabase/Sources/Constants/FConstants.h index ae237a6c118..1b0dc317fc8 100644 --- a/FirebaseDatabase/Sources/Constants/FConstants.h +++ b/FirebaseDatabase/Sources/Constants/FConstants.h @@ -75,6 +75,7 @@ FOUNDATION_EXPORT NSString *const kFWPAsyncServerControlMessageReset; FOUNDATION_EXPORT NSString *const kFWPRequestActionPut; FOUNDATION_EXPORT NSString *const kFWPRequestActionMerge; +FOUNDATION_EXPORT NSString *const kFWPRequestActionGet; FOUNDATION_EXPORT NSString *const kFWPRequestActionTaggedListen; FOUNDATION_EXPORT NSString *const kFWPRequestActionTaggedUnlisten; FOUNDATION_EXPORT NSString @@ -105,9 +106,11 @@ FOUNDATION_EXPORT NSString *const kFWPRequestStatus; FOUNDATION_EXPORT NSString *const kWireProtocolVersionParam; FOUNDATION_EXPORT NSString *const kWebsocketProtocolVersion; FOUNDATION_EXPORT NSString *const kWebsocketServerKillPacket; +FOUNDATION_EXPORT NSString *const kPersistentConnOffline; FOUNDATION_EXPORT const int kWebsocketMaxFrameSize; FOUNDATION_EXPORT NSUInteger const kWebsocketKeepaliveInterval; FOUNDATION_EXPORT NSUInteger const kWebsocketConnectTimeout; +FOUNDATION_EXPORT UInt64 const kPersistentConnGetConnectTimeout; FOUNDATION_EXPORT float const kPersistentConnReconnectMinDelay; FOUNDATION_EXPORT float const kPersistentConnReconnectMaxDelay; diff --git a/FirebaseDatabase/Sources/Constants/FConstants.m b/FirebaseDatabase/Sources/Constants/FConstants.m index 3a2f4231b56..25bd721edad 100644 --- a/FirebaseDatabase/Sources/Constants/FConstants.m +++ b/FirebaseDatabase/Sources/Constants/FConstants.m @@ -70,6 +70,7 @@ NSString *const kFWPRequestActionPut = @"p"; NSString *const kFWPRequestActionMerge = @"m"; +NSString *const kFWPRequestActionGet = @"g"; NSString *const kFWPRequestActionListen = @"l"; // {"t": "d", "d": {"r": 1, "a": "l", "b": { "p": "/" } } } NSString *const kFWPRequestActionUnlisten = @"u"; @@ -99,9 +100,11 @@ NSString *const kWireProtocolVersionParam = @"v"; NSString *const kWebsocketProtocolVersion = @"5"; NSString *const kWebsocketServerKillPacket = @"kill"; +NSString *const kPersistentConnOffline = @"Client is offline."; const int kWebsocketMaxFrameSize = 16384; NSUInteger const kWebsocketKeepaliveInterval = 45; NSUInteger const kWebsocketConnectTimeout = 30; +UInt64 const kPersistentConnGetConnectTimeout = 3 * NSEC_PER_SEC; float const kPersistentConnReconnectMinDelay = 1.0; float const kPersistentConnReconnectMaxDelay = 30.0; diff --git a/FirebaseDatabase/Sources/Core/FPersistentConnection.h b/FirebaseDatabase/Sources/Core/FPersistentConnection.h index d3b7b5892a3..e327daf47c0 100644 --- a/FirebaseDatabase/Sources/Core/FPersistentConnection.h +++ b/FirebaseDatabase/Sources/Core/FPersistentConnection.h @@ -60,6 +60,9 @@ - (void)onDisconnectCancelPath:(FPath *)path withCallback:(fbt_void_nsstring_nsstring)callback; - (void)ackPuts; +- (void)get:(NSString *)pathString + withParams:(NSDictionary *)queryWireProtocolParams + withCallback:(fbt_void_nsstring_nsstring_nsstring)onComplete; - (void)purgeOutstandingWrites; - (void)interruptForReason:(NSString *)reason; diff --git a/FirebaseDatabase/Sources/Core/FPersistentConnection.m b/FirebaseDatabase/Sources/Core/FPersistentConnection.m index 1410dd5d691..27c4d3bc06e 100644 --- a/FirebaseDatabase/Sources/Core/FPersistentConnection.m +++ b/FirebaseDatabase/Sources/Core/FPersistentConnection.m @@ -64,6 +64,18 @@ @implementation FOutstandingPut @end +@interface FOutstandingGet : NSObject + +@property(nonatomic, strong) NSDictionary *request; +@property(nonatomic, copy) fbt_void_nsstring_nsstring_nsstring onCompleteBlock; +@property(nonatomic) BOOL sent; + +@end + +@implementation FOutstandingGet + +@end + typedef enum { ConnectionStateDisconnected, ConnectionStateGettingToken, @@ -92,9 +104,11 @@ - (void)sendOnDisconnectAction:(NSString *)action @property(nonatomic, strong) FConnection *realtime; @property(nonatomic, strong) NSMutableDictionary *listens; @property(nonatomic, strong) NSMutableDictionary *outstandingPuts; +@property(nonatomic, strong) NSMutableDictionary *outstandingGets; @property(nonatomic, strong) NSMutableArray *onDisconnectQueue; @property(nonatomic, strong) FRepoInfo *repoInfo; @property(nonatomic, strong) FAtomicNumber *putCounter; +@property(nonatomic, strong) FAtomicNumber *getCounter; @property(nonatomic, strong) FAtomicNumber *requestNumber; @property(nonatomic, strong) NSMutableDictionary *requestCBHash; @property(nonatomic, strong) FIRDatabaseConfig *config; @@ -309,6 +323,9 @@ - (BOOL)canSendWrites { return self->connectionState == ConnectionStateConnected; } +- (BOOL)canSendReads { + return self->connectionState == ConnectionStateConnected; +} #pragma mark - #pragma mark FConnection delegate methods @@ -707,6 +724,37 @@ - (void)sendPut:(NSNumber *)index { }]; } +- (void)sendGet:(NSNumber *)index { + FOutstandingGet *get = self.outstandingGets[index]; + if ([get sent]) { + return; + } + get.sent = YES; + [self sendAction:kFWPRequestActionGet + body:get.request + sensitive:NO + callback:^(NSDictionary *data) { + FOutstandingGet *currentGet = self.outstandingGets[index]; + if (currentGet == get) { + [self.outstandingGets removeObjectForKey:index]; + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + NSString *resultData = + [data objectForKey:kFWPResponseForActionData]; + if (status == kFWPResponseForActionStatusOk) { + get.onCompleteBlock(status, resultData, nil); + return; + } + get.onCompleteBlock(status, nil, resultData); + } else { + FFLog(@"I-RDB034045", + @"Ignoring on complete for get %@ because it was " + @"already removed", + index); + } + }]; +} + - (void)sendUnlisten:(FPath *)path queryParams:(FQueryParams *)queryParams tagId:(NSNumber *)tagId { @@ -759,6 +807,45 @@ - (void)putInternal:(id)data } } +- (void)get:(NSString *)pathString + withParams:(NSDictionary *)queryWireProtocolParams + withCallback:(fbt_void_nsstring_nsstring_nsstring)onComplete { + NSMutableDictionary *request = [NSMutableDictionary + dictionaryWithObjectsAndKeys:pathString, kFWPRequestPath, + queryWireProtocolParams, + kFWPRequestQueries, nil]; + FOutstandingGet *get = [[FOutstandingGet alloc] init]; + get.request = request; + get.onCompleteBlock = onComplete; + get.sent = NO; + + NSNumber *index = [self.getCounter getAndIncrement]; + self.outstandingGets[index] = get; + + if (![self canSendReads]) { + dispatch_after( + dispatch_time(DISPATCH_TIME_NOW, kPersistentConnGetConnectTimeout), + self.dispatchQueue, ^{ + if (![get sent]) { + return; + } + [self.outstandingGets removeObjectForKey:index]; + get.onCompleteBlock(@"failed", nil, kPersistentConnOffline); + }); + return; + } + + if ([self canSendReads]) { + FFLog(@"I-RDB034024", @"Was connected, and added as index: %@", index); + [self sendGet:index]; + } else { + FFLog(@"I-RDB034025", + @"Wasn't connected or writes paused, so added to outstanding " + @"gets only. Path: %@", + pathString); + } +} + - (void)sendListen:(FOutstandingQuery *)listenSpec { FQuerySpec *query = listenSpec.query; FFLog(@"I-RDB034026", @"Listen for %@", query); diff --git a/FirebaseDatabase/Sources/Core/FRepo.h b/FirebaseDatabase/Sources/Core/FRepo.h index d8602910d1e..504028a61c2 100644 --- a/FirebaseDatabase/Sources/Core/FRepo.h +++ b/FirebaseDatabase/Sources/Core/FRepo.h @@ -45,6 +45,11 @@ withCallback:(fbt_void_nserror_ref)callback; - (void)purgeOutstandingWrites; +- (void)getValue:(FQuerySpec *)query + withCompletionBlock: + (void (^_Nonnull)(NSError *__nullable error, + FIRDataSnapshot *__nullable snapshot))block; + - (void)addEventRegistration:(id)eventRegistration forQuery:(FQuerySpec *)query; - (void)removeEventRegistration:(id)eventRegistration diff --git a/FirebaseDatabase/Sources/Core/FRepo.m b/FirebaseDatabase/Sources/Core/FRepo.m index 55608aeaddb..a6a570dd021 100644 --- a/FirebaseDatabase/Sources/Core/FRepo.m +++ b/FirebaseDatabase/Sources/Core/FRepo.m @@ -513,6 +513,61 @@ - (void)purgeOutstandingWrites { [self.connection purgeOutstandingWrites]; } +- (void)getValue:(FIRDatabaseQuery *)query + withCompletionBlock: + (void (^_Nonnull)(NSError *__nullable error, + FIRDataSnapshot *__nullable snapshot))block { + FQuerySpec *querySpec = [query querySpec]; + [self.persistenceManager setQueryActive:querySpec]; + [self.connection + get:[query.path toString] + withParams:querySpec.params.wireProtocolParams + withCallback:^(NSString *status, NSString *data, + NSString *errorReason) { + if (![status isEqualToString:kFWPResponseForActionStatusOk]) { + FFLog(@"I-RDB038024", + @"getValue for query %@ falling back to cache", + [querySpec.path toString]); + id cached = [self.serverSyncTree + calcCompleteEventCacheAtPath:querySpec.path + excludeWriteIds:@[]]; + if ([cached isEmpty]) { + FFWarn(@"I-RDB038025", @"getValue for query at %@ failed: %@", + [querySpec.path toString], status); + NSDictionary *errorDict = @{ + NSLocalizedDescriptionKey : [NSString + stringWithFormat: + @"Unable to get latest value for query %@, " + @"client offline and cache is empty", + querySpec] + }; + block([NSError errorWithDomain:kFirebaseCoreErrorDomain + code:1 + userInfo:errorDict], + nil); + return; + } + } else { + id node = [FSnapshotUtilities + nodeFrom:[NSJSONSerialization + JSONObjectWithData: + [data dataUsingEncoding:NSUTF8StringEncoding] + options:kNilOptions + error:nil]]; + [self.eventRaiser + raiseEvents:[self.serverSyncTree + applyServerOverwriteAtPath:[query path] + newData:node]]; + block(nil, + [[FIRDataSnapshot alloc] + initWithRef:query.ref + indexedNode:[FIndexedNode + indexedNodeWithNode:node + index:querySpec.index]]); + } + }]; +} + - (void)addEventRegistration:(id)eventRegistration forQuery:(FQuerySpec *)query { NSArray *events = nil; diff --git a/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h b/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h index 82057aaee3f..c2ec7c67553 100644 --- a/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h +++ b/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h @@ -131,6 +131,10 @@ NS_SWIFT_NAME(DatabaseQuery) withCancelBlock: (nullable void (^)(NSError *error))cancelBlock; +- (void)getDataWithCompletionBlock: + (void (^_Nonnull)(NSError *__nullable error, + FIRDataSnapshot *snapshot))block; + /** * This is equivalent to observeEventType:withBlock:, except the block is * immediately canceled after the initial data is returned. From b9b48661c88c5026068c424f1e16e0aca40ef135 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Fri, 4 Dec 2020 22:53:24 -0500 Subject: [PATCH 02/16] changelog --- FirebaseDatabase/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/FirebaseDatabase/CHANGELOG.md b/FirebaseDatabase/CHANGELOG.md index 2ee409296fc..a7c5d9076a1 100644 --- a/FirebaseDatabase/CHANGELOG.md +++ b/FirebaseDatabase/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased - [added] Made emulator connection API consistent between Auth, Database, Firestore, and Functions (#5916). +- [added] Implement RTDB Query get (#7110) # v7.0.0 - [fixed] Disabled a deprecation warning. (#6502) From db9d95698c81b83b3daaa5ec356ff2bc22ed4516 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Mon, 7 Dec 2020 12:11:48 -0500 Subject: [PATCH 03/16] Mark query inactive after callback --- FirebaseDatabase/Sources/Core/FRepo.m | 1 + 1 file changed, 1 insertion(+) diff --git a/FirebaseDatabase/Sources/Core/FRepo.m b/FirebaseDatabase/Sources/Core/FRepo.m index a6a570dd021..2a5abcadb60 100644 --- a/FirebaseDatabase/Sources/Core/FRepo.m +++ b/FirebaseDatabase/Sources/Core/FRepo.m @@ -564,6 +564,7 @@ - (void)getValue:(FIRDatabaseQuery *)query indexedNode:[FIndexedNode indexedNodeWithNode:node index:querySpec.index]]); + [self.persistenceManager setQueryInactive:querySpec]; } }]; } From c04d225782098c54fe1ff96c31855e9567bb1861 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Tue, 8 Dec 2020 12:49:01 -0500 Subject: [PATCH 04/16] Add tests, fix some issues --- .../Sources/Api/FIRDatabaseQuery.m | 4 +- .../Sources/Api/Private/FTypedefs_Private.h | 5 +- .../Sources/Constants/FConstants.h | 1 + .../Sources/Constants/FConstants.m | 1 + .../Sources/Core/FPersistentConnection.h | 2 +- .../Sources/Core/FPersistentConnection.m | 36 +++- FirebaseDatabase/Sources/Core/FRepo.h | 3 +- FirebaseDatabase/Sources/Core/FRepo.m | 37 ++-- .../Tests/Integration/FIRDatabaseQueryTests.m | 189 ++++++++++++++++++ 9 files changed, 240 insertions(+), 38 deletions(-) diff --git a/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m b/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m index ffb5dc2ff16..b93183d0b36 100644 --- a/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m +++ b/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m @@ -583,7 +583,9 @@ - (void)keepSynced:(BOOL)keepSynced { - (void)getDataWithCompletionBlock:(void (^)(NSError *__nullable error, FIRDataSnapshot *snapshot))block { - [self.repo getValue:self withCompletionBlock:block]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo getValue:self withCompletionBlock:block]; + }); } - (void)observeSingleEventOfType:(FIRDataEventType)eventType diff --git a/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h b/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h index 0e60834444c..3fe2bf6a17d 100644 --- a/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h +++ b/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h @@ -46,9 +46,8 @@ typedef BOOL (^fbt_bool_nsstring_node)(NSString *, id); typedef void (^fbt_void_path_node_marray)(FPath *, id, NSMutableArray *); typedef BOOL (^fbt_bool_void)(void); typedef void (^fbt_void_nsstring_nsstring)(NSString *str1, NSString *str2); -typedef void (^fbt_void_nsstring_nsstring_nsstring)(NSString *str1, - NSString *dict1, - NSString *str2); +typedef void (^fbt_void_nsstring_id_nsstring)(NSString *str1, id dict1, + NSString *str2); typedef void (^fbt_void_nsstring_nserror)(NSString *str, NSError *error); typedef BOOL (^fbt_bool_path)(FPath *str); typedef void (^fbt_void_id)(id data); diff --git a/FirebaseDatabase/Sources/Constants/FConstants.h b/FirebaseDatabase/Sources/Constants/FConstants.h index 1b0dc317fc8..ca627299596 100644 --- a/FirebaseDatabase/Sources/Constants/FConstants.h +++ b/FirebaseDatabase/Sources/Constants/FConstants.h @@ -148,6 +148,7 @@ FOUNDATION_EXPORT NSString *const kFInterruptReasonAuthExpired; FOUNDATION_EXPORT NSString *const kPayloadPriority; FOUNDATION_EXPORT NSString *const kPayloadValue; FOUNDATION_EXPORT NSString *const kPayloadMetadataPrefix; +FOUNDATION_EXPORT NSString *const kPayloadNull; #pragma mark - #pragma mark ServerValue constants diff --git a/FirebaseDatabase/Sources/Constants/FConstants.m b/FirebaseDatabase/Sources/Constants/FConstants.m index 25bd721edad..1ef0e037694 100644 --- a/FirebaseDatabase/Sources/Constants/FConstants.m +++ b/FirebaseDatabase/Sources/Constants/FConstants.m @@ -140,6 +140,7 @@ NSString *const kPayloadPriority = @".priority"; NSString *const kPayloadValue = @".value"; NSString *const kPayloadMetadataPrefix = @"."; +NSString *const kPayloadNull = @""; #pragma mark - #pragma mark ServerValue constants diff --git a/FirebaseDatabase/Sources/Core/FPersistentConnection.h b/FirebaseDatabase/Sources/Core/FPersistentConnection.h index e327daf47c0..fb103357ec9 100644 --- a/FirebaseDatabase/Sources/Core/FPersistentConnection.h +++ b/FirebaseDatabase/Sources/Core/FPersistentConnection.h @@ -62,7 +62,7 @@ - (void)ackPuts; - (void)get:(NSString *)pathString withParams:(NSDictionary *)queryWireProtocolParams - withCallback:(fbt_void_nsstring_nsstring_nsstring)onComplete; + withCallback:(fbt_void_nsstring_id_nsstring)onComplete; - (void)purgeOutstandingWrites; - (void)interruptForReason:(NSString *)reason; diff --git a/FirebaseDatabase/Sources/Core/FPersistentConnection.m b/FirebaseDatabase/Sources/Core/FPersistentConnection.m index 27c4d3bc06e..a60b242e64f 100644 --- a/FirebaseDatabase/Sources/Core/FPersistentConnection.m +++ b/FirebaseDatabase/Sources/Core/FPersistentConnection.m @@ -67,7 +67,7 @@ @implementation FOutstandingPut @interface FOutstandingGet : NSObject @property(nonatomic, strong) NSDictionary *request; -@property(nonatomic, copy) fbt_void_nsstring_nsstring_nsstring onCompleteBlock; +@property(nonatomic, copy) fbt_void_nsstring_id_nsstring onCompleteBlock; @property(nonatomic) BOOL sent; @end @@ -142,8 +142,10 @@ - (id)initWithRepoInfo:(FRepoInfo *)repoInfo self.listens = [[NSMutableDictionary alloc] init]; self.outstandingPuts = [[NSMutableDictionary alloc] init]; + self.outstandingGets = [[NSMutableDictionary alloc] init]; self.onDisconnectQueue = [[NSMutableArray alloc] init]; self.putCounter = [[FAtomicNumber alloc] init]; + self.getCounter = [[FAtomicNumber alloc] init]; self.requestNumber = [[FAtomicNumber alloc] init]; self.requestCBHash = [[NSMutableDictionary alloc] init]; self.unackedListensCount = 0; @@ -725,7 +727,10 @@ - (void)sendPut:(NSNumber *)index { } - (void)sendGet:(NSNumber *)index { + NSAssert([self canSendReads], + @"sendGet called when not able to send reads"); FOutstandingGet *get = self.outstandingGets[index]; + assert(get != nil); if ([get sent]) { return; } @@ -739,9 +744,8 @@ - (void)sendGet:(NSNumber *)index { [self.outstandingGets removeObjectForKey:index]; NSString *status = [data objectForKey:kFWPResponseForActionStatus]; - NSString *resultData = - [data objectForKey:kFWPResponseForActionData]; - if (status == kFWPResponseForActionStatusOk) { + id resultData = [data objectForKey:kFWPResponseForActionData]; + if ([status isEqualToString:kFWPResponseForActionStatusOk]) { get.onCompleteBlock(status, resultData, nil); return; } @@ -809,7 +813,7 @@ - (void)putInternal:(id)data - (void)get:(NSString *)pathString withParams:(NSDictionary *)queryWireProtocolParams - withCallback:(fbt_void_nsstring_nsstring_nsstring)onComplete { + withCallback:(fbt_void_nsstring_id_nsstring)onComplete { NSMutableDictionary *request = [NSMutableDictionary dictionaryWithObjectsAndKeys:pathString, kFWPRequestPath, queryWireProtocolParams, @@ -822,13 +826,15 @@ - (void)get:(NSString *)pathString NSNumber *index = [self.getCounter getAndIncrement]; self.outstandingGets[index] = get; - if (![self canSendReads]) { + if (![self connected]) { dispatch_after( dispatch_time(DISPATCH_TIME_NOW, kPersistentConnGetConnectTimeout), self.dispatchQueue, ^{ - if (![get sent]) { + FOutstandingGet *get = self.outstandingGets[index]; + if ([get sent]) { return; } + get.sent = YES; [self.outstandingGets removeObjectForKey:index]; get.onCompleteBlock(@"failed", nil, kPersistentConnOffline); }); @@ -839,10 +845,7 @@ - (void)get:(NSString *)pathString FFLog(@"I-RDB034024", @"Was connected, and added as index: %@", index); [self sendGet:index]; } else { - FFLog(@"I-RDB034025", - @"Wasn't connected or writes paused, so added to outstanding " - @"gets only. Path: %@", - pathString); + FFLog(@"I-RDB034025", @"Was connected, and added as index: %@", index); } } @@ -1096,6 +1099,17 @@ - (void)restoreState { } } + NSArray *getKeys = [[self.outstandingGets allKeys] + sortedArrayUsingSelector:@selector(compare:)]; + for (int i = 0; i < [getKeys count]; i++) { + if ([self.outstandingGets objectForKey:[keys objectAtIndex:i]] != nil) { + FFLog(@"I-RDB034037", @"Restoring get: %d", i); + [self sendGet:[keys objectAtIndex:i]]; + } else { + FFLog(@"I-RDB034038", @"Restoring get: skipped nil: %d", i); + } + } + for (FTupleOnDisconnect *tuple in self.onDisconnectQueue) { [self sendOnDisconnectAction:tuple.action forPath:tuple.pathString diff --git a/FirebaseDatabase/Sources/Core/FRepo.h b/FirebaseDatabase/Sources/Core/FRepo.h index 504028a61c2..7e58bf37d00 100644 --- a/FirebaseDatabase/Sources/Core/FRepo.h +++ b/FirebaseDatabase/Sources/Core/FRepo.h @@ -17,6 +17,7 @@ #import "FirebaseDatabase/Sources/Core/FPersistentConnection.h" #import "FirebaseDatabase/Sources/Core/FRepoInfo.h" #import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" #import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h" #import @@ -45,7 +46,7 @@ withCallback:(fbt_void_nserror_ref)callback; - (void)purgeOutstandingWrites; -- (void)getValue:(FQuerySpec *)query +- (void)getValue:(FIRDatabaseQuery *)query withCompletionBlock: (void (^_Nonnull)(NSError *__nullable error, FIRDataSnapshot *__nullable snapshot))block; diff --git a/FirebaseDatabase/Sources/Core/FRepo.m b/FirebaseDatabase/Sources/Core/FRepo.m index 2a5abcadb60..7fa8685119e 100644 --- a/FirebaseDatabase/Sources/Core/FRepo.m +++ b/FirebaseDatabase/Sources/Core/FRepo.m @@ -522,19 +522,20 @@ - (void)getValue:(FIRDatabaseQuery *)query [self.connection get:[query.path toString] withParams:querySpec.params.wireProtocolParams - withCallback:^(NSString *status, NSString *data, - NSString *errorReason) { + withCallback:^(NSString *status, id data, NSString *errorReason) { + id node; if (![status isEqualToString:kFWPResponseForActionStatusOk]) { FFLog(@"I-RDB038024", @"getValue for query %@ falling back to cache", [querySpec.path toString]); - id cached = [self.serverSyncTree + node = [self.serverSyncTree calcCompleteEventCacheAtPath:querySpec.path excludeWriteIds:@[]]; - if ([cached isEmpty]) { + if ([node isEmpty]) { FFWarn(@"I-RDB038025", @"getValue for query at %@ failed: %@", [querySpec.path toString], status); NSDictionary *errorDict = @{ + NSLocalizedFailureReasonErrorKey : errorReason, NSLocalizedDescriptionKey : [NSString stringWithFormat: @"Unable to get latest value for query %@, " @@ -548,24 +549,18 @@ - (void)getValue:(FIRDatabaseQuery *)query return; } } else { - id node = [FSnapshotUtilities - nodeFrom:[NSJSONSerialization - JSONObjectWithData: - [data dataUsingEncoding:NSUTF8StringEncoding] - options:kNilOptions - error:nil]]; - [self.eventRaiser - raiseEvents:[self.serverSyncTree - applyServerOverwriteAtPath:[query path] - newData:node]]; - block(nil, - [[FIRDataSnapshot alloc] - initWithRef:query.ref - indexedNode:[FIndexedNode - indexedNodeWithNode:node - index:querySpec.index]]); - [self.persistenceManager setQueryInactive:querySpec]; + node = [FSnapshotUtilities nodeFrom:data]; } + [self.eventRaiser + raiseEvents:[self.serverSyncTree + applyServerOverwriteAtPath:[query path] + newData:node]]; + block(nil, [[FIRDataSnapshot alloc] + initWithRef:query.ref + indexedNode:[FIndexedNode + indexedNodeWithNode:node + index:querySpec.index]]); + [self.persistenceManager setQueryInactive:querySpec]; }]; } diff --git a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m index eb67b85c1b4..43ad04a0a54 100644 --- a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m +++ b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m @@ -15,8 +15,12 @@ */ #import "FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.h" +#import "FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h" #import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" #import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Tests/Helpers/FIRFakeApp.h" #import "FirebaseDatabase/Tests/Helpers/FTestExpectations.h" @implementation FIRDatabaseQueryTests @@ -3056,4 +3060,189 @@ - (void)testAddingListensForTheSamePathDoesNotCheckFail { WAIT_FOR(done); } +- (void)testEmptyQueryGet { + FIRDatabaseReference* ref = [FTestHelpers getRandomNode]; + + __block BOOL done = NO; + + [ref getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) { + XCTAssertNil(snapshot.value); + done = YES; + }]; + + WAIT_FOR(done); +} + +- (void)testOfflineQueryGet { + FIRDatabase* db = [FTestHelpers defaultDatabase]; + FIRDatabaseReference* ref = [db reference]; + + __block BOOL done = NO; + + [db goOffline]; + + [ref getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) { + XCTAssertNotNil(err); + XCTAssertEqualObjects([err localizedFailureReason], kPersistentConnOffline); + done = YES; + }]; + + WAIT_FOR(done); +} + +- (void)testGetQueryBasic { + FIRDatabase* db = [FTestHelpers defaultDatabase]; + FIRDatabaseReference* ref = [db reference]; + + __block BOOL done = NO; + + [ref setValue:@42 + withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) { + XCTAssertNil(error); + done = YES; + }]; + + WAIT_FOR(done); + + [ref getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) { + XCTAssertNil(err); + XCTAssertEqualObjects(snapshot.value, @42); + done = YES; + }]; + + WAIT_FOR(done); +} + +- (void)testQueryGetCached { + FIRDatabase* db = [FTestHelpers defaultDatabase]; + FIRDatabaseReference* ref = [db reference]; + + __block BOOL done = NO; + + [ref observeEventType:FIRDataEventTypeValue + withBlock:^(FIRDataSnapshot* snapshot) { + id value = [snapshot value]; + if (value != nil && [value isEqualToNumber:@42]) { + done = YES; + } + }]; + + WAIT_FOR(done); + done = NO; + + [ref setValue:@42 + withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) { + XCTAssertNil(error); + done = YES; + }]; + + WAIT_FOR(done); + done = NO; + + [db goOffline]; + + [ref getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) { + XCTAssertNil(err); + XCTAssertEqualObjects(snapshot.value, @42); + done = YES; + }]; + + WAIT_FOR(done); +} + +static NSString* kFirebaseDatabaseEmulatorUrlFmt = @"http://localhost:9000?ns=%@"; + +- (void)testGetRetrievesLatestValueEvenIfCached { + NSString* url = + [NSString stringWithFormat:kFirebaseDatabaseEmulatorUrlFmt, [[NSUUID UUID] UUIDString]]; + + id writerApp = [[FIRFakeApp alloc] initWithName:@"writer" URL:url]; + id readerApp = [[FIRFakeApp alloc] initWithName:@"reader" URL:url]; + + FIRDatabase* db = [FIRDatabase databaseForApp:readerApp]; + FIRDatabaseReference* readRef = [db reference]; + + FIRDatabase* db2 = [FIRDatabase databaseForApp:writerApp]; + FIRDatabaseReference* writeRef = [db2 reference]; + + XCTAssertNotEqual(db, db2); + + __block BOOL done = NO; + + [readRef observeEventType:FIRDataEventTypeValue + withBlock:^(FIRDataSnapshot* snapshot) { + id value = [snapshot value]; + if (value != nil && [value isEqualToNumber:@42]) { + done = YES; + } + }]; + + [writeRef setValue:@42 + withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) { + XCTAssertNil(error); + }]; + + WAIT_FOR(done); + done = NO; + + [writeRef setValue:@43 + withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) { + XCTAssertNil(error); + done = YES; + }]; + + WAIT_FOR(done); + done = NO; + + [readRef getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) { + XCTAssertNil(err); + XCTAssertEqualObjects(snapshot.value, @43); + done = YES; + }]; + + WAIT_FOR(done); +} + +- (void)testGetUpdatesPersistenceCacheWhenEnabled { + NSString* url = + [NSString stringWithFormat:kFirebaseDatabaseEmulatorUrlFmt, [[NSUUID UUID] UUIDString]]; + id writerApp = [[FIRFakeApp alloc] initWithName:@"writer" URL:url]; + id readerApp = [[FIRFakeApp alloc] initWithName:@"reader" URL:url]; + FIRDatabase* writer = [FIRDatabase databaseForApp:writerApp]; + FIRDatabase* reader = [FIRDatabase databaseForApp:readerApp]; + [reader setPersistenceEnabled:true]; + + __block BOOL done = NO; + + [writer.reference setValue:@42 + withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) { + XCTAssertNil(error); + done = YES; + }]; + + WAIT_FOR(done); + done = NO; + + FIRDatabaseReference* ref = reader.reference; + + [ref getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) { + XCTAssertNil(err); + XCTAssertEqualObjects(snapshot.value, @42); + done = YES; + }]; + + WAIT_FOR(done); + done = NO; + + [reader goOffline]; + + [ref observeEventType:FIRDataEventTypeValue + withBlock:^(FIRDataSnapshot* snapshot) { + XCTAssertEqualObjects(snapshot.value, @42); + done = YES; + }]; + + WAIT_FOR(done); +} + @end From f59c837cc69dca00adef06a5cc05c551af390537 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Tue, 8 Dec 2020 13:53:09 -0500 Subject: [PATCH 05/16] some small fixes --- FirebaseDatabase/Sources/Constants/FConstants.h | 2 +- FirebaseDatabase/Sources/Constants/FConstants.m | 2 +- FirebaseDatabase/Sources/Core/FPersistentConnection.m | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/FirebaseDatabase/Sources/Constants/FConstants.h b/FirebaseDatabase/Sources/Constants/FConstants.h index ca627299596..723fdd4a518 100644 --- a/FirebaseDatabase/Sources/Constants/FConstants.h +++ b/FirebaseDatabase/Sources/Constants/FConstants.h @@ -32,6 +32,7 @@ FOUNDATION_EXPORT NSString *const kFWPRequestAction; FOUNDATION_EXPORT NSString *const kFWPResponseForRNData; FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatus; FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatusOk; +FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatusFailed; FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatusDataStale; FOUNDATION_EXPORT NSString *const kFWPResponseForActionData; FOUNDATION_EXPORT NSString *const kFWPResponseDataWarnings; @@ -148,7 +149,6 @@ FOUNDATION_EXPORT NSString *const kFInterruptReasonAuthExpired; FOUNDATION_EXPORT NSString *const kPayloadPriority; FOUNDATION_EXPORT NSString *const kPayloadValue; FOUNDATION_EXPORT NSString *const kPayloadMetadataPrefix; -FOUNDATION_EXPORT NSString *const kPayloadNull; #pragma mark - #pragma mark ServerValue constants diff --git a/FirebaseDatabase/Sources/Constants/FConstants.m b/FirebaseDatabase/Sources/Constants/FConstants.m index 1ef0e037694..7bfa57d368c 100644 --- a/FirebaseDatabase/Sources/Constants/FConstants.m +++ b/FirebaseDatabase/Sources/Constants/FConstants.m @@ -29,6 +29,7 @@ NSString *const kFWPResponseForRNData = @"b"; NSString *const kFWPResponseForActionStatus = @"s"; NSString *const kFWPResponseForActionStatusOk = @"ok"; +NSString *const kFWPResponseForActionStatusFailed = @"failed"; NSString *const kFWPResponseForActionStatusDataStale = @"datastale"; NSString *const kFWPResponseForActionData = @"d"; NSString *const kFWPResponseDataWarnings = @"w"; @@ -140,7 +141,6 @@ NSString *const kPayloadPriority = @".priority"; NSString *const kPayloadValue = @".value"; NSString *const kPayloadMetadataPrefix = @"."; -NSString *const kPayloadNull = @""; #pragma mark - #pragma mark ServerValue constants diff --git a/FirebaseDatabase/Sources/Core/FPersistentConnection.m b/FirebaseDatabase/Sources/Core/FPersistentConnection.m index a60b242e64f..72eafbce498 100644 --- a/FirebaseDatabase/Sources/Core/FPersistentConnection.m +++ b/FirebaseDatabase/Sources/Core/FPersistentConnection.m @@ -836,7 +836,7 @@ - (void)get:(NSString *)pathString } get.sent = YES; [self.outstandingGets removeObjectForKey:index]; - get.onCompleteBlock(@"failed", nil, kPersistentConnOffline); + get.onCompleteBlock(kFWPResponseForActionStatusFailed, nil, kPersistentConnOffline); }); return; } From 8b90241e8ac4a23591b536a8ba1606aa3b4284e2 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Tue, 8 Dec 2020 15:47:19 -0500 Subject: [PATCH 06/16] Fix tests --- .../Sources/Core/FPersistentConnection.m | 3 +- .../Tests/Integration/FIRDatabaseQueryTests.m | 65 ++++++++++--------- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/FirebaseDatabase/Sources/Core/FPersistentConnection.m b/FirebaseDatabase/Sources/Core/FPersistentConnection.m index 72eafbce498..8e6c207e90e 100644 --- a/FirebaseDatabase/Sources/Core/FPersistentConnection.m +++ b/FirebaseDatabase/Sources/Core/FPersistentConnection.m @@ -836,7 +836,8 @@ - (void)get:(NSString *)pathString } get.sent = YES; [self.outstandingGets removeObjectForKey:index]; - get.onCompleteBlock(kFWPResponseForActionStatusFailed, nil, kPersistentConnOffline); + get.onCompleteBlock(kFWPResponseForActionStatusFailed, nil, + kPersistentConnOffline); }); return; } diff --git a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m index 43ad04a0a54..5d8dda94a99 100644 --- a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m +++ b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m @@ -3150,22 +3150,27 @@ - (void)testQueryGetCached { WAIT_FOR(done); } -static NSString* kFirebaseDatabaseEmulatorUrlFmt = @"http://localhost:9000?ns=%@"; +- (FIRDatabase*)databaseForURL:(NSString*)url name:(NSString*)name { + NSString* defaultDatabaseURL = [NSString stringWithFormat:@"url:%@", self.databaseURL]; + if ([url isEqualToString:self.databaseURL] && [name isEqualToString:defaultDatabaseURL]) { + // Use the default app for the default URL to avoid getting out of sync with FRepoManager + // when calling ensureRepo during tests that don't create their own FIRFakeApp. + return [FTestHelpers defaultDatabase]; + } else { + id app = [[FIRFakeApp alloc] initWithName:name URL:url]; + return [FIRDatabase databaseForApp:app]; + } +} - (void)testGetRetrievesLatestValueEvenIfCached { - NSString* url = - [NSString stringWithFormat:kFirebaseDatabaseEmulatorUrlFmt, [[NSUUID UUID] UUIDString]]; - - id writerApp = [[FIRFakeApp alloc] initWithName:@"writer" URL:url]; - id readerApp = [[FIRFakeApp alloc] initWithName:@"reader" URL:url]; + FIRDatabase* db = [self databaseForURL:self.databaseURL name:[[NSUUID UUID] UUIDString]]; + FIRDatabase* db2 = [self databaseForURL:self.databaseURL name:[[NSUUID UUID] UUIDString]]; + XCTAssertNotEqual(db, db2); - FIRDatabase* db = [FIRDatabase databaseForApp:readerApp]; FIRDatabaseReference* readRef = [db reference]; - - FIRDatabase* db2 = [FIRDatabase databaseForApp:writerApp]; FIRDatabaseReference* writeRef = [db2 reference]; - XCTAssertNotEqual(db, db2); + XCTAssertNotEqual(readRef, writeRef); __block BOOL done = NO; @@ -3204,28 +3209,26 @@ - (void)testGetRetrievesLatestValueEvenIfCached { } - (void)testGetUpdatesPersistenceCacheWhenEnabled { - NSString* url = - [NSString stringWithFormat:kFirebaseDatabaseEmulatorUrlFmt, [[NSUUID UUID] UUIDString]]; - id writerApp = [[FIRFakeApp alloc] initWithName:@"writer" URL:url]; - id readerApp = [[FIRFakeApp alloc] initWithName:@"reader" URL:url]; - FIRDatabase* writer = [FIRDatabase databaseForApp:writerApp]; - FIRDatabase* reader = [FIRDatabase databaseForApp:readerApp]; - [reader setPersistenceEnabled:true]; + FIRDatabase* db = [self databaseForURL:self.databaseURL name:[[NSUUID UUID] UUIDString]]; + FIRDatabase* db2 = [self databaseForURL:self.databaseURL name:[[NSUUID UUID] UUIDString]]; + + [db2 setPersistenceEnabled:true]; + + FIRDatabaseReference* writeRef = [db reference]; + FIRDatabaseReference* readRef = [db2 reference]; __block BOOL done = NO; - [writer.reference setValue:@42 - withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) { - XCTAssertNil(error); - done = YES; - }]; + [writeRef setValue:@42 + withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) { + XCTAssertNil(error); + done = YES; + }]; WAIT_FOR(done); done = NO; - FIRDatabaseReference* ref = reader.reference; - - [ref getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) { + [readRef getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) { XCTAssertNil(err); XCTAssertEqualObjects(snapshot.value, @42); done = YES; @@ -3234,13 +3237,13 @@ - (void)testGetUpdatesPersistenceCacheWhenEnabled { WAIT_FOR(done); done = NO; - [reader goOffline]; + [db2 goOffline]; - [ref observeEventType:FIRDataEventTypeValue - withBlock:^(FIRDataSnapshot* snapshot) { - XCTAssertEqualObjects(snapshot.value, @42); - done = YES; - }]; + [readRef observeEventType:FIRDataEventTypeValue + withBlock:^(FIRDataSnapshot* snapshot) { + XCTAssertEqualObjects(snapshot.value, @42); + done = YES; + }]; WAIT_FOR(done); } From d3548c4845dbe289c40a32af00e5e2902eef9c06 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Fri, 11 Dec 2020 13:52:13 -0800 Subject: [PATCH 07/16] Review feedback --- FirebaseDatabase/CHANGELOG.md | 2 +- .../Sources/Api/FIRDatabaseQuery.m | 2 +- .../Sources/Constants/FConstants.h | 4 +- .../Sources/Constants/FConstants.m | 4 +- .../Sources/Core/FPersistentConnection.m | 47 ++++++++++--------- FirebaseDatabase/Sources/Core/FRepo.h | 2 +- FirebaseDatabase/Sources/Core/FRepo.m | 2 +- .../Tests/Integration/FIRDatabaseQueryTests.m | 8 +--- 8 files changed, 36 insertions(+), 35 deletions(-) diff --git a/FirebaseDatabase/CHANGELOG.md b/FirebaseDatabase/CHANGELOG.md index a7c5d9076a1..c1d88f0c84c 100644 --- a/FirebaseDatabase/CHANGELOG.md +++ b/FirebaseDatabase/CHANGELOG.md @@ -1,6 +1,6 @@ # Unreleased - [added] Made emulator connection API consistent between Auth, Database, Firestore, and Functions (#5916). -- [added] Implement RTDB Query get (#7110) +- [added] Added FIRDatabaseQuery#getDataWithCompletionBlock which returns data from the server when cache is stale (#7110). # v7.0.0 - [fixed] Disabled a deprecation warning. (#6502) diff --git a/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m b/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m index b93183d0b36..493fc09836c 100644 --- a/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m +++ b/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m @@ -584,7 +584,7 @@ - (void)keepSynced:(BOOL)keepSynced { - (void)getDataWithCompletionBlock:(void (^)(NSError *__nullable error, FIRDataSnapshot *snapshot))block { dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - [self.repo getValue:self withCompletionBlock:block]; + [self.repo getData:self withCompletionBlock:block]; }); } diff --git a/FirebaseDatabase/Sources/Constants/FConstants.h b/FirebaseDatabase/Sources/Constants/FConstants.h index 723fdd4a518..2cdaf042713 100644 --- a/FirebaseDatabase/Sources/Constants/FConstants.h +++ b/FirebaseDatabase/Sources/Constants/FConstants.h @@ -107,11 +107,11 @@ FOUNDATION_EXPORT NSString *const kFWPRequestStatus; FOUNDATION_EXPORT NSString *const kWireProtocolVersionParam; FOUNDATION_EXPORT NSString *const kWebsocketProtocolVersion; FOUNDATION_EXPORT NSString *const kWebsocketServerKillPacket; -FOUNDATION_EXPORT NSString *const kPersistentConnOffline; +FOUNDATION_EXPORT NSString *const kPersistentConnectionOffline; FOUNDATION_EXPORT const int kWebsocketMaxFrameSize; FOUNDATION_EXPORT NSUInteger const kWebsocketKeepaliveInterval; FOUNDATION_EXPORT NSUInteger const kWebsocketConnectTimeout; -FOUNDATION_EXPORT UInt64 const kPersistentConnGetConnectTimeout; +FOUNDATION_EXPORT UInt64 const kPersistentConnectionGetConnectTimeout; FOUNDATION_EXPORT float const kPersistentConnReconnectMinDelay; FOUNDATION_EXPORT float const kPersistentConnReconnectMaxDelay; diff --git a/FirebaseDatabase/Sources/Constants/FConstants.m b/FirebaseDatabase/Sources/Constants/FConstants.m index 7bfa57d368c..c3b76ad4da5 100644 --- a/FirebaseDatabase/Sources/Constants/FConstants.m +++ b/FirebaseDatabase/Sources/Constants/FConstants.m @@ -101,11 +101,11 @@ NSString *const kWireProtocolVersionParam = @"v"; NSString *const kWebsocketProtocolVersion = @"5"; NSString *const kWebsocketServerKillPacket = @"kill"; -NSString *const kPersistentConnOffline = @"Client is offline."; +NSString *const kPersistentConnectionOffline = @"Client is offline."; const int kWebsocketMaxFrameSize = 16384; NSUInteger const kWebsocketKeepaliveInterval = 45; NSUInteger const kWebsocketConnectTimeout = 30; -UInt64 const kPersistentConnGetConnectTimeout = 3 * NSEC_PER_SEC; +UInt64 const kPersistentConnectionGetConnectTimeout = 3 * NSEC_PER_SEC; float const kPersistentConnReconnectMinDelay = 1.0; float const kPersistentConnReconnectMaxDelay = 30.0; diff --git a/FirebaseDatabase/Sources/Core/FPersistentConnection.m b/FirebaseDatabase/Sources/Core/FPersistentConnection.m index 8e6c207e90e..771905df6bc 100644 --- a/FirebaseDatabase/Sources/Core/FPersistentConnection.m +++ b/FirebaseDatabase/Sources/Core/FPersistentConnection.m @@ -328,6 +328,7 @@ - (BOOL)canSendWrites { - (BOOL)canSendReads { return self->connectionState == ConnectionStateConnected; } + #pragma mark - #pragma mark FConnection delegate methods @@ -730,7 +731,8 @@ - (void)sendGet:(NSNumber *)index { NSAssert([self canSendReads], @"sendGet called when not able to send reads"); FOutstandingGet *get = self.outstandingGets[index]; - assert(get != nil); + NSAssert(get != nil, @"sendGet found no outstanding get at index %@", + index); if ([get sent]) { return; } @@ -827,26 +829,27 @@ - (void)get:(NSString *)pathString self.outstandingGets[index] = get; if (![self connected]) { - dispatch_after( - dispatch_time(DISPATCH_TIME_NOW, kPersistentConnGetConnectTimeout), - self.dispatchQueue, ^{ - FOutstandingGet *get = self.outstandingGets[index]; - if ([get sent]) { - return; - } - get.sent = YES; - [self.outstandingGets removeObjectForKey:index]; - get.onCompleteBlock(kFWPResponseForActionStatusFailed, nil, - kPersistentConnOffline); - }); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, + kPersistentConnectionGetConnectTimeout), + self.dispatchQueue, ^{ + FOutstandingGet *get = self.outstandingGets[index]; + if ([get sent]) { + return; + } + FFLog(@"I-RDB034045", + @"get %@ timed out waiting for a connection", + index); + get.sent = YES; + [self.outstandingGets removeObjectForKey:index]; + get.onCompleteBlock(kFWPResponseForActionStatusFailed, + nil, kPersistentConnectionOffline); + }); return; } if ([self canSendReads]) { FFLog(@"I-RDB034024", @"Was connected, and added as index: %@", index); [self sendGet:index]; - } else { - FFLog(@"I-RDB034025", @"Was connected, and added as index: %@", index); } } @@ -1089,12 +1092,13 @@ - (void)restoreState { [self sendListen:outstandingListen]; }]; - NSArray *keys = [[self.outstandingPuts allKeys] + NSArray *putKeys = [[self.outstandingPuts allKeys] sortedArrayUsingSelector:@selector(compare:)]; - for (int i = 0; i < [keys count]; i++) { - if ([self.outstandingPuts objectForKey:[keys objectAtIndex:i]] != nil) { + for (int i = 0; i < [putKeys count]; i++) { + if ([self.outstandingPuts objectForKey:[putKeys objectAtIndex:i]] != + nil) { FFLog(@"I-RDB034037", @"Restoring put: %d", i); - [self sendPut:[keys objectAtIndex:i]]; + [self sendPut:[putKeys objectAtIndex:i]]; } else { FFLog(@"I-RDB034038", @"Restoring put: skipped nil: %d", i); } @@ -1103,9 +1107,10 @@ - (void)restoreState { NSArray *getKeys = [[self.outstandingGets allKeys] sortedArrayUsingSelector:@selector(compare:)]; for (int i = 0; i < [getKeys count]; i++) { - if ([self.outstandingGets objectForKey:[keys objectAtIndex:i]] != nil) { + if ([self.outstandingGets objectForKey:[getKeys objectAtIndex:i]] != + nil) { FFLog(@"I-RDB034037", @"Restoring get: %d", i); - [self sendGet:[keys objectAtIndex:i]]; + [self sendGet:[getKeys objectAtIndex:i]]; } else { FFLog(@"I-RDB034038", @"Restoring get: skipped nil: %d", i); } diff --git a/FirebaseDatabase/Sources/Core/FRepo.h b/FirebaseDatabase/Sources/Core/FRepo.h index 7e58bf37d00..c626a1a49bd 100644 --- a/FirebaseDatabase/Sources/Core/FRepo.h +++ b/FirebaseDatabase/Sources/Core/FRepo.h @@ -46,7 +46,7 @@ withCallback:(fbt_void_nserror_ref)callback; - (void)purgeOutstandingWrites; -- (void)getValue:(FIRDatabaseQuery *)query +- (void)getData:(FIRDatabaseQuery *)query withCompletionBlock: (void (^_Nonnull)(NSError *__nullable error, FIRDataSnapshot *__nullable snapshot))block; diff --git a/FirebaseDatabase/Sources/Core/FRepo.m b/FirebaseDatabase/Sources/Core/FRepo.m index 7fa8685119e..160a8fc1911 100644 --- a/FirebaseDatabase/Sources/Core/FRepo.m +++ b/FirebaseDatabase/Sources/Core/FRepo.m @@ -513,7 +513,7 @@ - (void)purgeOutstandingWrites { [self.connection purgeOutstandingWrites]; } -- (void)getValue:(FIRDatabaseQuery *)query +- (void)getData:(FIRDatabaseQuery *)query withCompletionBlock: (void (^_Nonnull)(NSError *__nullable error, FIRDataSnapshot *__nullable snapshot))block { diff --git a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m index 5d8dda94a99..552b67d88df 100644 --- a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m +++ b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m @@ -14,12 +14,12 @@ * limitations under the License. */ -#import "FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.h" #import "FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h" #import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" #import "FirebaseDatabase/Sources/Constants/FConstants.h" #import "FirebaseDatabase/Sources/Core/FQuerySpec.h" #import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.h" #import "FirebaseDatabase/Tests/Helpers/FIRFakeApp.h" #import "FirebaseDatabase/Tests/Helpers/FTestExpectations.h" @@ -3083,7 +3083,7 @@ - (void)testOfflineQueryGet { [ref getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) { XCTAssertNotNil(err); - XCTAssertEqualObjects([err localizedFailureReason], kPersistentConnOffline); + XCTAssertEqualObjects([err localizedFailureReason], kPersistentConnectionOffline); done = YES; }]; @@ -3127,13 +3127,9 @@ - (void)testQueryGetCached { } }]; - WAIT_FOR(done); - done = NO; - [ref setValue:@42 withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) { XCTAssertNil(error); - done = YES; }]; WAIT_FOR(done); From 76a544c6b75446db65b0637395b64225ec7ea39b Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Tue, 15 Dec 2020 17:01:08 -0800 Subject: [PATCH 08/16] Address review feedback + fixup tests --- .../Sources/Core/FPersistentConnection.h | 6 +- .../Sources/Core/FPersistentConnection.m | 9 +- FirebaseDatabase/Sources/Core/FRepo.m | 88 ++++++++++--------- .../Tests/Integration/FIRDatabaseQueryTests.m | 4 +- 4 files changed, 57 insertions(+), 50 deletions(-) diff --git a/FirebaseDatabase/Sources/Core/FPersistentConnection.h b/FirebaseDatabase/Sources/Core/FPersistentConnection.h index fb103357ec9..a40bcd61c2c 100644 --- a/FirebaseDatabase/Sources/Core/FPersistentConnection.h +++ b/FirebaseDatabase/Sources/Core/FPersistentConnection.h @@ -60,9 +60,9 @@ - (void)onDisconnectCancelPath:(FPath *)path withCallback:(fbt_void_nsstring_nsstring)callback; - (void)ackPuts; -- (void)get:(NSString *)pathString - withParams:(NSDictionary *)queryWireProtocolParams - withCallback:(fbt_void_nsstring_id_nsstring)onComplete; +- (void)getDataAtPath:(NSString *)pathString + withParams:(NSDictionary *)queryWireProtocolParams + withCallback:(fbt_void_nsstring_id_nsstring)onComplete; - (void)purgeOutstandingWrites; - (void)interruptForReason:(NSString *)reason; diff --git a/FirebaseDatabase/Sources/Core/FPersistentConnection.m b/FirebaseDatabase/Sources/Core/FPersistentConnection.m index 771905df6bc..3cc034ac276 100644 --- a/FirebaseDatabase/Sources/Core/FPersistentConnection.m +++ b/FirebaseDatabase/Sources/Core/FPersistentConnection.m @@ -747,6 +747,9 @@ - (void)sendGet:(NSNumber *)index { NSString *status = [data objectForKey:kFWPResponseForActionStatus]; id resultData = [data objectForKey:kFWPResponseForActionData]; + if (resultData == (id)[NSNull null]) { + resultData = nil; + } if ([status isEqualToString:kFWPResponseForActionStatusOk]) { get.onCompleteBlock(status, resultData, nil); return; @@ -813,9 +816,9 @@ - (void)putInternal:(id)data } } -- (void)get:(NSString *)pathString - withParams:(NSDictionary *)queryWireProtocolParams - withCallback:(fbt_void_nsstring_id_nsstring)onComplete { +- (void)getDataAtPath:(NSString *)pathString + withParams:(NSDictionary *)queryWireProtocolParams + withCallback:(fbt_void_nsstring_id_nsstring)onComplete { NSMutableDictionary *request = [NSMutableDictionary dictionaryWithObjectsAndKeys:pathString, kFWPRequestPath, queryWireProtocolParams, diff --git a/FirebaseDatabase/Sources/Core/FRepo.m b/FirebaseDatabase/Sources/Core/FRepo.m index 160a8fc1911..d05137188c1 100644 --- a/FirebaseDatabase/Sources/Core/FRepo.m +++ b/FirebaseDatabase/Sources/Core/FRepo.m @@ -520,48 +520,52 @@ - (void)getData:(FIRDatabaseQuery *)query FQuerySpec *querySpec = [query querySpec]; [self.persistenceManager setQueryActive:querySpec]; [self.connection - get:[query.path toString] - withParams:querySpec.params.wireProtocolParams - withCallback:^(NSString *status, id data, NSString *errorReason) { - id node; - if (![status isEqualToString:kFWPResponseForActionStatusOk]) { - FFLog(@"I-RDB038024", - @"getValue for query %@ falling back to cache", - [querySpec.path toString]); - node = [self.serverSyncTree - calcCompleteEventCacheAtPath:querySpec.path - excludeWriteIds:@[]]; - if ([node isEmpty]) { - FFWarn(@"I-RDB038025", @"getValue for query at %@ failed: %@", - [querySpec.path toString], status); - NSDictionary *errorDict = @{ - NSLocalizedFailureReasonErrorKey : errorReason, - NSLocalizedDescriptionKey : [NSString - stringWithFormat: - @"Unable to get latest value for query %@, " - @"client offline and cache is empty", - querySpec] - }; - block([NSError errorWithDomain:kFirebaseCoreErrorDomain - code:1 - userInfo:errorDict], - nil); - return; - } - } else { - node = [FSnapshotUtilities nodeFrom:data]; - } - [self.eventRaiser - raiseEvents:[self.serverSyncTree - applyServerOverwriteAtPath:[query path] - newData:node]]; - block(nil, [[FIRDataSnapshot alloc] - initWithRef:query.ref - indexedNode:[FIndexedNode - indexedNodeWithNode:node - index:querySpec.index]]); - [self.persistenceManager setQueryInactive:querySpec]; - }]; + getDataAtPath:[query.path toString] + withParams:querySpec.params.wireProtocolParams + withCallback:^(NSString *status, id data, NSString *errorReason) { + id node; + if (![status isEqualToString:kFWPResponseForActionStatusOk]) { + FFLog(@"I-RDB038024", + @"getValue for query %@ falling back to cache", + [querySpec.path toString]); + node = [self.serverSyncTree + calcCompleteEventCacheAtPath:querySpec.path + excludeWriteIds:@[]]; + if ([node isEmpty]) { + FFWarn(@"I-RDB038025", + @"getValue for query at %@ failed: %@", + [querySpec.path toString], status); + NSDictionary *errorDict = @{ + NSLocalizedFailureReasonErrorKey : errorReason, + NSLocalizedDescriptionKey : [NSString + stringWithFormat: + @"Unable to get latest value for query %@, " + @"client offline and cache is empty", + querySpec] + }; + block([NSError errorWithDomain:kFirebaseCoreErrorDomain + code:1 + userInfo:errorDict], + nil); + return; + } + } else { + NSLog(@"Creating node from data = %d", data == nil); + node = [FSnapshotUtilities nodeFrom:data]; + NSLog(@"node = %@, %d", node, [node isEmpty]); + } + [self.eventRaiser + raiseEvents:[self.serverSyncTree + applyServerOverwriteAtPath:[query path] + newData:node]]; + block(nil, + [[FIRDataSnapshot alloc] + initWithRef:query.ref + indexedNode:[FIndexedNode + indexedNodeWithNode:node + index:querySpec.index]]); + [self.persistenceManager setQueryInactive:querySpec]; + }]; } - (void)addEventRegistration:(id)eventRegistration diff --git a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m index 552b67d88df..4a793a24b58 100644 --- a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m +++ b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m @@ -14,12 +14,12 @@ * limitations under the License. */ +#import "FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.h" #import "FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h" #import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" #import "FirebaseDatabase/Sources/Constants/FConstants.h" #import "FirebaseDatabase/Sources/Core/FQuerySpec.h" #import "FirebaseDatabase/Sources/Utilities/FUtilities.h" -#import "FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.h" #import "FirebaseDatabase/Tests/Helpers/FIRFakeApp.h" #import "FirebaseDatabase/Tests/Helpers/FTestExpectations.h" @@ -3066,7 +3066,7 @@ - (void)testEmptyQueryGet { __block BOOL done = NO; [ref getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) { - XCTAssertNil(snapshot.value); + XCTAssert([snapshot.value isEqual:[NSNull null]]); done = YES; }]; From c33d2c2273e5aed2b053d0829b1dd89e2ab896f9 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Tue, 15 Dec 2020 17:03:07 -0800 Subject: [PATCH 09/16] Remove extra logs --- FirebaseDatabase/Sources/Core/FRepo.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/FirebaseDatabase/Sources/Core/FRepo.m b/FirebaseDatabase/Sources/Core/FRepo.m index d05137188c1..2713419fd14 100644 --- a/FirebaseDatabase/Sources/Core/FRepo.m +++ b/FirebaseDatabase/Sources/Core/FRepo.m @@ -550,9 +550,7 @@ - (void)getData:(FIRDatabaseQuery *)query return; } } else { - NSLog(@"Creating node from data = %d", data == nil); node = [FSnapshotUtilities nodeFrom:data]; - NSLog(@"node = %@, %d", node, [node isEmpty]); } [self.eventRaiser raiseEvents:[self.serverSyncTree From 05784bfeb462fa7c80b54f620c00410baf358617 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Wed, 16 Dec 2020 14:48:18 -0800 Subject: [PATCH 10/16] Update FirebaseDatabase/Sources/Core/FPersistentConnection.m Co-authored-by: Sebastian Schmidt --- FirebaseDatabase/Sources/Core/FPersistentConnection.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseDatabase/Sources/Core/FPersistentConnection.m b/FirebaseDatabase/Sources/Core/FPersistentConnection.m index 3cc034ac276..26aea7fe515 100644 --- a/FirebaseDatabase/Sources/Core/FPersistentConnection.m +++ b/FirebaseDatabase/Sources/Core/FPersistentConnection.m @@ -851,7 +851,7 @@ - (void)getDataAtPath:(NSString *)pathString } if ([self canSendReads]) { - FFLog(@"I-RDB034024", @"Was connected, and added as index: %@", index); + FFLog(@"I-RDB034024", @"Sending get: %@", index); [self sendGet:index]; } } From 14ef2d7c5f5bfd41825e5e88ce5584eaf2c9ab6b Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Wed, 16 Dec 2020 15:16:04 -0800 Subject: [PATCH 11/16] Review feedback --- FirebaseDatabase/CHANGELOG.md | 2 +- .../Public/FirebaseDatabase/FIRDatabaseQuery.h | 3 ++- .../Tests/Integration/FIRDatabaseQueryTests.m | 11 +++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/FirebaseDatabase/CHANGELOG.md b/FirebaseDatabase/CHANGELOG.md index c1d88f0c84c..47ebdb2e1fa 100644 --- a/FirebaseDatabase/CHANGELOG.md +++ b/FirebaseDatabase/CHANGELOG.md @@ -1,6 +1,6 @@ # Unreleased - [added] Made emulator connection API consistent between Auth, Database, Firestore, and Functions (#5916). -- [added] Added FIRDatabaseQuery#getDataWithCompletionBlock which returns data from the server when cache is stale (#7110). +- [added] Added `FIRDatabaseQuery#getData` which returns data from the server when cache is stale (#7110). # v7.0.0 - [fixed] Disabled a deprecation warning. (#6502) diff --git a/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h b/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h index c2ec7c67553..0c9097fb733 100644 --- a/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h +++ b/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h @@ -133,7 +133,8 @@ NS_SWIFT_NAME(DatabaseQuery) - (void)getDataWithCompletionBlock: (void (^_Nonnull)(NSError *__nullable error, - FIRDataSnapshot *snapshot))block; + FIRDataSnapshot *snapshot))block + NS_SWIFT_NAME(getData(completion:)); /** * This is equivalent to observeEventType:withBlock:, except the block is diff --git a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m index 4a793a24b58..4f1e3dad059 100644 --- a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m +++ b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m @@ -3074,8 +3074,8 @@ - (void)testEmptyQueryGet { } - (void)testOfflineQueryGet { - FIRDatabase* db = [FTestHelpers defaultDatabase]; - FIRDatabaseReference* ref = [db reference]; + FIRDatabaseReference* ref = [FTestHelpers getRandomNode]; + FIRDatabase* db = [ref database]; __block BOOL done = NO; @@ -3091,8 +3091,7 @@ - (void)testOfflineQueryGet { } - (void)testGetQueryBasic { - FIRDatabase* db = [FTestHelpers defaultDatabase]; - FIRDatabaseReference* ref = [db reference]; + FIRDatabaseReference* ref = [FTestHelpers getRandomNode]; __block BOOL done = NO; @@ -3114,8 +3113,8 @@ - (void)testGetQueryBasic { } - (void)testQueryGetCached { - FIRDatabase* db = [FTestHelpers defaultDatabase]; - FIRDatabaseReference* ref = [db reference]; + FIRDatabaseReference* ref = [FTestHelpers getRandomNode]; + FIRDatabase* db = [ref database]; __block BOOL done = NO; From 253f14cdba830d25b05d86257afbc6847d02c51e Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Wed, 16 Dec 2020 16:08:18 -0800 Subject: [PATCH 12/16] Write to unique paths --- .../Tests/Integration/FIRDatabaseQueryTests.m | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m index 4f1e3dad059..8c4cda14f7b 100644 --- a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m +++ b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m @@ -3126,10 +3126,7 @@ - (void)testQueryGetCached { } }]; - [ref setValue:@42 - withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) { - XCTAssertNil(error); - }]; + [self waitForCompletionOf:ref setValue:@42]; WAIT_FOR(done); done = NO; @@ -3160,10 +3157,13 @@ - (FIRDatabase*)databaseForURL:(NSString*)url name:(NSString*)name { - (void)testGetRetrievesLatestValueEvenIfCached { FIRDatabase* db = [self databaseForURL:self.databaseURL name:[[NSUUID UUID] UUIDString]]; FIRDatabase* db2 = [self databaseForURL:self.databaseURL name:[[NSUUID UUID] UUIDString]]; + XCTAssertNotEqual(db, db2); - FIRDatabaseReference* readRef = [db reference]; - FIRDatabaseReference* writeRef = [db2 reference]; + NSString* uuidPath = [[NSUUID UUID] UUIDString]; + + FIRDatabaseReference* readRef = [db referenceWithPath:uuidPath]; + FIRDatabaseReference* writeRef = [db2 referenceWithPath:uuidPath]; XCTAssertNotEqual(readRef, writeRef); @@ -3177,10 +3177,7 @@ - (void)testGetRetrievesLatestValueEvenIfCached { } }]; - [writeRef setValue:@42 - withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) { - XCTAssertNil(error); - }]; + [self waitForCompletionOf:writeRef setValue:@42]; WAIT_FOR(done); done = NO; @@ -3209,8 +3206,10 @@ - (void)testGetUpdatesPersistenceCacheWhenEnabled { [db2 setPersistenceEnabled:true]; - FIRDatabaseReference* writeRef = [db reference]; - FIRDatabaseReference* readRef = [db2 reference]; + NSString* uuidPath = [[NSUUID UUID] UUIDString]; + + FIRDatabaseReference* writeRef = [db referenceWithPath:uuidPath]; + FIRDatabaseReference* readRef = [db2 referenceWithPath:uuidPath]; __block BOOL done = NO; From 2546839667ddfd3e4c8517d55c0fe52cd5071665 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Thu, 17 Dec 2020 14:33:05 -0800 Subject: [PATCH 13/16] Removed FIR prefix --- FirebaseDatabase/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseDatabase/CHANGELOG.md b/FirebaseDatabase/CHANGELOG.md index 47ebdb2e1fa..0b046e4e4f0 100644 --- a/FirebaseDatabase/CHANGELOG.md +++ b/FirebaseDatabase/CHANGELOG.md @@ -1,6 +1,6 @@ # Unreleased - [added] Made emulator connection API consistent between Auth, Database, Firestore, and Functions (#5916). -- [added] Added `FIRDatabaseQuery#getData` which returns data from the server when cache is stale (#7110). +- [added] Added `DatabaseQuery#getData` which returns data from the server when cache is stale (#7110). # v7.0.0 - [fixed] Disabled a deprecation warning. (#6502) From 953112c61151c6496ce293f16107aec9af759d67 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Mon, 21 Dec 2020 19:25:08 -0800 Subject: [PATCH 14/16] Add _Nullable specifiers in FRepo.h --- FirebaseDatabase/Sources/Core/FRepo.h | 82 +++++++++++++-------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/FirebaseDatabase/Sources/Core/FRepo.h b/FirebaseDatabase/Sources/Core/FRepo.h index c626a1a49bd..f585d67f28c 100644 --- a/FirebaseDatabase/Sources/Core/FRepo.h +++ b/FirebaseDatabase/Sources/Core/FRepo.h @@ -32,68 +32,68 @@ @interface FRepo : NSObject -@property(nonatomic, strong) FIRDatabaseConfig *config; - -- (id)initWithRepoInfo:(FRepoInfo *)info - config:(FIRDatabaseConfig *)config - database:(FIRDatabase *)database; - -- (void)set:(FPath *)path - withNode:(id)node - withCallback:(fbt_void_nserror_ref)onComplete; -- (void)update:(FPath *)path - withNodes:(FCompoundWrite *)compoundWrite - withCallback:(fbt_void_nserror_ref)callback; +@property(nonatomic, strong) FIRDatabaseConfig * _Nullable config; + +- (id _Nonnull)initWithRepoInfo:(FRepoInfo * _Nullable)info + config:(FIRDatabaseConfig * _Nullable)config + database:(FIRDatabase * _Nullable)database; + +- (void)set:(FPath * _Nullable)path + withNode:(id _Nullable)node + withCallback:(fbt_void_nserror_ref _Nullable)onComplete; +- (void)update:(FPath * _Nullable)path + withNodes:(FCompoundWrite * _Nullable)compoundWrite + withCallback:(fbt_void_nserror_ref _Nullable)callback; - (void)purgeOutstandingWrites; -- (void)getData:(FIRDatabaseQuery *)query +- (void)getData:(FIRDatabaseQuery * _Nullable)query withCompletionBlock: - (void (^_Nonnull)(NSError *__nullable error, - FIRDataSnapshot *__nullable snapshot))block; + (void (^_Nonnull)(NSError * _Nullable error, + FIRDataSnapshot *_Nullable snapshot))block; -- (void)addEventRegistration:(id)eventRegistration - forQuery:(FQuerySpec *)query; -- (void)removeEventRegistration:(id)eventRegistration - forQuery:(FQuerySpec *)query; -- (void)keepQuery:(FQuerySpec *)query synced:(BOOL)synced; +- (void)addEventRegistration:(id _Nullable)eventRegistration + forQuery:(FQuerySpec * _Nullable)query; +- (void)removeEventRegistration:(id _Nullable)eventRegistration + forQuery:(FQuerySpec * _Nullable)query; +- (void)keepQuery:(FQuerySpec * _Nullable)query synced:(BOOL)synced; -- (NSString *)name; +- (NSString * _Nullable)name; - (NSTimeInterval)serverTime; -- (void)onDataUpdate:(FPersistentConnection *)fpconnection - forPath:(NSString *)pathString - message:(id)message +- (void)onDataUpdate:(FPersistentConnection * _Nullable)fpconnection + forPath:(NSString * _Nullable)pathString + message:(id _Nullable)message isMerge:(BOOL)isMerge - tagId:(NSNumber *)tagId; -- (void)onConnect:(FPersistentConnection *)fpconnection; -- (void)onDisconnect:(FPersistentConnection *)fpconnection; + tagId:(NSNumber * _Nullable)tagId; +- (void)onConnect:(FPersistentConnection * _Nullable)fpconnection; +- (void)onDisconnect:(FPersistentConnection * _Nullable)fpconnection; // Disconnect methods -- (void)onDisconnectCancel:(FPath *)path - withCallback:(fbt_void_nserror_ref)callback; -- (void)onDisconnectSet:(FPath *)path - withNode:(id)node - withCallback:(fbt_void_nserror_ref)callback; -- (void)onDisconnectUpdate:(FPath *)path - withNodes:(FCompoundWrite *)compoundWrite - withCallback:(fbt_void_nserror_ref)callback; +- (void)onDisconnectCancel:(FPath * _Nullable)path + withCallback:(fbt_void_nserror_ref _Nullable)callback; +- (void)onDisconnectSet:(FPath * _Nullable)path + withNode:(id _Nullable)node + withCallback:(fbt_void_nserror_ref _Nullable)callback; +- (void)onDisconnectUpdate:(FPath * _Nullable)path + withNodes:(FCompoundWrite * _Nullable)compoundWrite + withCallback:(fbt_void_nserror_ref _Nullable)callback; // Connection Management. - (void)interrupt; - (void)resume; // Transactions -- (void)startTransactionOnPath:(FPath *)path - update:(fbt_transactionresult_mutabledata)update - onComplete:(fbt_void_nserror_bool_datasnapshot)onComplete +- (void)startTransactionOnPath:(FPath * _Nullable)path + update:(fbt_transactionresult_mutabledata _Nullable)update + onComplete:(fbt_void_nserror_bool_datasnapshot _Nullable)onComplete withLocalEvents:(BOOL)applyLocally; // Testing methods -- (NSDictionary *)dumpListens; +- (NSDictionary * _Nullable)dumpListens; - (void)dispose; - (void)setHijackHash:(BOOL)hijack; -@property(nonatomic, strong, readonly) FAuthenticationManager *auth; -@property(nonatomic, strong, readonly) FIRDatabase *database; +@property(nonatomic, strong, readonly) FAuthenticationManager * _Nullable auth; +@property(nonatomic, strong, readonly) FIRDatabase * _Nullable database; @end From f7df365e2db3796f6887965b684ce0f7a69e0857 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Mon, 21 Dec 2020 19:35:17 -0800 Subject: [PATCH 15/16] format nullability stuff --- FirebaseDatabase/Sources/Core/FRepo.h | 61 ++++++++++++++------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/FirebaseDatabase/Sources/Core/FRepo.h b/FirebaseDatabase/Sources/Core/FRepo.h index f585d67f28c..94adbc2d4df 100644 --- a/FirebaseDatabase/Sources/Core/FRepo.h +++ b/FirebaseDatabase/Sources/Core/FRepo.h @@ -32,50 +32,51 @@ @interface FRepo : NSObject -@property(nonatomic, strong) FIRDatabaseConfig * _Nullable config; +@property(nonatomic, strong) FIRDatabaseConfig *_Nullable config; -- (id _Nonnull)initWithRepoInfo:(FRepoInfo * _Nullable)info - config:(FIRDatabaseConfig * _Nullable)config - database:(FIRDatabase * _Nullable)database; +- (id _Nonnull)initWithRepoInfo:(FRepoInfo *_Nullable)info + config:(FIRDatabaseConfig *_Nullable)config + database:(FIRDatabase *_Nullable)database; -- (void)set:(FPath * _Nullable)path +- (void)set:(FPath *_Nullable)path withNode:(id _Nullable)node withCallback:(fbt_void_nserror_ref _Nullable)onComplete; -- (void)update:(FPath * _Nullable)path - withNodes:(FCompoundWrite * _Nullable)compoundWrite +- (void)update:(FPath *_Nullable)path + withNodes:(FCompoundWrite *_Nullable)compoundWrite withCallback:(fbt_void_nserror_ref _Nullable)callback; - (void)purgeOutstandingWrites; -- (void)getData:(FIRDatabaseQuery * _Nullable)query +- (void)getData:(FIRDatabaseQuery *_Nullable)query withCompletionBlock: - (void (^_Nonnull)(NSError * _Nullable error, + (void (^_Nonnull)(NSError *_Nullable error, FIRDataSnapshot *_Nullable snapshot))block; - (void)addEventRegistration:(id _Nullable)eventRegistration - forQuery:(FQuerySpec * _Nullable)query; -- (void)removeEventRegistration:(id _Nullable)eventRegistration - forQuery:(FQuerySpec * _Nullable)query; -- (void)keepQuery:(FQuerySpec * _Nullable)query synced:(BOOL)synced; + forQuery:(FQuerySpec *_Nullable)query; +- (void)removeEventRegistration: + (id _Nullable)eventRegistration + forQuery:(FQuerySpec *_Nullable)query; +- (void)keepQuery:(FQuerySpec *_Nullable)query synced:(BOOL)synced; -- (NSString * _Nullable)name; +- (NSString *_Nullable)name; - (NSTimeInterval)serverTime; -- (void)onDataUpdate:(FPersistentConnection * _Nullable)fpconnection - forPath:(NSString * _Nullable)pathString +- (void)onDataUpdate:(FPersistentConnection *_Nullable)fpconnection + forPath:(NSString *_Nullable)pathString message:(id _Nullable)message isMerge:(BOOL)isMerge - tagId:(NSNumber * _Nullable)tagId; -- (void)onConnect:(FPersistentConnection * _Nullable)fpconnection; -- (void)onDisconnect:(FPersistentConnection * _Nullable)fpconnection; + tagId:(NSNumber *_Nullable)tagId; +- (void)onConnect:(FPersistentConnection *_Nullable)fpconnection; +- (void)onDisconnect:(FPersistentConnection *_Nullable)fpconnection; // Disconnect methods -- (void)onDisconnectCancel:(FPath * _Nullable)path +- (void)onDisconnectCancel:(FPath *_Nullable)path withCallback:(fbt_void_nserror_ref _Nullable)callback; -- (void)onDisconnectSet:(FPath * _Nullable)path +- (void)onDisconnectSet:(FPath *_Nullable)path withNode:(id _Nullable)node withCallback:(fbt_void_nserror_ref _Nullable)callback; -- (void)onDisconnectUpdate:(FPath * _Nullable)path - withNodes:(FCompoundWrite * _Nullable)compoundWrite +- (void)onDisconnectUpdate:(FPath *_Nullable)path + withNodes:(FCompoundWrite *_Nullable)compoundWrite withCallback:(fbt_void_nserror_ref _Nullable)callback; // Connection Management. @@ -83,17 +84,19 @@ - (void)resume; // Transactions -- (void)startTransactionOnPath:(FPath * _Nullable)path - update:(fbt_transactionresult_mutabledata _Nullable)update - onComplete:(fbt_void_nserror_bool_datasnapshot _Nullable)onComplete +- (void)startTransactionOnPath:(FPath *_Nullable)path + update: + (fbt_transactionresult_mutabledata _Nullable)update + onComplete: + (fbt_void_nserror_bool_datasnapshot _Nullable)onComplete withLocalEvents:(BOOL)applyLocally; // Testing methods -- (NSDictionary * _Nullable)dumpListens; +- (NSDictionary *_Nullable)dumpListens; - (void)dispose; - (void)setHijackHash:(BOOL)hijack; -@property(nonatomic, strong, readonly) FAuthenticationManager * _Nullable auth; -@property(nonatomic, strong, readonly) FIRDatabase * _Nullable database; +@property(nonatomic, strong, readonly) FAuthenticationManager *_Nullable auth; +@property(nonatomic, strong, readonly) FIRDatabase *_Nullable database; @end From ce0e21ea09baa673aed2e374e458a797a8913571 Mon Sep 17 00:00:00 2001 From: Jan Wyszynski Date: Tue, 22 Dec 2020 10:08:23 -0800 Subject: [PATCH 16/16] fix get cache test --- FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m index 8c4cda14f7b..7606b12d437 100644 --- a/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m +++ b/FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m @@ -3169,16 +3169,16 @@ - (void)testGetRetrievesLatestValueEvenIfCached { __block BOOL done = NO; + [self waitForCompletionOf:writeRef setValue:@42]; + [readRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot* snapshot) { - id value = [snapshot value]; + NSNumber* value = [snapshot value]; if (value != nil && [value isEqualToNumber:@42]) { done = YES; } }]; - [self waitForCompletionOf:writeRef setValue:@42]; - WAIT_FOR(done); done = NO;