FEventGenerator.m 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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 "FirebaseDatabase/Sources/FEventGenerator.h"
  17. #import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h"
  18. #import "FirebaseDatabase/Sources/Core/FQueryParams.h"
  19. #import "FirebaseDatabase/Sources/Core/FQuerySpec.h"
  20. #import "FirebaseDatabase/Sources/Core/View/FChange.h"
  21. #import "FirebaseDatabase/Sources/Core/View/FDataEvent.h"
  22. #import "FirebaseDatabase/Sources/Core/View/FEvent.h"
  23. #import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h"
  24. #import "FirebaseDatabase/Sources/FNamedNode.h"
  25. #import "FirebaseDatabase/Sources/Snapshot/FNode.h"
  26. @interface FEventGenerator ()
  27. @property(nonatomic, strong) FQuerySpec *query;
  28. @end
  29. /**
  30. * An EventGenerator is used to convert "raw" changes (fb.core.view.Change) as
  31. * computed by the CacheDiffer into actual events (fb.core.view.Event) that can
  32. * be raised. See generateEventsForChanges() for details.
  33. */
  34. @implementation FEventGenerator
  35. - (id)initWithQuery:(FQuerySpec *)query {
  36. self = [super init];
  37. if (self) {
  38. self.query = query;
  39. }
  40. return self;
  41. }
  42. /**
  43. * Given a set of raw changes (no moved events, and prevName not specified yet),
  44. * and a set of EventRegistrations that should be notified of these changes,
  45. * generate the actual events to be raised.
  46. *
  47. * Notes:
  48. * - child_moved events will be synthesized at this time for any child_changed
  49. * events that affect our index
  50. * - prevName will be calculated based on the index ordering
  51. *
  52. * @param changes NSArray of FChange, not necessarily in order.
  53. * @param registrations is NSArray of FEventRegistration.
  54. * @return NSArray of FEvent.
  55. */
  56. - (NSArray *)generateEventsForChanges:(NSArray *)changes
  57. eventCache:(FIndexedNode *)eventCache
  58. eventRegistrations:(NSArray *)registrations {
  59. NSMutableArray *events = [[NSMutableArray alloc] init];
  60. // child_moved is index-specific, so check all our child_changed events to
  61. // see if we need to materialize child_moved events with this view's index
  62. NSMutableArray *moves = [[NSMutableArray alloc] init];
  63. for (FChange *change in changes) {
  64. if (change.type == FIRDataEventTypeChildChanged &&
  65. [self.query.index
  66. indexedValueChangedBetween:change.oldIndexedNode.node
  67. and:change.indexedNode.node]) {
  68. FChange *moveChange =
  69. [[FChange alloc] initWithType:FIRDataEventTypeChildMoved
  70. indexedNode:change.indexedNode
  71. childKey:change.childKey
  72. oldIndexedNode:nil];
  73. [moves addObject:moveChange];
  74. }
  75. }
  76. [self generateEvents:events
  77. forType:FIRDataEventTypeChildRemoved
  78. changes:changes
  79. eventCache:eventCache
  80. eventRegistrations:registrations];
  81. [self generateEvents:events
  82. forType:FIRDataEventTypeChildAdded
  83. changes:changes
  84. eventCache:eventCache
  85. eventRegistrations:registrations];
  86. [self generateEvents:events
  87. forType:FIRDataEventTypeChildMoved
  88. changes:moves
  89. eventCache:eventCache
  90. eventRegistrations:registrations];
  91. [self generateEvents:events
  92. forType:FIRDataEventTypeChildChanged
  93. changes:changes
  94. eventCache:eventCache
  95. eventRegistrations:registrations];
  96. [self generateEvents:events
  97. forType:FIRDataEventTypeValue
  98. changes:changes
  99. eventCache:eventCache
  100. eventRegistrations:registrations];
  101. return events;
  102. }
  103. - (void)generateEvents:(NSMutableArray *)events
  104. forType:(FIRDataEventType)eventType
  105. changes:(NSArray *)changes
  106. eventCache:(FIndexedNode *)eventCache
  107. eventRegistrations:(NSArray *)registrations {
  108. NSMutableArray *filteredChanges = [[NSMutableArray alloc] init];
  109. for (FChange *change in changes) {
  110. if (change.type == eventType) {
  111. [filteredChanges addObject:change];
  112. }
  113. }
  114. id<FIndex> index = self.query.index;
  115. [filteredChanges
  116. sortUsingComparator:^NSComparisonResult(FChange *one, FChange *two) {
  117. if (one.childKey == nil || two.childKey == nil) {
  118. @throw [[NSException alloc]
  119. initWithName:@"InternalInconsistencyError"
  120. reason:@"Should only compare child_ events"
  121. userInfo:nil];
  122. }
  123. return [index compareKey:one.childKey
  124. andNode:one.indexedNode.node
  125. toOtherKey:two.childKey
  126. andNode:two.indexedNode.node];
  127. }];
  128. for (FChange *change in filteredChanges) {
  129. for (id<FEventRegistration> registration in registrations) {
  130. if ([registration responseTo:eventType]) {
  131. id<FEvent> event = [self generateEventForChange:change
  132. registration:registration
  133. eventCache:eventCache];
  134. [events addObject:event];
  135. }
  136. }
  137. }
  138. }
  139. - (id<FEvent>)generateEventForChange:(FChange *)change
  140. registration:(id<FEventRegistration>)registration
  141. eventCache:(FIndexedNode *)eventCache {
  142. FChange *materializedChange;
  143. if (change.type == FIRDataEventTypeValue ||
  144. change.type == FIRDataEventTypeChildRemoved) {
  145. materializedChange = change;
  146. } else {
  147. NSString *prevChildKey =
  148. [eventCache predecessorForChildKey:change.childKey
  149. childNode:change.indexedNode.node
  150. index:self.query.index];
  151. materializedChange = [change changeWithPrevKey:prevChildKey];
  152. }
  153. return [registration createEventFrom:materializedChange query:self.query];
  154. }
  155. @end