[go: nahoru, domu]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix startAfter/endBefore for orderByKeys queries #7403

Merged
merged 13 commits into from
Feb 10, 2021
Prev Previous commit
Next Next commit
fix get
  • Loading branch information
jmwski committed Feb 3, 2021
commit 9691f24d1d299f4a717eaa49a58f00914326220c
6 changes: 2 additions & 4 deletions FirebaseDatabase/Sources/Core/FRepo.m
Original file line number Diff line number Diff line change
Expand Up @@ -518,10 +518,8 @@ - (void)getData:(FIRDatabaseQuery *)query
(void (^_Nonnull)(NSError *__nullable error,
FIRDataSnapshot *__nullable snapshot))block {
FQuerySpec *querySpec = [query querySpec];
id<FNode> node =
[self.serverSyncTree calcCompleteEventCacheAtPath:querySpec.path
excludeWriteIds:@[]];
if (![node isEmpty]) {
id<FNode> node = [self.serverSyncTree getServerValue:[query querySpec]];
if (node != nil) {
block(nil, [[FIRDataSnapshot alloc]
initWithRef:query.ref
indexedNode:[FIndexedNode
Expand Down
4 changes: 4 additions & 0 deletions FirebaseDatabase/Sources/Core/FSyncPoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
writesCache:(FWriteTreeRef *)writesCache
serverCache:(id<FNode>)optCompleteServerCache;

- (FView *)getView:(FQuerySpec *)query
writesCache:(FWriteTreeRef *)writesCache
serverCache:(FCacheNode *)serverCache;

/**
* Returns array of FEvent
*/
Expand Down
59 changes: 34 additions & 25 deletions FirebaseDatabase/Sources/Core/FSyncPoint.m
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,36 @@ - (NSArray *)applyOperation:(id<FOperation>)operation
}
}

- (FView *)getView:(FQuerySpec *)query
writesCache:(FWriteTreeRef *)writesCache
serverCache:(FCacheNode *)serverCache {
FView *view = [self.views objectForKey:[query params]];
if (view == nil) {
id<FNode> serverCacheNode = [serverCache node];
id<FNode> eventCache = [writesCache
calculateCompleteEventCacheWithCompleteServerCache:serverCacheNode];
BOOL eventCacheComplete;
if (eventCache != nil) {
eventCacheComplete = YES;
} else {
eventCache = [writesCache
calculateCompleteEventChildrenWithCompleteServerChildren:
serverCacheNode];
eventCacheComplete = NO;
}
FCacheNode *eventCacheNode = [[FCacheNode alloc]
initWithIndexedNode:[FIndexedNode indexedNodeWithNode:eventCache
index:[query index]]
isFullyInitialized:eventCacheComplete
isFiltered:NO];
FViewCache *viewCache =
[[FViewCache alloc] initWithEventCache:eventCacheNode
serverCache:serverCache];
return [[FView alloc] initWithQuery:query initialViewCache:viewCache];
}
return nil;
}

/**
* Add an event callback for the specified query
* Returns Array of FEvent events to raise.
jmwski marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -138,31 +168,10 @@ - (NSArray *)addEventRegistration:(id<FEventRegistration>)eventRegistration
serverCache:(FCacheNode *)serverCache {
NSAssert(self.views[query.params] == nil, @"Found view for query: %@",
query.params);
// TODO: make writesCache take flag for complete server node
id<FNode> eventCache = [writesCache
calculateCompleteEventCacheWithCompleteServerCache:
serverCache.isFullyInitialized ? serverCache.node : nil];
BOOL eventCacheComplete;
if (eventCache != nil) {
eventCacheComplete = YES;
} else {
eventCache = [writesCache
calculateCompleteEventChildrenWithCompleteServerChildren:serverCache
.node];
eventCacheComplete = NO;
}

FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:eventCache
index:query.index];
FCacheNode *eventCacheNode =
[[FCacheNode alloc] initWithIndexedNode:indexed
isFullyInitialized:eventCacheComplete
isFiltered:NO];
FViewCache *viewCache =
[[FViewCache alloc] initWithEventCache:eventCacheNode
serverCache:serverCache];
FView *view = [[FView alloc] initWithQuery:query
initialViewCache:viewCache];
// // TODO: make writesCache take flag for complete server node
FView *view = [self getView:query
writesCache:writesCache
serverCache:serverCache];
// If this is a non-default query we need to tell persistence our current
// view of the data
if (!query.loadsAllData) {
Expand Down
1 change: 1 addition & 0 deletions FirebaseDatabase/Sources/Core/FSyncTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
- (NSArray *)removeAllWrites;

- (FIndexedNode *)persistenceServerCache:(FQuerySpec *)querySpec;
- (id<FNode>)getServerValue:(FQuerySpec *)query;
- (id<FNode>)calcCompleteEventCacheAtPath:(FPath *)path
excludeWriteIds:(NSArray *)writeIdsToExclude;

Expand Down
50 changes: 50 additions & 0 deletions FirebaseDatabase/Sources/Core/FSyncTree.m
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,56 @@ - (FIndexedNode *)persistenceServerCache:(FQuerySpec *)querySpec {
return cacheNode.node;
}

- (id<FNode>)getServerValue:(FQuerySpec *)query {
FPath *path = [query path];
__block id<FNode> serverCacheNode = nil;
__block BOOL foundAncestorDefaultView = NO;
[self.syncPointTree
forEachOnPath:query.path
whileBlock:^BOOL(FPath *pathToSyncPoint, FSyncPoint *syncPoint) {
serverCacheNode =
serverCacheNode != nil
? serverCacheNode
: [syncPoint completeServerCacheAtPath:pathToSyncPoint];
foundAncestorDefaultView =
foundAncestorDefaultView || [syncPoint hasCompleteView];
return !foundAncestorDefaultView;
}];

[self.persistenceManager setQueryActive:query];
jmwski marked this conversation as resolved.
Show resolved Hide resolved

FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path];
if (syncPoint == nil) {
syncPoint = [[FSyncPoint alloc]
initWithPersistenceManager:self.persistenceManager];
self.syncPointTree = [self.syncPointTree setValue:syncPoint
atPath:path];
} else {
foundAncestorDefaultView =
foundAncestorDefaultView || [syncPoint hasCompleteView];
jmwski marked this conversation as resolved.
Show resolved Hide resolved
serverCacheNode =
serverCacheNode != nil
? serverCacheNode
: [syncPoint completeServerCacheAtPath:[FPath empty]];
}

FCacheNode *serverCache;
jmwski marked this conversation as resolved.
Show resolved Hide resolved
if (serverCacheNode != nil) {
serverCache = [[FCacheNode alloc]
initWithIndexedNode:[FIndexedNode
indexedNodeWithNode:serverCacheNode
index:[query index]]
isFullyInitialized:YES
isFiltered:NO];
FView *view = [syncPoint
getView:query
writesCache:[_pendingWriteTree childWritesForPath:[query path]]
serverCache:serverCache];
return [view completeServerCacheFor:[query path]];
}
return nil;
}

/**
* Returns a complete cache, if we have one, of the data at a particular path.
* The location must have a listener above it, but as this is only used by
Expand Down
70 changes: 69 additions & 1 deletion FirebaseDatabase/Tests/Integration/FIRDatabaseQueryTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -1434,6 +1434,66 @@ - (void)testEndBeforeWithOrderByKey {
WAIT_FOR(done);
}

- (void)testStartAfterWithOrderByKeyOverlappingListener {
FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
FIRDatabaseReference* childOne = [ref childByAutoId];
FIRDatabaseReference* childTwo = [ref childByAutoId];

[childOne setValue:@1];
[childTwo setValue:@2];

__block BOOL done = NO;

[ref observeEventType:FIRDataEventTypeValue
jmwski marked this conversation as resolved.
Show resolved Hide resolved
withBlock:^(FIRDataSnapshot* snapshot) {
done = YES;
}];

WAIT_FOR(done);
done = NO;

[[[ref queryOrderedByKey] queryStartingAfterValue:[childOne key]]
getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) {
XCTAssert([[snapshot value] isKindOfClass:[NSDictionary class]]);
NSDictionary* data = (NSDictionary*)[snapshot value];
XCTAssertEqualObjects([data allKeys], @[ [childTwo key] ]);
XCTAssertEqualObjects([data allValues], @[ @2 ]);
done = YES;
}];

WAIT_FOR(done);
}

- (void)testEndBeforeWithOrderByKeyOverlappingListener {
FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
FIRDatabaseReference* childOne = [ref childByAutoId];
FIRDatabaseReference* childTwo = [ref childByAutoId];

[childOne setValue:@1];
[childTwo setValue:@2];

__block BOOL done = NO;

[ref observeEventType:FIRDataEventTypeValue
withBlock:^(FIRDataSnapshot* snapshot) {
done = YES;
}];

WAIT_FOR(done);
done = NO;

[[[ref queryOrderedByKey] queryEndingBeforeValue:[childTwo key]]
getDataWithCompletionBlock:^(NSError* err, FIRDataSnapshot* snapshot) {
XCTAssert([[snapshot value] isKindOfClass:[NSDictionary class]]);
NSDictionary* data = (NSDictionary*)[snapshot value];
XCTAssertEqualObjects([data allKeys], @[ [childOne key] ]);
XCTAssertEqualObjects([data allValues], @[ @1 ]);
done = YES;
}];

WAIT_FOR(done);
}

- (void)testStartAfterPriorityAndEndAtPriorityWork {
FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
Expand Down Expand Up @@ -4116,7 +4176,15 @@ - (void)testGetProbesInMemoryCacheForActiveListenerWhenOffline {
}
}];

[self waitForCompletionOf:ref setValue:@42];
__block BOOL writeDone = NO;
jmwski marked this conversation as resolved.
Show resolved Hide resolved

[ref setValue:@42
withCompletionBlock:^(NSError* _Nullable error, FIRDatabaseReference* _Nonnull ref) {
writeDone = YES;
}];

WAIT_FOR(writeDone);
writeDone = NO;

WAIT_FOR(done);
jmwski marked this conversation as resolved.
Show resolved Hide resolved
done = NO;
Expand Down