Skip to content

Commit 5dc0adb

Browse files
committed
Implemented queryWithBypassCache that is not returning data from cache when persistenceEnabled.
1 parent 2c2614e commit 5dc0adb

File tree

8 files changed

+167
-16
lines changed

8 files changed

+167
-16
lines changed

Example/Database/Tests/Integration/FPersist.m

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,109 @@ - (void) testServerDataCompleteness2 {
221221
[device dispose];
222222
}
223223

224+
- (void)testServerDataNotReturnedWhenQueryWithBypassCacheWhenOnline {
225+
FIRDatabaseReference *writerRef = [FTestHelpers getRandomNode];
226+
FDevice *device = [[FDevice alloc] initOnlineWithUrl:[writerRef description] ];
227+
id data = @{@"a": @1, @"b": @2};
228+
[device do:^(FIRDatabaseReference *ref) {
229+
[self waitForCompletionOf:ref setValue:data];
230+
}];
231+
232+
// Wait for the data to get it cached.
233+
[device do:^(FIRDatabaseReference *ref) {
234+
[self waitForValueOf:ref toBe:data];
235+
}];
236+
237+
// Write new data using different device so not cached
238+
id newData = @{@"a": @1, @"b": @2, @"c": @3};
239+
240+
FDevice *secondDevice = [[FDevice alloc] initOnlineWithUrl:[writerRef description] ];
241+
[secondDevice waitForIdleUsingWaiter:self];
242+
[secondDevice do:^(FIRDatabaseReference *ref) {
243+
[self waitForCompletionOf:ref setValue:newData];
244+
}];
245+
[secondDevice dispose];
246+
247+
//Normal observe should return previous data
248+
__block BOOL done = NO;
249+
done = NO;
250+
[device do:^(FIRDatabaseReference *ref) {
251+
[ref observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
252+
XCTAssertEqualObjects(data, [snapshot value], @"Properly saw node value");
253+
done = YES;
254+
}];
255+
}];
256+
WAIT_FOR(done);
257+
258+
//queryWithBypassCache observe should return new data from server
259+
done = NO;
260+
[device do:^(FIRDatabaseReference *ref) {
261+
[ref.queryWithBypassCache observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
262+
XCTAssertEqualObjects(newData, [snapshot value], @"Properly saw node value");
263+
done = YES;
264+
}];
265+
}];
266+
WAIT_FOR(done);
267+
268+
[device dispose];
269+
}
270+
271+
- (void)testServerDataNotReturnedWhenQueryWithBypassCacheWhenOffline {
272+
FIRDatabaseReference *writerRef = [FTestHelpers getRandomNode];
273+
FDevice *device = [[FDevice alloc] initOnlineWithUrl:[writerRef description] ];
274+
__block BOOL done = NO;
275+
id data = @{@"a": @1, @"b": @2};
276+
[writerRef setValue:data withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
277+
done = YES;
278+
}];
279+
WAIT_FOR(done);
280+
281+
// Wait for the data to get it cached.
282+
[device do:^(FIRDatabaseReference *ref) {
283+
[self waitForValueOf:ref toBe:data];
284+
}];
285+
286+
// Write new data using different device so not cached
287+
id newData = @{@"a": @1, @"b": @2, @"c": @3};
288+
289+
FDevice *secondDevice = [[FDevice alloc] initOnlineWithUrl:[writerRef description] ];
290+
[secondDevice do:^(FIRDatabaseReference *ref) {
291+
[self waitForCompletionOf:ref setValue:newData];
292+
}];
293+
[secondDevice dispose];
294+
295+
296+
[device goOffline];
297+
298+
//Normal observe should return previous cached data
299+
done = NO;
300+
[device do:^(FIRDatabaseReference *ref) {
301+
[ref observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
302+
XCTAssertEqualObjects(data, [snapshot value], @"Properly saw node value");
303+
done = YES;
304+
}];
305+
}];
306+
WAIT_FOR(done);
307+
308+
//queryWithBypassCache observe should not return data
309+
XCTestExpectation *timeoutExpectation = [self expectationWithDescription:@"Should not be fulfilled"];
310+
[timeoutExpectation setInverted:YES];
311+
312+
__block FIRDatabaseHandle handle;
313+
__block FIRDatabaseQuery *handleRef;
314+
[device do:^(FIRDatabaseReference *ref) {
315+
handleRef = ref.queryWithBypassCache;
316+
handle = [handleRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
317+
[timeoutExpectation fulfill];
318+
}];
319+
}];
320+
321+
[self waitForExpectationsWithTimeout:kFirebaseTestWaitUntilTimeout handler:nil];
322+
[handleRef removeObserverWithHandle:handle];
323+
324+
[device dispose];
325+
}
326+
224327
- (void)testServerDataLimit {
225328
FIRDatabaseReference *writerRef = [FTestHelpers getRandomNode];
226329
FDevice *device = [[FDevice alloc] initOnlineWithUrl:[writerRef description] ];

Firebase/Database/Api/FIRDatabaseQuery.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,15 @@ - (FIRDatabaseQuery *)queryEqualToInternal:(id)value
247247
priorityMethodCalled:priorityMethod || self.priorityMethodCalled];
248248
}
249249

250+
- (FIRDatabaseQuery *)queryWithBypassCache {
251+
FQueryParams* params = [self.queryParams enableBypassCache];
252+
return [[FIRDatabaseQuery alloc] initWithRepo:self.repo
253+
path:self.path
254+
params:params
255+
orderByCalled:self.orderByCalled
256+
priorityMethodCalled:self.priorityMethodCalled];;
257+
}
258+
250259
- (void)validateLimitRange:(NSUInteger)limit
251260
{
252261
// No need to check for negative ranges, since limit is unsigned

Firebase/Database/Core/FQueryParams.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
@property (nonatomic, strong, readonly) id<FIndex> index;
3333

34+
@property (nonatomic, readonly) BOOL bypassCache;
35+
3436
- (BOOL)loadsAllData;
3537
- (BOOL)isDefault;
3638
- (BOOL)isValid;
@@ -47,6 +49,8 @@
4749

4850
- (FQueryParams *) orderBy:(id<FIndex>) index;
4951

52+
- (FQueryParams *) enableBypassCache;
53+
5054
+ (FQueryParams *) defaultInstance;
5155
+ (FQueryParams *) fromQueryObject:(NSDictionary *)dict;
5256

Firebase/Database/Core/FQueryParams.m

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ - (id)init {
7373
self->_indexEndKey = nil;
7474

7575
self->_index = [FPriorityIndex priorityIndex];
76+
77+
self->_bypassCache = NO;
7678
}
7779
return self;
7880
}
@@ -158,6 +160,8 @@ - (id) mutableCopy {
158160
other->_indexEndKey = _indexEndKey;
159161
other->_viewFrom = _viewFrom;
160162
other->_index = _index;
163+
other->_bypassCache = _bypassCache;
164+
161165
return other;
162166
}
163167

@@ -215,6 +219,12 @@ - (FQueryParams *) orderBy:(id)newIndex {
215219
return newParams;
216220
}
217221

222+
- (FQueryParams *) enableBypassCache {
223+
FQueryParams *newParams = [self mutableCopy];
224+
newParams->_bypassCache = YES;
225+
return newParams;
226+
}
227+
218228
- (NSDictionary *) wireProtocolParams {
219229
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
220230
if ([self hasStart]) {
@@ -353,6 +363,7 @@ - (BOOL) isEqual:(id)obj {
353363
if ((self->_indexStartValue != other->_indexStartValue) && ![self->_indexStartValue isEqual:other->_indexStartValue]) return NO;
354364
if ((self->_indexEndKey != other->_indexEndKey) && ![self->_indexEndKey isEqualToString:other->_indexEndKey]) return NO;
355365
if ((self->_indexEndValue != other->_indexEndValue) && ![self->_indexEndValue isEqual:other->_indexEndValue]) return NO;
366+
if (self->_bypassCache != other->_bypassCache) return NO;
356367
if ([self isViewFromLeft] != [other isViewFromLeft]) return NO;
357368

358369
return YES;
@@ -366,6 +377,8 @@ - (NSUInteger) hash {
366377
result = 31 * result + [_indexEndKey hash];
367378
result = 31 * result + [_indexEndValue hash];
368379
result = 31 * result + [_index hash];
380+
result = 31 * result + (_bypassCache ? 1232 : 1238);
381+
369382
return result;
370383
}
371384

Firebase/Database/FIRDatabaseReference.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,9 @@ - (FIRDatabaseQuery *)queryEqualToValue:(id)value childKey:(NSString *)childKey
374374
return [super queryEqualToValue:value childKey:childKey];
375375
}
376376

377+
- (FIRDatabaseQuery *)queryWithBypassCache {
378+
return [super queryWithBypassCache];
379+
}
377380

378381
#pragma mark -
379382
#pragma mark Transaction methods

Firebase/Database/Persistence/FPersistenceManager.m

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#import "FUtilities.h"
2525
#import "FPruneForest.h"
2626
#import "FClock.h"
27+
#import "FSnapshotUtilities.h"
2728

2829
@interface FPersistenceManager ()
2930

@@ -77,24 +78,29 @@ - (FCacheNode *)serverCacheForQuery:(FQuerySpec *)query {
7778
NSSet *trackedKeys;
7879
BOOL complete;
7980
// TODO[offline]: Should we use trackedKeys to find out if this location is a child of a complete query?
80-
if ([self.trackedQueryManager isQueryComplete:query]) {
81-
complete = YES;
82-
FTrackedQuery *trackedQuery = [self.trackedQueryManager findTrackedQuery:query];
83-
if (!query.loadsAllData && trackedQuery.isComplete) {
84-
trackedKeys = [self.storageEngine trackedQueryKeysForQuery:trackedQuery.queryId];
81+
id<FNode> node;
82+
if (query.params.bypassCache) {
83+
complete = NO;
84+
node = [FSnapshotUtilities nodeFrom:nil];
85+
}else{
86+
if ([self.trackedQueryManager isQueryComplete:query]) {
87+
complete = YES;
88+
FTrackedQuery *trackedQuery = [self.trackedQueryManager findTrackedQuery:query];
89+
if (!query.loadsAllData && trackedQuery.isComplete) {
90+
trackedKeys = [self.storageEngine trackedQueryKeysForQuery:trackedQuery.queryId];
91+
} else {
92+
trackedKeys = nil;
93+
}
8594
} else {
86-
trackedKeys = nil;
95+
complete = NO;
96+
trackedKeys = [self.trackedQueryManager knownCompleteChildrenAtPath:query.path];
97+
}
98+
99+
if (trackedKeys != nil) {
100+
node = [self.storageEngine serverCacheForKeys:trackedKeys atPath:query.path];
101+
} else {
102+
node = [self.storageEngine serverCacheAtPath:query.path];
87103
}
88-
} else {
89-
complete = NO;
90-
trackedKeys = [self.trackedQueryManager knownCompleteChildrenAtPath:query.path];
91-
}
92-
93-
id<FNode> node;
94-
if (trackedKeys != nil) {
95-
node = [self.storageEngine serverCacheForKeys:trackedKeys atPath:query.path];
96-
} else {
97-
node = [self.storageEngine serverCacheAtPath:query.path];
98104
}
99105

100106
FIndexedNode *indexedNode = [FIndexedNode indexedNodeWithNode:node index:query.index];

Firebase/Database/Public/FIRDatabaseQuery.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,12 @@ NS_SWIFT_NAME(DatabaseQuery)
299299
*/
300300
- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value childKey:(nullable NSString *)childKey;
301301

302+
/**
303+
* queryWithBypassCache is used to generate a query that will not return cachedData.
304+
*
305+
* @return A FIRDatabaseQuery instance, that will not return cached data.
306+
*/
307+
- (FIRDatabaseQuery *)queryWithBypassCache;
302308

303309
#pragma mark - Properties
304310

Firebase/Database/Public/FIRDatabaseReference.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,13 @@ is meant to be preserved, you should use setValue:andPriority: instead.
450450
*/
451451
- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value childKey:(nullable NSString *)childKey;
452452

453+
/**
454+
* queryWithBypassCache is used to generate a query that will not return cachedData
455+
*
456+
* @return A FIRDatabaseQuery instance, that will not return cached data.
457+
*/
458+
- (FIRDatabaseQuery *)queryWithBypassCache;
459+
453460
#pragma mark - Managing presence
454461

455462
/**

0 commit comments

Comments
 (0)