Add support for skipping an aggregate relationship mapping in the event that the parent representation does not contain any values for the property mappings of the concrete RKObjectMapping configured for the relationship. fixes #1114, closes #1115

This commit is contained in:
Blake Watters
2012-12-31 17:33:41 -05:00
parent d024a518a4
commit a03191c291
2 changed files with 46 additions and 2 deletions

View File

@@ -198,6 +198,15 @@ static void RKSetValueForObject(id value, id destinationObject)
}
}
// Returns YES if there is a value present for at least one key path in the given collection
static BOOL RKObjectContainsValueForKeyPaths(id representation, NSArray *keyPaths)
{
for (NSString *keyPath in keyPaths) {
if ([representation valueForKeyPath:keyPath]) return YES;
}
return NO;
}
@interface RKMappingOperation ()
@property (nonatomic, strong, readwrite) RKMapping *mapping;
@property (nonatomic, strong, readwrite) id sourceObject;
@@ -599,8 +608,26 @@ static void RKSetValueForObject(id value, id destinationObject)
for (RKRelationshipMapping *relationshipMapping in [self relationshipMappings]) {
if ([self isCancelled]) return NO;
// The nil source keyPath indicates that we want to map directly from the parent representation
id value = (relationshipMapping.sourceKeyPath == nil) ? self.sourceObject : [self.sourceObject valueForKeyPath:relationshipMapping.sourceKeyPath];
id value = nil;
if (relationshipMapping.sourceKeyPath) {
value = [self.sourceObject valueForKeyPath:relationshipMapping.sourceKeyPath];
} else {
// The nil source keyPath indicates that we want to map directly from the parent representation
value = self.sourceObject;
RKObjectMapping *objectMapping = nil;
if ([relationshipMapping.mapping isKindOfClass:[RKObjectMapping class]]) {
objectMapping = (RKObjectMapping *)relationshipMapping.mapping;
} else if ([relationshipMapping.mapping isKindOfClass:[RKDynamicMapping class]]) {
objectMapping = [(RKDynamicMapping *)relationshipMapping.mapping objectMappingForRepresentation:value];
}
if (! objectMapping) continue; // Mapping declined
NSArray *propertyKeyPaths = [relationshipMapping valueForKeyPath:@"mapping.propertyMappings.sourceKeyPath"];
if (! RKObjectContainsValueForKeyPaths(value, propertyKeyPaths)) {
continue;
}
}
// Track that we applied this mapping
[mappingsApplied addObject:relationshipMapping];

View File

@@ -2414,4 +2414,21 @@
expect(user.coordinate.longitude).to.equal(200.5);
}
- (void)testThatAggregatedRelationshipMappingsAreOnlyAppliedIfThereIsAtLeastOneValueInTheRepresentation
{
NSDictionary *objectRepresentation = @{ @"name": @"Blake" };
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]];
[userMapping addAttributeMappingsFromArray:@[ @"name" ]];
RKObjectMapping *coordinateMapping = [RKObjectMapping mappingForClass:[RKTestCoordinate class]];
[coordinateMapping addAttributeMappingsFromArray:@[ @"latitude", @"longitude" ]];
[userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil toKeyPath:@"coordinate" withMapping:coordinateMapping]];
RKTestUser *user = [RKTestUser new];
RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:objectRepresentation destinationObject:user mapping:userMapping];
RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new];
mappingOperation.dataSource = dataSource;
[mappingOperation start];
expect(mappingOperation.error).to.beNil();
expect(user.coordinate).to.beNil();
}
@end