Files
firebase-ios-sdk/Firebase/Database/FEventGenerator.m
T

169 lines
6.2 KiB
Objective-C
Raw Normal View History

2017-05-15 12:27:07 -07:00
/*
* 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"
2019-08-05 13:27:47 -07:00
#import "FChange.h"
#import "FDataEvent.h"
#import "FEvent.h"
#import "FEventRegistration.h"
2017-05-15 12:27:07 -07:00
#import "FIRDatabaseQuery_Private.h"
2019-08-05 13:27:47 -07:00
#import "FNamedNode.h"
#import "FNode.h"
2017-05-15 12:27:07 -07:00
#import "FQueryParams.h"
#import "FQuerySpec.h"
@interface FEventGenerator ()
2019-08-05 13:27:47 -07:00
@property(nonatomic, strong) FQuerySpec *query;
2017-05-15 12:27:07 -07:00
@end
/**
2019-08-05 13:27:47 -07:00
* 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.
*/
2017-05-15 12:27:07 -07:00
@implementation FEventGenerator
- (id)initWithQuery:(FQuerySpec *)query {
self = [super init];
if (self) {
self.query = query;
}
return self;
}
/**
2019-08-05 13:27:47 -07:00
* 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 {
2017-05-15 12:27:07 -07:00
NSMutableArray *events = [[NSMutableArray alloc] init];
2019-08-05 13:27:47 -07:00
// 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
2017-05-15 12:27:07 -07:00
NSMutableArray *moves = [[NSMutableArray alloc] init];
for (FChange *change in changes) {
2019-08-05 13:27:47 -07:00
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];
2017-05-15 12:27:07 -07:00
[moves addObject:moveChange];
}
}
2019-08-05 13:27:47 -07:00
[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];
2017-05-15 12:27:07 -07:00
return events;
}
2019-08-05 13:27:47 -07:00
- (void)generateEvents:(NSMutableArray *)events
forType:(FIRDataEventType)eventType
changes:(NSArray *)changes
eventCache:(FIndexedNode *)eventCache
eventRegistrations:(NSArray *)registrations {
2017-05-15 12:27:07 -07:00
NSMutableArray *filteredChanges = [[NSMutableArray alloc] init];
for (FChange *change in changes) {
if (change.type == eventType) {
[filteredChanges addObject:change];
}
}
id<FIndex> index = self.query.index;
2019-08-05 13:27:47 -07:00
[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];
}];
2017-05-15 12:27:07 -07:00
for (FChange *change in filteredChanges) {
for (id<FEventRegistration> registration in registrations) {
if ([registration responseTo:eventType]) {
2019-08-05 13:27:47 -07:00
id<FEvent> event = [self generateEventForChange:change
registration:registration
eventCache:eventCache];
2017-05-15 12:27:07 -07:00
[events addObject:event];
}
}
}
}
2019-08-05 13:27:47 -07:00
- (id<FEvent>)generateEventForChange:(FChange *)change
registration:(id<FEventRegistration>)registration
eventCache:(FIndexedNode *)eventCache {
2017-05-15 12:27:07 -07:00
FChange *materializedChange;
2019-08-05 13:27:47 -07:00
if (change.type == FIRDataEventTypeValue ||
change.type == FIRDataEventTypeChildRemoved) {
2017-05-15 12:27:07 -07:00
materializedChange = change;
} else {
2019-08-05 13:27:47 -07:00
NSString *prevChildKey =
[eventCache predecessorForChildKey:change.childKey
childNode:change.indexedNode.node
index:self.query.index];
2017-05-15 12:27:07 -07:00
materializedChange = [change changeWithPrevKey:prevChildKey];
}
return [registration createEventFrom:materializedChange query:self.query];
}
@end