Fix bug with mapping nested attribute values with identification attributes when the identification attribute is not the nesting key. fixes #1129

This commit is contained in:
Blake Watters
2013-01-17 11:34:40 -05:00
parent a2ca2ec937
commit a65a50e8f7
3 changed files with 43 additions and 35 deletions

View File

@@ -54,23 +54,6 @@ static BOOL RKEntityMappingIsIdentifiedByNestingAttribute(RKEntityMapping *entit
return NO;
}
// We always need to map the dynamic nesting attribute first so that sub-key attribute mappings apply cleanly
static NSArray *RKEntityIdentificationAttributesInMappingOrder(RKEntityMapping *entityMapping)
{
NSMutableArray *orderedAttributes = [NSMutableArray arrayWithCapacity:[[entityMapping identificationAttributes] count]];
for (NSAttributeDescription *attribute in [entityMapping identificationAttributes]) {
RKAttributeMapping *attributeMapping = [[entityMapping propertyMappingsByDestinationKeyPath] objectForKey:[attribute name]];
if ([attributeMapping.sourceKeyPath isEqualToString:RKObjectMappingNestingAttributeKeyName]) {
// We want to map the nesting attribute first
[orderedAttributes insertObject:attribute atIndex:0];
} else {
[orderedAttributes addObject:attribute];
}
}
return orderedAttributes;
}
static id RKValueForAttributeMappingInRepresentation(RKAttributeMapping *attributeMapping, NSDictionary *representation)
{
if ([attributeMapping.sourceKeyPath isEqualToString:RKObjectMappingNestingAttributeKeyName]) {
@@ -96,25 +79,23 @@ static NSDictionary *RKEntityIdentificationAttributesForEntityMappingWithReprese
{
RKDateToStringValueTransformer *dateToStringTransformer = [[RKDateToStringValueTransformer alloc] initWithDateToStringFormatter:entityMapping.preferredDateFormatter
stringToDateFormatters:entityMapping.dateFormatters];
NSArray *orderedAttributes = RKEntityIdentificationAttributesInMappingOrder(entityMapping);
BOOL containsNestingAttribute = RKEntityMappingIsIdentifiedByNestingAttribute(entityMapping);
__block NSArray *attributeMappings = entityMapping.attributeMappings;
if (containsNestingAttribute) RKLogDebug(@"Detected use of nested dictionary key as identifying attribute");
NSMutableDictionary *entityIdentifierAttributes = [NSMutableDictionary dictionaryWithCapacity:[orderedAttributes count]];
[orderedAttributes enumerateObjectsUsingBlock:^(NSAttributeDescription *attribute, NSUInteger idx, BOOL *stop) {
NSArray *attributeMappings = entityMapping.attributeMappings;
// If the representation is mapped with a nesting attribute, we must apply the nesting value to the representation before constructing the identification attributes
RKAttributeMapping *nestingAttributeMapping = [[entityMapping propertyMappingsBySourceKeyPath] objectForKey:RKObjectMappingNestingAttributeKeyName];
if (nestingAttributeMapping) {
Class attributeClass = [entityMapping classForProperty:nestingAttributeMapping.destinationKeyPath];
id attributeValue = RKTransformedValueWithClass([[representation allKeys] lastObject], attributeClass, dateToStringTransformer);
attributeMappings = RKApplyNestingAttributeValueToMappings(nestingAttributeMapping.destinationKeyPath, attributeValue, attributeMappings);
}
// Map the identification attributes
NSMutableDictionary *entityIdentifierAttributes = [NSMutableDictionary dictionaryWithCapacity:[entityMapping.identificationAttributes count]];
[entityMapping.identificationAttributes enumerateObjectsUsingBlock:^(NSAttributeDescription *attribute, NSUInteger idx, BOOL *stop) {
RKAttributeMapping *attributeMapping = RKAttributeMappingForNameInMappings([attribute name], attributeMappings);
Class attributeClass = [entityMapping classForProperty:[attribute name]];
id attributeValue = nil;
if (containsNestingAttribute && idx == 0) {
// This is the nesting attribute
attributeValue = RKTransformedValueWithClass([[representation allKeys] lastObject], attributeClass, dateToStringTransformer);
attributeMappings = RKApplyNestingAttributeValueToMappings([attribute name], attributeValue, attributeMappings);
} else {
id sourceValue = RKValueForAttributeMappingInRepresentation(attributeMapping, representation);
attributeValue = RKTransformedValueWithClass(sourceValue, attributeClass, dateToStringTransformer);
}
id sourceValue = RKValueForAttributeMappingInRepresentation(attributeMapping, representation);
id attributeValue = RKTransformedValueWithClass(sourceValue, attributeClass, dateToStringTransformer);
[entityIdentifierAttributes setObject:attributeValue ?: [NSNull null] forKey:[attribute name]];
}];