Browse files

Add support for skipping an aggregate relationship mapping in the eve…

…nt 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
  • Loading branch information...
1 parent d024a51 commit a03191c29165a79a785a17ac8ea498f6659b3263 @blakewatters blakewatters committed Dec 31, 2012
Showing with 46 additions and 2 deletions.
  1. +29 −2 Code/ObjectMapping/RKMappingOperation.m
  2. +17 −0 Tests/Logic/ObjectMapping/RKObjectMappingNextGenTest.m
View
31 Code/ObjectMapping/RKMappingOperation.m
@@ -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 @@ - (BOOL)applyRelationshipMappings
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
17 Tests/Logic/ObjectMapping/RKObjectMappingNextGenTest.m
@@ -2414,4 +2414,21 @@ - (void)testAggregatingPropertyMappingUsingNilKeyPath
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

0 comments on commit a03191c

Please sign in to comment.