FView.m 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "FView.h"
  17. #import "FNode.h"
  18. #import "FWriteTreeRef.h"
  19. #import "FOperation.h"
  20. #import "FIRDatabaseQuery.h"
  21. #import "FIRDatabaseQuery_Private.h"
  22. #import "FEventRegistration.h"
  23. #import "FQueryParams.h"
  24. #import "FQuerySpec.h"
  25. #import "FViewCache.h"
  26. #import "FPath.h"
  27. #import "FEventGenerator.h"
  28. #import "FOperationSource.h"
  29. #import "FCancelEvent.h"
  30. #import "FIndexedFilter.h"
  31. #import "FCacheNode.h"
  32. #import "FEmptyNode.h"
  33. #import "FViewProcessor.h"
  34. #import "FViewProcessorResult.h"
  35. #import "FIndexedNode.h"
  36. @interface FViewOperationResult ()
  37. @property (nonatomic, strong, readwrite) NSArray *changes;
  38. @property (nonatomic, strong, readwrite) NSArray *events;
  39. @end
  40. @implementation FViewOperationResult
  41. - (id)initWithChanges:(NSArray *)changes events:(NSArray *)events {
  42. self = [super init];
  43. if (self != nil) {
  44. self->_changes = changes;
  45. self->_events = events;
  46. }
  47. return self;
  48. }
  49. @end
  50. /**
  51. * A view represents a specific location and query that has 1 or more event registrations.
  52. *
  53. * It does several things:
  54. * - Maintains the list of event registration for this location/query.
  55. * - Maintains a cache of the data visible for this location/query.
  56. * - Applies new operations (via applyOperation), updates the cache, and based on the event
  57. * registrations returns the set of events to be raised.
  58. */
  59. @interface FView ()
  60. @property (nonatomic, strong, readwrite) FQuerySpec *query;
  61. @property (nonatomic, strong) FViewProcessor *processor;
  62. @property (nonatomic, strong) FViewCache *viewCache;
  63. @property (nonatomic, strong) NSMutableArray *eventRegistrations;
  64. @property (nonatomic, strong) FEventGenerator *eventGenerator;
  65. @end
  66. @implementation FView
  67. - (id) initWithQuery:(FQuerySpec *)query initialViewCache:(FViewCache *)initialViewCache {
  68. self = [super init];
  69. if (self) {
  70. self.query = query;
  71. FIndexedFilter *indexFilter = [[FIndexedFilter alloc] initWithIndex:query.index];
  72. id<FNodeFilter> filter = query.params.nodeFilter;
  73. self.processor = [[FViewProcessor alloc] initWithFilter:filter];
  74. FCacheNode *initialServerCache = initialViewCache.cachedServerSnap;
  75. FCacheNode *initialEventCache = initialViewCache.cachedEventSnap;
  76. // Don't filter server node with other filter than index, wait for tagged listen
  77. FIndexedNode *emptyIndexedNode = [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] index:query.index];
  78. FIndexedNode *serverSnap = [indexFilter updateFullNode:emptyIndexedNode
  79. withNewNode:initialServerCache.indexedNode
  80. accumulator:nil];
  81. FIndexedNode *eventSnap = [filter updateFullNode:emptyIndexedNode
  82. withNewNode:initialEventCache.indexedNode
  83. accumulator:nil];
  84. FCacheNode *newServerCache = [[FCacheNode alloc] initWithIndexedNode:serverSnap
  85. isFullyInitialized:initialServerCache.isFullyInitialized
  86. isFiltered:indexFilter.filtersNodes];
  87. FCacheNode *newEventCache = [[FCacheNode alloc] initWithIndexedNode:eventSnap
  88. isFullyInitialized:initialEventCache.isFullyInitialized
  89. isFiltered:filter.filtersNodes];
  90. self.viewCache = [[FViewCache alloc] initWithEventCache:newEventCache serverCache:newServerCache];
  91. self.eventRegistrations = [[NSMutableArray alloc] init];
  92. self.eventGenerator = [[FEventGenerator alloc] initWithQuery:query];
  93. }
  94. return self;
  95. }
  96. - (id <FNode>) serverCache {
  97. return self.viewCache.cachedServerSnap.node;
  98. }
  99. - (id <FNode>) eventCache {
  100. return self.viewCache.cachedEventSnap.node;
  101. }
  102. - (id <FNode>) completeServerCacheFor:(FPath*)path {
  103. id<FNode> cache = self.viewCache.completeServerSnap;
  104. if (cache) {
  105. // If this isn't a "loadsAllData" view, then cache isn't actually a complete cache and
  106. // we need to see if it contains the child we're interested in.
  107. if ([self.query loadsAllData] ||
  108. (!path.isEmpty && ![cache getImmediateChild:path.getFront].isEmpty)) {
  109. return [cache getChild:path];
  110. }
  111. }
  112. return nil;
  113. }
  114. - (BOOL) isEmpty {
  115. return self.eventRegistrations.count == 0;
  116. }
  117. - (void) addEventRegistration:(id <FEventRegistration>)eventRegistration {
  118. [self.eventRegistrations addObject:eventRegistration];
  119. }
  120. /**
  121. * @param eventRegistration If null, remove all callbacks.
  122. * @param cancelError If a cancelError is provided, appropriate cancel events will be returned.
  123. * @return Cancel events, if cancelError was provided.
  124. */
  125. - (NSArray *) removeEventRegistration:(id <FEventRegistration>)eventRegistration cancelError:(NSError *)cancelError {
  126. NSMutableArray *cancelEvents = [[NSMutableArray alloc] init];
  127. if (cancelError != nil) {
  128. NSAssert(eventRegistration == nil, @"A cancel should cancel all event registrations.");
  129. FPath *path = self.query.path;
  130. for (id <FEventRegistration> registration in self.eventRegistrations) {
  131. FCancelEvent *maybeEvent = [registration createCancelEventFromError:cancelError path:path];
  132. if (maybeEvent) {
  133. [cancelEvents addObject:maybeEvent];
  134. }
  135. }
  136. }
  137. if (eventRegistration) {
  138. NSUInteger i = 0;
  139. while (i < self.eventRegistrations.count) {
  140. id<FEventRegistration> existing = self.eventRegistrations[i];
  141. if ([existing matches:eventRegistration]) {
  142. [self.eventRegistrations removeObjectAtIndex:i];
  143. } else {
  144. i++;
  145. }
  146. }
  147. } else {
  148. [self.eventRegistrations removeAllObjects];
  149. }
  150. return cancelEvents;
  151. }
  152. /**
  153. * Applies the given Operation, updates our cache, and returns the appropriate events and changes
  154. */
  155. - (FViewOperationResult *) applyOperation:(id <FOperation>)operation writesCache:(FWriteTreeRef *)writesCache serverCache:(id <FNode>)optCompleteServerCache {
  156. if (operation.type == FOperationTypeMerge && operation.source.queryParams != nil) {
  157. NSAssert(self.viewCache.completeServerSnap != nil, @"We should always have a full cache before handling merges");
  158. NSAssert(self.viewCache.completeEventSnap != nil, @"Missing event cache, even though we have a server cache");
  159. }
  160. FViewCache *oldViewCache = self.viewCache;
  161. FViewProcessorResult *result = [self.processor applyOperationOn:oldViewCache operation:operation writesCache:writesCache completeCache:optCompleteServerCache];
  162. NSAssert(result.viewCache.cachedServerSnap.isFullyInitialized || !oldViewCache.cachedServerSnap.isFullyInitialized, @"Once a server snap is complete, it should never go back.");
  163. self.viewCache = result.viewCache;
  164. NSArray *events = [self generateEventsForChanges:result.changes eventCache:result.viewCache.cachedEventSnap.indexedNode registration:nil];
  165. return [[FViewOperationResult alloc] initWithChanges:result.changes events:events];
  166. }
  167. - (NSArray *) initialEvents:(id<FEventRegistration>)registration {
  168. FCacheNode *eventSnap = self.viewCache.cachedEventSnap;
  169. NSMutableArray *initialChanges = [[NSMutableArray alloc] init];
  170. [eventSnap.indexedNode.node enumerateChildrenUsingBlock:^(NSString *key, id<FNode> node, BOOL *stop) {
  171. FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:node];
  172. FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildAdded indexedNode:indexed childKey:key];
  173. [initialChanges addObject:change];
  174. }];
  175. if (eventSnap.isFullyInitialized) {
  176. FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeValue indexedNode:eventSnap.indexedNode];
  177. [initialChanges addObject:change];
  178. }
  179. return [self generateEventsForChanges:initialChanges eventCache:eventSnap.indexedNode registration:registration];
  180. }
  181. - (NSArray *) generateEventsForChanges:(NSArray *)changes eventCache:(FIndexedNode *)eventCache registration:(id<FEventRegistration>)registration {
  182. NSArray *registrations;
  183. if (registration == nil) {
  184. registrations = [[NSArray alloc] initWithArray:self.eventRegistrations];
  185. } else {
  186. registrations = [[NSArray alloc] initWithObjects:registration, nil];
  187. }
  188. return [self.eventGenerator generateEventsForChanges:changes eventCache:eventCache eventRegistrations:registrations];
  189. }
  190. - (NSString *) description {
  191. return [NSString stringWithFormat:@"FView (%@)", self.query];
  192. }
  193. @end