FEventGenerator.m 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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 "FEventGenerator.h"
  17. #import "FNode.h"
  18. #import "FIRDatabaseQuery_Private.h"
  19. #import "FQueryParams.h"
  20. #import "FQuerySpec.h"
  21. #import "FChange.h"
  22. #import "FNamedNode.h"
  23. #import "FEventRegistration.h"
  24. #import "FEvent.h"
  25. #import "FDataEvent.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 computed by the
  31. * CacheDiffer into actual events (fb.core.view.Event) that can be raised. See generateEventsForChanges()
  32. * 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), and a set of EventRegistrations that
  44. * should be notified of these changes, generate the actual events to be raised.
  45. *
  46. * Notes:
  47. * - child_moved events will be synthesized at this time for any child_changed events that affect our index
  48. * - prevName will be calculated based on the index ordering
  49. *
  50. * @param changes NSArray of FChange, not necessarily in order.
  51. * @param registrations is NSArray of FEventRegistration.
  52. * @return NSArray of FEvent.
  53. */
  54. - (NSArray *) generateEventsForChanges:(NSArray *)changes
  55. eventCache:(FIndexedNode *)eventCache
  56. eventRegistrations:(NSArray *)registrations
  57. {
  58. NSMutableArray *events = [[NSMutableArray alloc] init];
  59. // child_moved is index-specific, so check all our child_changed events to see if we need to materialize
  60. // child_moved events with this view's index
  61. NSMutableArray *moves = [[NSMutableArray alloc] init];
  62. for (FChange *change in changes) {
  63. if (change.type == FIRDataEventTypeChildChanged && [self.query.index indexedValueChangedBetween:change.oldIndexedNode.node
  64. and:change.indexedNode.node]) {
  65. FChange *moveChange = [[FChange alloc] initWithType:FIRDataEventTypeChildMoved
  66. indexedNode:change.indexedNode
  67. childKey:change.childKey
  68. oldIndexedNode:nil];
  69. [moves addObject:moveChange];
  70. }
  71. }
  72. [self generateEvents:events forType:FIRDataEventTypeChildRemoved changes:changes eventCache:eventCache eventRegistrations:registrations];
  73. [self generateEvents:events forType:FIRDataEventTypeChildAdded changes:changes eventCache:eventCache eventRegistrations:registrations];
  74. [self generateEvents:events forType:FIRDataEventTypeChildMoved changes:moves eventCache:eventCache eventRegistrations:registrations];
  75. [self generateEvents:events forType:FIRDataEventTypeChildChanged changes:changes eventCache:eventCache eventRegistrations:registrations];
  76. [self generateEvents:events forType:FIRDataEventTypeValue changes:changes eventCache:eventCache eventRegistrations:registrations];
  77. return events;
  78. }
  79. - (void) generateEvents:(NSMutableArray *)events
  80. forType:(FIRDataEventType)eventType
  81. changes:(NSArray *)changes
  82. eventCache:(FIndexedNode *)eventCache
  83. eventRegistrations:(NSArray *)registrations
  84. {
  85. NSMutableArray *filteredChanges = [[NSMutableArray alloc] init];
  86. for (FChange *change in changes) {
  87. if (change.type == eventType) {
  88. [filteredChanges addObject:change];
  89. }
  90. }
  91. id<FIndex> index = self.query.index;
  92. [filteredChanges sortUsingComparator:^NSComparisonResult(FChange *one, FChange *two) {
  93. if (one.childKey == nil || two.childKey == nil) {
  94. @throw [[NSException alloc] initWithName:@"InternalInconsistencyError"
  95. reason:@"Should only compare child_ events"
  96. userInfo:nil];
  97. }
  98. return [index compareKey:one.childKey
  99. andNode:one.indexedNode.node
  100. toOtherKey:two.childKey
  101. andNode:two.indexedNode.node];
  102. }];
  103. for (FChange *change in filteredChanges) {
  104. for (id<FEventRegistration> registration in registrations) {
  105. if ([registration responseTo:eventType]) {
  106. id<FEvent> event = [self generateEventForChange:change registration:registration eventCache:eventCache];
  107. [events addObject:event];
  108. }
  109. }
  110. }
  111. }
  112. - (id<FEvent>) generateEventForChange:(FChange *)change
  113. registration:(id<FEventRegistration>)registration
  114. eventCache:(FIndexedNode *)eventCache
  115. {
  116. FChange *materializedChange;
  117. if (change.type == FIRDataEventTypeValue || change.type == FIRDataEventTypeChildRemoved) {
  118. materializedChange = change;
  119. } else {
  120. NSString *prevChildKey = [eventCache predecessorForChildKey:change.childKey
  121. childNode:change.indexedNode.node
  122. index:self.query.index];
  123. materializedChange = [change changeWithPrevKey:prevChildKey];
  124. }
  125. return [registration createEventFrom:materializedChange query:self.query];
  126. }
  127. @end