diff options
author | Paul Beusterien <paulbeusterien@google.com> | 2017-05-15 12:27:07 -0700 |
---|---|---|
committer | Paul Beusterien <paulbeusterien@google.com> | 2017-05-15 12:27:07 -0700 |
commit | 98ba64449a632518bd2b86fe8d927f4a960d3ddc (patch) | |
tree | 131d9c4272fa6179fcda6c5a33fcb3b1bd57ad2e /Firebase/Database/FEventGenerator.m | |
parent | 32461366c9e204a527ca05e6e9b9404a2454ac51 (diff) |
Initial
Diffstat (limited to 'Firebase/Database/FEventGenerator.m')
-rw-r--r-- | Firebase/Database/FEventGenerator.m | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/Firebase/Database/FEventGenerator.m b/Firebase/Database/FEventGenerator.m new file mode 100644 index 0000000..f6e8f47 --- /dev/null +++ b/Firebase/Database/FEventGenerator.m @@ -0,0 +1,141 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FEventGenerator.h" +#import "FNode.h" +#import "FIRDatabaseQuery_Private.h" +#import "FQueryParams.h" +#import "FQuerySpec.h" +#import "FChange.h" +#import "FNamedNode.h" +#import "FEventRegistration.h" +#import "FEvent.h" +#import "FDataEvent.h" + +@interface FEventGenerator () +@property (nonatomic, strong) FQuerySpec *query; +@end + +/** +* An EventGenerator is used to convert "raw" changes (fb.core.view.Change) as computed by the +* CacheDiffer into actual events (fb.core.view.Event) that can be raised. See generateEventsForChanges() +* for details. +*/ +@implementation FEventGenerator + +- (id)initWithQuery:(FQuerySpec *)query { + self = [super init]; + if (self) { + self.query = query; + } + return self; +} + +/** +* Given a set of raw changes (no moved events, and prevName not specified yet), and a set of EventRegistrations that +* should be notified of these changes, generate the actual events to be raised. +* +* Notes: +* - child_moved events will be synthesized at this time for any child_changed events that affect our index +* - prevName will be calculated based on the index ordering +* +* @param changes NSArray of FChange, not necessarily in order. +* @param registrations is NSArray of FEventRegistration. +* @return NSArray of FEvent. +*/ +- (NSArray *) generateEventsForChanges:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + eventRegistrations:(NSArray *)registrations +{ + NSMutableArray *events = [[NSMutableArray alloc] init]; + + // child_moved is index-specific, so check all our child_changed events to see if we need to materialize + // child_moved events with this view's index + NSMutableArray *moves = [[NSMutableArray alloc] init]; + for (FChange *change in changes) { + if (change.type == FIRDataEventTypeChildChanged && [self.query.index indexedValueChangedBetween:change.oldIndexedNode.node + and:change.indexedNode.node]) { + FChange *moveChange = [[FChange alloc] initWithType:FIRDataEventTypeChildMoved + indexedNode:change.indexedNode + childKey:change.childKey + oldIndexedNode:nil]; + [moves addObject:moveChange]; + } + } + + [self generateEvents:events forType:FIRDataEventTypeChildRemoved changes:changes eventCache:eventCache eventRegistrations:registrations]; + [self generateEvents:events forType:FIRDataEventTypeChildAdded changes:changes eventCache:eventCache eventRegistrations:registrations]; + [self generateEvents:events forType:FIRDataEventTypeChildMoved changes:moves eventCache:eventCache eventRegistrations:registrations]; + [self generateEvents:events forType:FIRDataEventTypeChildChanged changes:changes eventCache:eventCache eventRegistrations:registrations]; + [self generateEvents:events forType:FIRDataEventTypeValue changes:changes eventCache:eventCache eventRegistrations:registrations]; + + return events; +} + +- (void) generateEvents:(NSMutableArray *)events + forType:(FIRDataEventType)eventType + changes:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + eventRegistrations:(NSArray *)registrations +{ + NSMutableArray *filteredChanges = [[NSMutableArray alloc] init]; + for (FChange *change in changes) { + if (change.type == eventType) { + [filteredChanges addObject:change]; + } + } + + id<FIndex> index = self.query.index; + + [filteredChanges sortUsingComparator:^NSComparisonResult(FChange *one, FChange *two) { + if (one.childKey == nil || two.childKey == nil) { + @throw [[NSException alloc] initWithName:@"InternalInconsistencyError" + reason:@"Should only compare child_ events" + userInfo:nil]; + } + return [index compareKey:one.childKey + andNode:one.indexedNode.node + toOtherKey:two.childKey + andNode:two.indexedNode.node]; + }]; + + for (FChange *change in filteredChanges) { + for (id<FEventRegistration> registration in registrations) { + if ([registration responseTo:eventType]) { + id<FEvent> event = [self generateEventForChange:change registration:registration eventCache:eventCache]; + [events addObject:event]; + } + } + } +} + +- (id<FEvent>) generateEventForChange:(FChange *)change + registration:(id<FEventRegistration>)registration + eventCache:(FIndexedNode *)eventCache +{ + FChange *materializedChange; + if (change.type == FIRDataEventTypeValue || change.type == FIRDataEventTypeChildRemoved) { + materializedChange = change; + } else { + NSString *prevChildKey = [eventCache predecessorForChildKey:change.childKey + childNode:change.indexedNode.node + index:self.query.index]; + materializedChange = [change changeWithPrevKey:prevChildKey]; + } + return [registration createEventFrom:materializedChange query:self.query]; +} + +@end |