FView.m 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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 "FCacheNode.h"
  18. #import "FCancelEvent.h"
  19. #import "FEmptyNode.h"
  20. #import "FEventGenerator.h"
  21. #import "FEventRegistration.h"
  22. #import "FIRDatabaseQuery.h"
  23. #import "FIRDatabaseQuery_Private.h"
  24. #import "FIndexedFilter.h"
  25. #import "FIndexedNode.h"
  26. #import "FNode.h"
  27. #import "FOperation.h"
  28. #import "FOperationSource.h"
  29. #import "FPath.h"
  30. #import "FQueryParams.h"
  31. #import "FQuerySpec.h"
  32. #import "FViewCache.h"
  33. #import "FViewProcessor.h"
  34. #import "FViewProcessorResult.h"
  35. #import "FWriteTreeRef.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
  52. * registrations.
  53. *
  54. * It does several things:
  55. * - Maintains the list of event registration for this location/query.
  56. * - Maintains a cache of the data visible for this location/query.
  57. * - Applies new operations (via applyOperation), updates the cache, and based
  58. * on the event registrations returns the set of events to be raised.
  59. */
  60. @interface FView ()
  61. @property(nonatomic, strong, readwrite) FQuerySpec *query;
  62. @property(nonatomic, strong) FViewProcessor *processor;
  63. @property(nonatomic, strong) FViewCache *viewCache;
  64. @property(nonatomic, strong) NSMutableArray *eventRegistrations;
  65. @property(nonatomic, strong) FEventGenerator *eventGenerator;
  66. @end
  67. @implementation FView
  68. - (id)initWithQuery:(FQuerySpec *)query
  69. initialViewCache:(FViewCache *)initialViewCache {
  70. self = [super init];
  71. if (self) {
  72. self.query = query;
  73. FIndexedFilter *indexFilter =
  74. [[FIndexedFilter alloc] initWithIndex:query.index];
  75. id<FNodeFilter> filter = query.params.nodeFilter;
  76. self.processor = [[FViewProcessor alloc] initWithFilter:filter];
  77. FCacheNode *initialServerCache = initialViewCache.cachedServerSnap;
  78. FCacheNode *initialEventCache = initialViewCache.cachedEventSnap;
  79. // Don't filter server node with other filter than index, wait for
  80. // tagged listen
  81. FIndexedNode *emptyIndexedNode =
  82. [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode]
  83. index:query.index];
  84. FIndexedNode *serverSnap =
  85. [indexFilter updateFullNode:emptyIndexedNode
  86. withNewNode:initialServerCache.indexedNode
  87. accumulator:nil];
  88. FIndexedNode *eventSnap =
  89. [filter updateFullNode:emptyIndexedNode
  90. withNewNode:initialEventCache.indexedNode
  91. accumulator:nil];
  92. FCacheNode *newServerCache = [[FCacheNode alloc]
  93. initWithIndexedNode:serverSnap
  94. isFullyInitialized:initialServerCache.isFullyInitialized
  95. isFiltered:indexFilter.filtersNodes];
  96. FCacheNode *newEventCache = [[FCacheNode alloc]
  97. initWithIndexedNode:eventSnap
  98. isFullyInitialized:initialEventCache.isFullyInitialized
  99. isFiltered:filter.filtersNodes];
  100. self.viewCache = [[FViewCache alloc] initWithEventCache:newEventCache
  101. serverCache:newServerCache];
  102. self.eventRegistrations = [[NSMutableArray alloc] init];
  103. self.eventGenerator = [[FEventGenerator alloc] initWithQuery:query];
  104. }
  105. return self;
  106. }
  107. - (id<FNode>)serverCache {
  108. return self.viewCache.cachedServerSnap.node;
  109. }
  110. - (id<FNode>)eventCache {
  111. return self.viewCache.cachedEventSnap.node;
  112. }
  113. - (id<FNode>)completeServerCacheFor:(FPath *)path {
  114. id<FNode> cache = self.viewCache.completeServerSnap;
  115. if (cache) {
  116. // If this isn't a "loadsAllData" view, then cache isn't actually a
  117. // complete cache and we need to see if it contains the child we're
  118. // interested in.
  119. if ([self.query loadsAllData] ||
  120. (!path.isEmpty &&
  121. ![cache getImmediateChild:path.getFront].isEmpty)) {
  122. return [cache getChild:path];
  123. }
  124. }
  125. return nil;
  126. }
  127. - (BOOL)isEmpty {
  128. return self.eventRegistrations.count == 0;
  129. }
  130. - (void)addEventRegistration:(id<FEventRegistration>)eventRegistration {
  131. [self.eventRegistrations addObject:eventRegistration];
  132. }
  133. /**
  134. * @param eventRegistration If null, remove all callbacks.
  135. * @param cancelError If a cancelError is provided, appropriate cancel events
  136. * will be returned.
  137. * @return Cancel events, if cancelError was provided.
  138. */
  139. - (NSArray *)removeEventRegistration:(id<FEventRegistration>)eventRegistration
  140. cancelError:(NSError *)cancelError {
  141. NSMutableArray *cancelEvents = [[NSMutableArray alloc] init];
  142. if (cancelError != nil) {
  143. NSAssert(eventRegistration == nil,
  144. @"A cancel should cancel all event registrations.");
  145. FPath *path = self.query.path;
  146. for (id<FEventRegistration> registration in self.eventRegistrations) {
  147. FCancelEvent *maybeEvent =
  148. [registration createCancelEventFromError:cancelError path:path];
  149. if (maybeEvent) {
  150. [cancelEvents addObject:maybeEvent];
  151. }
  152. }
  153. }
  154. if (eventRegistration) {
  155. NSUInteger i = 0;
  156. while (i < self.eventRegistrations.count) {
  157. id<FEventRegistration> existing = self.eventRegistrations[i];
  158. if ([existing matches:eventRegistration]) {
  159. [self.eventRegistrations removeObjectAtIndex:i];
  160. } else {
  161. i++;
  162. }
  163. }
  164. } else {
  165. [self.eventRegistrations removeAllObjects];
  166. }
  167. return cancelEvents;
  168. }
  169. /**
  170. * Applies the given Operation, updates our cache, and returns the appropriate
  171. * events and changes
  172. */
  173. - (FViewOperationResult *)applyOperation:(id<FOperation>)operation
  174. writesCache:(FWriteTreeRef *)writesCache
  175. serverCache:(id<FNode>)optCompleteServerCache {
  176. if (operation.type == FOperationTypeMerge &&
  177. operation.source.queryParams != nil) {
  178. NSAssert(self.viewCache.completeServerSnap != nil,
  179. @"We should always have a full cache before handling merges");
  180. NSAssert(self.viewCache.completeEventSnap != nil,
  181. @"Missing event cache, even though we have a server cache");
  182. }
  183. FViewCache *oldViewCache = self.viewCache;
  184. FViewProcessorResult *result =
  185. [self.processor applyOperationOn:oldViewCache
  186. operation:operation
  187. writesCache:writesCache
  188. completeCache:optCompleteServerCache];
  189. NSAssert(result.viewCache.cachedServerSnap.isFullyInitialized ||
  190. !oldViewCache.cachedServerSnap.isFullyInitialized,
  191. @"Once a server snap is complete, it should never go back.");
  192. self.viewCache = result.viewCache;
  193. NSArray *events = [self
  194. generateEventsForChanges:result.changes
  195. eventCache:result.viewCache.cachedEventSnap.indexedNode
  196. registration:nil];
  197. return [[FViewOperationResult alloc] initWithChanges:result.changes
  198. events:events];
  199. }
  200. - (NSArray *)initialEvents:(id<FEventRegistration>)registration {
  201. FCacheNode *eventSnap = self.viewCache.cachedEventSnap;
  202. NSMutableArray *initialChanges = [[NSMutableArray alloc] init];
  203. [eventSnap.indexedNode.node enumerateChildrenUsingBlock:^(
  204. NSString *key, id<FNode> node, BOOL *stop) {
  205. FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:node];
  206. FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildAdded
  207. indexedNode:indexed
  208. childKey:key];
  209. [initialChanges addObject:change];
  210. }];
  211. if (eventSnap.isFullyInitialized) {
  212. FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeValue
  213. indexedNode:eventSnap.indexedNode];
  214. [initialChanges addObject:change];
  215. }
  216. return [self generateEventsForChanges:initialChanges
  217. eventCache:eventSnap.indexedNode
  218. registration:registration];
  219. }
  220. - (NSArray *)generateEventsForChanges:(NSArray *)changes
  221. eventCache:(FIndexedNode *)eventCache
  222. registration:(id<FEventRegistration>)registration {
  223. NSArray *registrations;
  224. if (registration == nil) {
  225. registrations = [[NSArray alloc] initWithArray:self.eventRegistrations];
  226. } else {
  227. registrations = [[NSArray alloc] initWithObjects:registration, nil];
  228. }
  229. return [self.eventGenerator generateEventsForChanges:changes
  230. eventCache:eventCache
  231. eventRegistrations:registrations];
  232. }
  233. - (NSString *)description {
  234. return [NSString stringWithFormat:@"FView (%@)", self.query];
  235. }
  236. @end