Skip to content

Commit 55f27b5

Browse files
Implement RTDB Query get (#7110)
* Implement RTDB Query get * changelog * Mark query inactive after callback * Add tests, fix some issues * some small fixes * Fix tests * Review feedback * Address review feedback + fixup tests * Remove extra logs * Update FirebaseDatabase/Sources/Core/FPersistentConnection.m Co-authored-by: Sebastian Schmidt <[email protected]> * Review feedback * Write to unique paths * Removed FIR prefix * Add _Nullable specifiers in FRepo.h * format nullability stuff * fix get cache test Co-authored-by: Sebastian Schmidt <[email protected]>
1 parent 6553d37 commit 55f27b5

File tree

11 files changed

+424
-40
lines changed

11 files changed

+424
-40
lines changed

FirebaseDatabase/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# v7.2.0
22
- [added] Made emulator connection API consistent between Auth, Database, Firestore, and Functions (#5916).
3+
- [added] Added `DatabaseQuery#getData` which returns data from the server when cache is stale (#7110).
34

45
# v7.0.0
56
- [fixed] Disabled a deprecation warning. (#6502)

FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,13 @@ - (void)keepSynced:(BOOL)keepSynced {
581581
});
582582
}
583583

584+
- (void)getDataWithCompletionBlock:(void (^)(NSError *__nullable error,
585+
FIRDataSnapshot *snapshot))block {
586+
dispatch_async([FIRDatabaseQuery sharedQueue], ^{
587+
[self.repo getData:self withCompletionBlock:block];
588+
});
589+
}
590+
584591
- (void)observeSingleEventOfType:(FIRDataEventType)eventType
585592
withBlock:(fbt_void_datasnapshot)block {
586593

FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ typedef BOOL (^fbt_bool_nsstring_node)(NSString *, id<FNode>);
4646
typedef void (^fbt_void_path_node_marray)(FPath *, id<FNode>, NSMutableArray *);
4747
typedef BOOL (^fbt_bool_void)(void);
4848
typedef void (^fbt_void_nsstring_nsstring)(NSString *str1, NSString *str2);
49+
typedef void (^fbt_void_nsstring_id_nsstring)(NSString *str1, id dict1,
50+
NSString *str2);
4951
typedef void (^fbt_void_nsstring_nserror)(NSString *str, NSError *error);
5052
typedef BOOL (^fbt_bool_path)(FPath *str);
5153
typedef void (^fbt_void_id)(id data);

FirebaseDatabase/Sources/Constants/FConstants.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ FOUNDATION_EXPORT NSString *const kFWPRequestAction;
3232
FOUNDATION_EXPORT NSString *const kFWPResponseForRNData;
3333
FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatus;
3434
FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatusOk;
35+
FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatusFailed;
3536
FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatusDataStale;
3637
FOUNDATION_EXPORT NSString *const kFWPResponseForActionData;
3738
FOUNDATION_EXPORT NSString *const kFWPResponseDataWarnings;
@@ -75,6 +76,7 @@ FOUNDATION_EXPORT NSString *const kFWPAsyncServerControlMessageReset;
7576

7677
FOUNDATION_EXPORT NSString *const kFWPRequestActionPut;
7778
FOUNDATION_EXPORT NSString *const kFWPRequestActionMerge;
79+
FOUNDATION_EXPORT NSString *const kFWPRequestActionGet;
7880
FOUNDATION_EXPORT NSString *const kFWPRequestActionTaggedListen;
7981
FOUNDATION_EXPORT NSString *const kFWPRequestActionTaggedUnlisten;
8082
FOUNDATION_EXPORT NSString
@@ -105,9 +107,11 @@ FOUNDATION_EXPORT NSString *const kFWPRequestStatus;
105107
FOUNDATION_EXPORT NSString *const kWireProtocolVersionParam;
106108
FOUNDATION_EXPORT NSString *const kWebsocketProtocolVersion;
107109
FOUNDATION_EXPORT NSString *const kWebsocketServerKillPacket;
110+
FOUNDATION_EXPORT NSString *const kPersistentConnectionOffline;
108111
FOUNDATION_EXPORT const int kWebsocketMaxFrameSize;
109112
FOUNDATION_EXPORT NSUInteger const kWebsocketKeepaliveInterval;
110113
FOUNDATION_EXPORT NSUInteger const kWebsocketConnectTimeout;
114+
FOUNDATION_EXPORT UInt64 const kPersistentConnectionGetConnectTimeout;
111115

112116
FOUNDATION_EXPORT float const kPersistentConnReconnectMinDelay;
113117
FOUNDATION_EXPORT float const kPersistentConnReconnectMaxDelay;

FirebaseDatabase/Sources/Constants/FConstants.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
NSString *const kFWPResponseForRNData = @"b";
3030
NSString *const kFWPResponseForActionStatus = @"s";
3131
NSString *const kFWPResponseForActionStatusOk = @"ok";
32+
NSString *const kFWPResponseForActionStatusFailed = @"failed";
3233
NSString *const kFWPResponseForActionStatusDataStale = @"datastale";
3334
NSString *const kFWPResponseForActionData = @"d";
3435
NSString *const kFWPResponseDataWarnings = @"w";
@@ -70,6 +71,7 @@
7071

7172
NSString *const kFWPRequestActionPut = @"p";
7273
NSString *const kFWPRequestActionMerge = @"m";
74+
NSString *const kFWPRequestActionGet = @"g";
7375
NSString *const kFWPRequestActionListen =
7476
@"l"; // {"t": "d", "d": {"r": 1, "a": "l", "b": { "p": "/" } } }
7577
NSString *const kFWPRequestActionUnlisten = @"u";
@@ -99,9 +101,11 @@
99101
NSString *const kWireProtocolVersionParam = @"v";
100102
NSString *const kWebsocketProtocolVersion = @"5";
101103
NSString *const kWebsocketServerKillPacket = @"kill";
104+
NSString *const kPersistentConnectionOffline = @"Client is offline.";
102105
const int kWebsocketMaxFrameSize = 16384;
103106
NSUInteger const kWebsocketKeepaliveInterval = 45;
104107
NSUInteger const kWebsocketConnectTimeout = 30;
108+
UInt64 const kPersistentConnectionGetConnectTimeout = 3 * NSEC_PER_SEC;
105109

106110
float const kPersistentConnReconnectMinDelay = 1.0;
107111
float const kPersistentConnReconnectMaxDelay = 30.0;

FirebaseDatabase/Sources/Core/FPersistentConnection.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@
6060
- (void)onDisconnectCancelPath:(FPath *)path
6161
withCallback:(fbt_void_nsstring_nsstring)callback;
6262
- (void)ackPuts;
63+
- (void)getDataAtPath:(NSString *)pathString
64+
withParams:(NSDictionary *)queryWireProtocolParams
65+
withCallback:(fbt_void_nsstring_id_nsstring)onComplete;
6366
- (void)purgeOutstandingWrites;
6467

6568
- (void)interruptForReason:(NSString *)reason;

FirebaseDatabase/Sources/Core/FPersistentConnection.m

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ @implementation FOutstandingPut
6464

6565
@end
6666

67+
@interface FOutstandingGet : NSObject
68+
69+
@property(nonatomic, strong) NSDictionary *request;
70+
@property(nonatomic, copy) fbt_void_nsstring_id_nsstring onCompleteBlock;
71+
@property(nonatomic) BOOL sent;
72+
73+
@end
74+
75+
@implementation FOutstandingGet
76+
77+
@end
78+
6779
typedef enum {
6880
ConnectionStateDisconnected,
6981
ConnectionStateGettingToken,
@@ -92,9 +104,11 @@ - (void)sendOnDisconnectAction:(NSString *)action
92104
@property(nonatomic, strong) FConnection *realtime;
93105
@property(nonatomic, strong) NSMutableDictionary *listens;
94106
@property(nonatomic, strong) NSMutableDictionary *outstandingPuts;
107+
@property(nonatomic, strong) NSMutableDictionary *outstandingGets;
95108
@property(nonatomic, strong) NSMutableArray *onDisconnectQueue;
96109
@property(nonatomic, strong) FRepoInfo *repoInfo;
97110
@property(nonatomic, strong) FAtomicNumber *putCounter;
111+
@property(nonatomic, strong) FAtomicNumber *getCounter;
98112
@property(nonatomic, strong) FAtomicNumber *requestNumber;
99113
@property(nonatomic, strong) NSMutableDictionary *requestCBHash;
100114
@property(nonatomic, strong) FIRDatabaseConfig *config;
@@ -128,8 +142,10 @@ - (id)initWithRepoInfo:(FRepoInfo *)repoInfo
128142

129143
self.listens = [[NSMutableDictionary alloc] init];
130144
self.outstandingPuts = [[NSMutableDictionary alloc] init];
145+
self.outstandingGets = [[NSMutableDictionary alloc] init];
131146
self.onDisconnectQueue = [[NSMutableArray alloc] init];
132147
self.putCounter = [[FAtomicNumber alloc] init];
148+
self.getCounter = [[FAtomicNumber alloc] init];
133149
self.requestNumber = [[FAtomicNumber alloc] init];
134150
self.requestCBHash = [[NSMutableDictionary alloc] init];
135151
self.unackedListensCount = 0;
@@ -309,6 +325,10 @@ - (BOOL)canSendWrites {
309325
return self->connectionState == ConnectionStateConnected;
310326
}
311327

328+
- (BOOL)canSendReads {
329+
return self->connectionState == ConnectionStateConnected;
330+
}
331+
312332
#pragma mark -
313333
#pragma mark FConnection delegate methods
314334

@@ -707,6 +727,43 @@ - (void)sendPut:(NSNumber *)index {
707727
}];
708728
}
709729

730+
- (void)sendGet:(NSNumber *)index {
731+
NSAssert([self canSendReads],
732+
@"sendGet called when not able to send reads");
733+
FOutstandingGet *get = self.outstandingGets[index];
734+
NSAssert(get != nil, @"sendGet found no outstanding get at index %@",
735+
index);
736+
if ([get sent]) {
737+
return;
738+
}
739+
get.sent = YES;
740+
[self sendAction:kFWPRequestActionGet
741+
body:get.request
742+
sensitive:NO
743+
callback:^(NSDictionary *data) {
744+
FOutstandingGet *currentGet = self.outstandingGets[index];
745+
if (currentGet == get) {
746+
[self.outstandingGets removeObjectForKey:index];
747+
NSString *status =
748+
[data objectForKey:kFWPResponseForActionStatus];
749+
id resultData = [data objectForKey:kFWPResponseForActionData];
750+
if (resultData == (id)[NSNull null]) {
751+
resultData = nil;
752+
}
753+
if ([status isEqualToString:kFWPResponseForActionStatusOk]) {
754+
get.onCompleteBlock(status, resultData, nil);
755+
return;
756+
}
757+
get.onCompleteBlock(status, nil, resultData);
758+
} else {
759+
FFLog(@"I-RDB034045",
760+
@"Ignoring on complete for get %@ because it was "
761+
@"already removed",
762+
index);
763+
}
764+
}];
765+
}
766+
710767
- (void)sendUnlisten:(FPath *)path
711768
queryParams:(FQueryParams *)queryParams
712769
tagId:(NSNumber *)tagId {
@@ -759,6 +816,46 @@ - (void)putInternal:(id)data
759816
}
760817
}
761818

819+
- (void)getDataAtPath:(NSString *)pathString
820+
withParams:(NSDictionary *)queryWireProtocolParams
821+
withCallback:(fbt_void_nsstring_id_nsstring)onComplete {
822+
NSMutableDictionary *request = [NSMutableDictionary
823+
dictionaryWithObjectsAndKeys:pathString, kFWPRequestPath,
824+
queryWireProtocolParams,
825+
kFWPRequestQueries, nil];
826+
FOutstandingGet *get = [[FOutstandingGet alloc] init];
827+
get.request = request;
828+
get.onCompleteBlock = onComplete;
829+
get.sent = NO;
830+
831+
NSNumber *index = [self.getCounter getAndIncrement];
832+
self.outstandingGets[index] = get;
833+
834+
if (![self connected]) {
835+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
836+
kPersistentConnectionGetConnectTimeout),
837+
self.dispatchQueue, ^{
838+
FOutstandingGet *get = self.outstandingGets[index];
839+
if ([get sent]) {
840+
return;
841+
}
842+
FFLog(@"I-RDB034045",
843+
@"get %@ timed out waiting for a connection",
844+
index);
845+
get.sent = YES;
846+
[self.outstandingGets removeObjectForKey:index];
847+
get.onCompleteBlock(kFWPResponseForActionStatusFailed,
848+
nil, kPersistentConnectionOffline);
849+
});
850+
return;
851+
}
852+
853+
if ([self canSendReads]) {
854+
FFLog(@"I-RDB034024", @"Sending get: %@", index);
855+
[self sendGet:index];
856+
}
857+
}
858+
762859
- (void)sendListen:(FOutstandingQuery *)listenSpec {
763860
FQuerySpec *query = listenSpec.query;
764861
FFLog(@"I-RDB034026", @"Listen for %@", query);
@@ -998,17 +1095,30 @@ - (void)restoreState {
9981095
[self sendListen:outstandingListen];
9991096
}];
10001097

1001-
NSArray *keys = [[self.outstandingPuts allKeys]
1098+
NSArray *putKeys = [[self.outstandingPuts allKeys]
10021099
sortedArrayUsingSelector:@selector(compare:)];
1003-
for (int i = 0; i < [keys count]; i++) {
1004-
if ([self.outstandingPuts objectForKey:[keys objectAtIndex:i]] != nil) {
1100+
for (int i = 0; i < [putKeys count]; i++) {
1101+
if ([self.outstandingPuts objectForKey:[putKeys objectAtIndex:i]] !=
1102+
nil) {
10051103
FFLog(@"I-RDB034037", @"Restoring put: %d", i);
1006-
[self sendPut:[keys objectAtIndex:i]];
1104+
[self sendPut:[putKeys objectAtIndex:i]];
10071105
} else {
10081106
FFLog(@"I-RDB034038", @"Restoring put: skipped nil: %d", i);
10091107
}
10101108
}
10111109

1110+
NSArray *getKeys = [[self.outstandingGets allKeys]
1111+
sortedArrayUsingSelector:@selector(compare:)];
1112+
for (int i = 0; i < [getKeys count]; i++) {
1113+
if ([self.outstandingGets objectForKey:[getKeys objectAtIndex:i]] !=
1114+
nil) {
1115+
FFLog(@"I-RDB034037", @"Restoring get: %d", i);
1116+
[self sendGet:[getKeys objectAtIndex:i]];
1117+
} else {
1118+
FFLog(@"I-RDB034038", @"Restoring get: skipped nil: %d", i);
1119+
}
1120+
}
1121+
10121122
for (FTupleOnDisconnect *tuple in self.onDisconnectQueue) {
10131123
[self sendOnDisconnectAction:tuple.action
10141124
forPath:tuple.pathString

FirebaseDatabase/Sources/Core/FRepo.h

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#import "FirebaseDatabase/Sources/Core/FPersistentConnection.h"
1818
#import "FirebaseDatabase/Sources/Core/FRepoInfo.h"
1919
#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h"
20+
#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h"
2021
#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h"
2122
#import <Foundation/Foundation.h>
2223

@@ -31,63 +32,71 @@
3132

3233
@interface FRepo : NSObject <FPersistentConnectionDelegate>
3334

34-
@property(nonatomic, strong) FIRDatabaseConfig *config;
35+
@property(nonatomic, strong) FIRDatabaseConfig *_Nullable config;
3536

36-
- (id)initWithRepoInfo:(FRepoInfo *)info
37-
config:(FIRDatabaseConfig *)config
38-
database:(FIRDatabase *)database;
37+
- (id _Nonnull)initWithRepoInfo:(FRepoInfo *_Nullable)info
38+
config:(FIRDatabaseConfig *_Nullable)config
39+
database:(FIRDatabase *_Nullable)database;
3940

40-
- (void)set:(FPath *)path
41-
withNode:(id)node
42-
withCallback:(fbt_void_nserror_ref)onComplete;
43-
- (void)update:(FPath *)path
44-
withNodes:(FCompoundWrite *)compoundWrite
45-
withCallback:(fbt_void_nserror_ref)callback;
41+
- (void)set:(FPath *_Nullable)path
42+
withNode:(id _Nullable)node
43+
withCallback:(fbt_void_nserror_ref _Nullable)onComplete;
44+
- (void)update:(FPath *_Nullable)path
45+
withNodes:(FCompoundWrite *_Nullable)compoundWrite
46+
withCallback:(fbt_void_nserror_ref _Nullable)callback;
4647
- (void)purgeOutstandingWrites;
4748

48-
- (void)addEventRegistration:(id<FEventRegistration>)eventRegistration
49-
forQuery:(FQuerySpec *)query;
50-
- (void)removeEventRegistration:(id<FEventRegistration>)eventRegistration
51-
forQuery:(FQuerySpec *)query;
52-
- (void)keepQuery:(FQuerySpec *)query synced:(BOOL)synced;
49+
- (void)getData:(FIRDatabaseQuery *_Nullable)query
50+
withCompletionBlock:
51+
(void (^_Nonnull)(NSError *_Nullable error,
52+
FIRDataSnapshot *_Nullable snapshot))block;
5353

54-
- (NSString *)name;
54+
- (void)addEventRegistration:(id<FEventRegistration> _Nullable)eventRegistration
55+
forQuery:(FQuerySpec *_Nullable)query;
56+
- (void)removeEventRegistration:
57+
(id<FEventRegistration> _Nullable)eventRegistration
58+
forQuery:(FQuerySpec *_Nullable)query;
59+
- (void)keepQuery:(FQuerySpec *_Nullable)query synced:(BOOL)synced;
60+
61+
- (NSString *_Nullable)name;
5562
- (NSTimeInterval)serverTime;
5663

57-
- (void)onDataUpdate:(FPersistentConnection *)fpconnection
58-
forPath:(NSString *)pathString
59-
message:(id)message
64+
- (void)onDataUpdate:(FPersistentConnection *_Nullable)fpconnection
65+
forPath:(NSString *_Nullable)pathString
66+
message:(id _Nullable)message
6067
isMerge:(BOOL)isMerge
61-
tagId:(NSNumber *)tagId;
62-
- (void)onConnect:(FPersistentConnection *)fpconnection;
63-
- (void)onDisconnect:(FPersistentConnection *)fpconnection;
68+
tagId:(NSNumber *_Nullable)tagId;
69+
- (void)onConnect:(FPersistentConnection *_Nullable)fpconnection;
70+
- (void)onDisconnect:(FPersistentConnection *_Nullable)fpconnection;
6471

6572
// Disconnect methods
66-
- (void)onDisconnectCancel:(FPath *)path
67-
withCallback:(fbt_void_nserror_ref)callback;
68-
- (void)onDisconnectSet:(FPath *)path
69-
withNode:(id<FNode>)node
70-
withCallback:(fbt_void_nserror_ref)callback;
71-
- (void)onDisconnectUpdate:(FPath *)path
72-
withNodes:(FCompoundWrite *)compoundWrite
73-
withCallback:(fbt_void_nserror_ref)callback;
73+
- (void)onDisconnectCancel:(FPath *_Nullable)path
74+
withCallback:(fbt_void_nserror_ref _Nullable)callback;
75+
- (void)onDisconnectSet:(FPath *_Nullable)path
76+
withNode:(id<FNode> _Nullable)node
77+
withCallback:(fbt_void_nserror_ref _Nullable)callback;
78+
- (void)onDisconnectUpdate:(FPath *_Nullable)path
79+
withNodes:(FCompoundWrite *_Nullable)compoundWrite
80+
withCallback:(fbt_void_nserror_ref _Nullable)callback;
7481

7582
// Connection Management.
7683
- (void)interrupt;
7784
- (void)resume;
7885

7986
// Transactions
80-
- (void)startTransactionOnPath:(FPath *)path
81-
update:(fbt_transactionresult_mutabledata)update
82-
onComplete:(fbt_void_nserror_bool_datasnapshot)onComplete
87+
- (void)startTransactionOnPath:(FPath *_Nullable)path
88+
update:
89+
(fbt_transactionresult_mutabledata _Nullable)update
90+
onComplete:
91+
(fbt_void_nserror_bool_datasnapshot _Nullable)onComplete
8392
withLocalEvents:(BOOL)applyLocally;
8493

8594
// Testing methods
86-
- (NSDictionary *)dumpListens;
95+
- (NSDictionary *_Nullable)dumpListens;
8796
- (void)dispose;
8897
- (void)setHijackHash:(BOOL)hijack;
8998

90-
@property(nonatomic, strong, readonly) FAuthenticationManager *auth;
91-
@property(nonatomic, strong, readonly) FIRDatabase *database;
99+
@property(nonatomic, strong, readonly) FAuthenticationManager *_Nullable auth;
100+
@property(nonatomic, strong, readonly) FIRDatabase *_Nullable database;
92101

93102
@end

0 commit comments

Comments
 (0)