Fix of RKObjectMappingOperation does not respect forceCollectionMapping (Issue 341)

Includes test cases and fixtures
This commit is contained in:
Björn Jonsson
2011-09-14 22:50:03 +02:00
parent 64d496672e
commit 90ef91e890
4 changed files with 236 additions and 4 deletions

View File

@@ -355,6 +355,22 @@ BOOL RKObjectIsValueEqualToValue(id sourceValue, id destinationValue) {
continue;
}
// Handle case where incoming content is collection represented by a dictionary
if (relationshipMapping.mapping.forceCollectionMapping) {
// If we have forced mapping of a dictionary, map each subdictionary
if ([value isKindOfClass:[NSDictionary class]]) {
RKLogDebug(@"Collection mapping forced for NSDictionary, mapping each key/value independently...");
NSArray* objectsToMap = [NSMutableArray arrayWithCapacity:[value count]];
for (id key in value) {
NSDictionary* dictionaryToMap = [NSDictionary dictionaryWithObject:[value valueForKey:key] forKey:key];
[(NSMutableArray*)objectsToMap addObject:dictionaryToMap];
}
value = objectsToMap;
} else {
RKLogWarning(@"Collection mapping forced but mappable objects is of type '%@' rather than NSDictionary", NSStringFromClass([value class]));
}
}
// Handle case where incoming content is a single object, but we want a collection
Class relationshipType = [self.objectMapping classForProperty:relationshipMapping.destinationKeyPath];
BOOL mappingToCollection = (relationshipType &&

View File

@@ -62,7 +62,7 @@
251939E913AABED40073A39B /* DynamicKeys.json in Resources */ = {isa = PBXBuildFile; fileRef = 251939E613AABED40073A39B /* DynamicKeys.json */; };
251939EA13AABED40073A39B /* error.json in Resources */ = {isa = PBXBuildFile; fileRef = 251939E713AABED40073A39B /* error.json */; };
251939EB13AABED40073A39B /* errors.json in Resources */ = {isa = PBXBuildFile; fileRef = 251939E813AABED40073A39B /* errors.json */; };
251939ED13ABA06D0073A39B /* DynamicKeysWithRelationship.json in Resources */ = {isa = PBXBuildFile; fileRef = 251939EC13ABA06D0073A39B /* DynamicKeysWithRelationship.json */; };
251939ED13ABA06D0073A39B /* DynamicKeysWithNestedRelationship.json in Resources */ = {isa = PBXBuildFile; fileRef = 251939EC13ABA06D0073A39B /* DynamicKeysWithNestedRelationship.json */; };
251D14AC133597B800959061 /* RKManagedObjectLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 251D14AA133597B800959061 /* RKManagedObjectLoader.h */; settings = {ATTRIBUTES = (Public, ); }; };
251D14AD133597B800959061 /* RKManagedObjectLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 251D14AB133597B800959061 /* RKManagedObjectLoader.m */; };
2523363E11E7A1F00048F9B4 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F6C3A9510FE7524008F47C5 /* UIKit.framework */; };
@@ -303,6 +303,7 @@
3F71ED3413748536006281CA /* RKObjectMappingProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F71ED3213748536006281CA /* RKObjectMappingProvider.h */; settings = {ATTRIBUTES = (Public, ); }; };
3F71ED3513748536006281CA /* RKObjectMappingProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F71ED3313748536006281CA /* RKObjectMappingProvider.m */; };
3FD12C851379AD64008B996A /* RKRouter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FD12C841379AD64008B996A /* RKRouter.h */; settings = {ATTRIBUTES = (Public, ); }; };
40A0C79C14212B3B00D36DD2 /* DynamicKeysWithRelationship.json in Resources */ = {isa = PBXBuildFile; fileRef = 409341EC14211E7900EF4609 /* DynamicKeysWithRelationship.json */; };
57D7EA2713D98672000E4E63 /* NSNumberCreator.m in Sources */ = {isa = PBXBuildFile; fileRef = 57D7EA2213D98672000E4E63 /* NSNumberCreator.m */; };
57D7EA2813D98672000E4E63 /* UIConsoleLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 57D7EA2313D98672000E4E63 /* UIConsoleLog.m */; };
57D7EA2913D98672000E4E63 /* UIExpectation.m in Sources */ = {isa = PBXBuildFile; fileRef = 57D7EA2413D98672000E4E63 /* UIExpectation.m */; };
@@ -465,7 +466,7 @@
251939E613AABED40073A39B /* DynamicKeys.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DynamicKeys.json; sourceTree = "<group>"; };
251939E713AABED40073A39B /* error.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = error.json; sourceTree = "<group>"; };
251939E813AABED40073A39B /* errors.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = errors.json; sourceTree = "<group>"; };
251939EC13ABA06D0073A39B /* DynamicKeysWithRelationship.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DynamicKeysWithRelationship.json; sourceTree = "<group>"; };
251939EC13ABA06D0073A39B /* DynamicKeysWithNestedRelationship.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = DynamicKeysWithNestedRelationship.json; sourceTree = "<group>"; };
251D14AA133597B800959061 /* RKManagedObjectLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKManagedObjectLoader.h; sourceTree = "<group>"; };
251D14AB133597B800959061 /* RKManagedObjectLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKManagedObjectLoader.m; sourceTree = "<group>"; };
2523360511E79F090048F9B4 /* libRestKitThree20.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRestKitThree20.a; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -739,6 +740,7 @@
3F71ED3213748536006281CA /* RKObjectMappingProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKObjectMappingProvider.h; sourceTree = "<group>"; };
3F71ED3313748536006281CA /* RKObjectMappingProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectMappingProvider.m; sourceTree = "<group>"; };
3FD12C841379AD64008B996A /* RKRouter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RKRouter.h; path = Code/ObjectMapping/RKRouter.h; sourceTree = SOURCE_ROOT; };
409341EC14211E7900EF4609 /* DynamicKeysWithRelationship.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = DynamicKeysWithRelationship.json; sourceTree = "<group>"; };
57D7EA2213D98672000E4E63 /* NSNumberCreator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = NSNumberCreator.m; path = ../UISpecRunner/NSNumberCreator.m; sourceTree = "<group>"; };
57D7EA2313D98672000E4E63 /* UIConsoleLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = UIConsoleLog.m; path = ../UISpecRunner/UIConsoleLog.m; sourceTree = "<group>"; };
57D7EA2413D98672000E4E63 /* UIExpectation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = UIExpectation.m; path = ../UISpecRunner/UIExpectation.m; sourceTree = "<group>"; };
@@ -1402,7 +1404,8 @@
children = (
252CF8B713E255B90093BBD6 /* Dynamic */,
2515E7B913B36A7D00E013A4 /* ArrayOfResults.json */,
251939EC13ABA06D0073A39B /* DynamicKeysWithRelationship.json */,
409341EC14211E7900EF4609 /* DynamicKeysWithRelationship.json */,
251939EC13ABA06D0073A39B /* DynamicKeysWithNestedRelationship.json */,
251939E613AABED40073A39B /* DynamicKeys.json */,
251939E713AABED40073A39B /* error.json */,
251939E813AABED40073A39B /* errors.json */,
@@ -2023,6 +2026,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
40A0C79C14212B3B00D36DD2 /* DynamicKeysWithRelationship.json in Resources */,
25952EE1136F563E00D04F93 /* blake.png in Resources */,
25952EE2136F563E00D04F93 /* ComplexNestedUser.json in Resources */,
25952EE3136F563E00D04F93 /* Foursquare.json in Resources */,
@@ -2036,7 +2040,7 @@
251939E913AABED40073A39B /* DynamicKeys.json in Resources */,
251939EA13AABED40073A39B /* error.json in Resources */,
251939EB13AABED40073A39B /* errors.json in Resources */,
251939ED13ABA06D0073A39B /* DynamicKeysWithRelationship.json in Resources */,
251939ED13ABA06D0073A39B /* DynamicKeysWithNestedRelationship.json in Resources */,
25BA443513ABB34900ADC7D0 /* tab_data.xml in Resources */,
2515E7BA13B36A7D00E013A4 /* ArrayOfResults.json in Resources */,
252CF8B913E255D70093BBD6 /* boy.json in Resources */,

View File

@@ -0,0 +1,33 @@
{
"groups":[
{
"name":"restkit",
"users": {
"blake": {
"id": 31337,
"website": "http://restkit.org/"
},
"rachit": {
"id": 7,
"website": "http://www.twotoasters.com/",
"address": {
"city": "New York",
"state": "New York"
}
}
}
},
{
"name":"others",
"users":{
"bjorn": {
"id": 10,
"address": {
"city": "Gothenburg",
"country": "Sweden"
}
}
}
}
]
}

View File

@@ -136,6 +136,68 @@
@end
@interface RKExampleGroupWithUserArray : NSObject {
NSString * _name;
NSArray* _users;
}
@property (nonatomic, retain) NSString* name;
@property (nonatomic, retain) NSArray* users;
@end
@implementation RKExampleGroupWithUserArray
@synthesize name = _name;
@synthesize users = _users;
+ (RKExampleGroupWithUserArray*)group {
return [[self new] autorelease];
}
// isEqual: is consulted by the mapping operation
// to determine if assocation values should be set
- (BOOL)isEqual:(id)object {
if ([object isKindOfClass:[RKExampleGroupWithUserArray class]]) {
return [[(RKExampleGroupWithUserArray*)object name] isEqualToString:self.name];
} else {
return NO;
}
}
@end
@interface RKExampleGroupWithUserSet : NSObject {
NSString * _name;
NSSet* _users;
}
@property (nonatomic, retain) NSString* name;
@property (nonatomic, retain) NSSet* users;
@end
@implementation RKExampleGroupWithUserSet
@synthesize name = _name;
@synthesize users = _users;
+ (RKExampleGroupWithUserSet*)group {
return [[self new] autorelease];
}
// isEqual: is consulted by the mapping operation
// to determine if assocation values should be set
- (BOOL)isEqual:(id)object {
if ([object isKindOfClass:[RKExampleGroupWithUserSet class]]) {
return [[(RKExampleGroupWithUserSet*)object name] isEqualToString:self.name];
} else {
return NO;
}
}
@end
////////////////////////////////////////////////////////////////////////////////
#pragma mark -
@@ -454,6 +516,123 @@
[expectThat(user.address.city) should:be(@"New York")];
}
- (void)itShouldMapANestedArrayOfObjectsWithDynamicKeysAndArrayRelationships {
RKObjectMapping* mapping = [RKObjectMapping mappingForClass:[RKExampleGroupWithUserArray class]];
[mapping mapAttributes:@"name", nil];
RKObjectMapping* userMapping = [RKObjectMapping mappingForClass:[RKExampleUser class]];
userMapping.forceCollectionMapping = YES;
[userMapping mapKeyOfNestedDictionaryToAttribute:@"name"];
[mapping mapKeyPath:@"users" toRelationship:@"users" withMapping:userMapping];
RKObjectMapping* addressMapping = [RKObjectMapping mappingForClass:[RKSpecAddress class]];
[addressMapping mapAttributes:
@"city", @"city",
@"state", @"state",
@"country", @"country",
nil
];
[userMapping mapKeyPath:@"(name).address" toRelationship:@"address" withMapping:addressMapping];
RKObjectMappingProvider* provider = [[RKObjectMappingProvider new] autorelease];
[provider setMapping:mapping forKeyPath:@"groups"];
id userInfo = RKSpecParseFixture(@"DynamicKeysWithNestedRelationship.json");
RKObjectMapper* mapper = [RKObjectMapper mapperWithObject:userInfo mappingProvider:provider];
RKObjectMappingResult* result = [mapper performMapping];
NSArray* groups = [result asCollection];
[expectThat([groups isKindOfClass:[NSArray class]]) should:be(YES)];
[expectThat([groups count]) should:be(2)];
RKExampleGroupWithUserArray* group = [groups objectAtIndex:0];
[expectThat([group isKindOfClass:[RKExampleGroupWithUserArray class]]) should:be(YES)];
[expectThat(group.name) should:be(@"restkit")];
NSArray * users = group.users;
[expectThat([users count]) should:be(2)];
RKExampleUser* user = [users objectAtIndex:0];
[expectThat([user isKindOfClass:[RKExampleUser class]]) should:be(YES)];
[expectThat(user.name) should:be(@"blake")];
user = [users objectAtIndex:1];
[expectThat([user isKindOfClass:[RKExampleUser class]]) should:be(YES)];
[expectThat(user.name) should:be(@"rachit")];
[expectThat(user.address) shouldNot:be(nil)];
[expectThat(user.address.city) should:be(@"New York")];
group = [groups objectAtIndex:1];
[expectThat([group isKindOfClass:[RKExampleGroupWithUserArray class]]) should:be(YES)];
[expectThat(group.name) should:be(@"others")];
users = group.users;
[expectThat([users count]) should:be(1)];
user = [users objectAtIndex:0];
[expectThat([user isKindOfClass:[RKExampleUser class]]) should:be(YES)];
[expectThat(user.name) should:be(@"bjorn")];
[expectThat(user.address) shouldNot:be(nil)];
[expectThat(user.address.city) should:be(@"Gothenburg")];
[expectThat(user.address.country) should:be(@"Sweden")];
}
- (void)itShouldMapANestedArrayOfObjectsWithDynamicKeysAndSetRelationships {
RKObjectMapping* mapping = [RKObjectMapping mappingForClass:[RKExampleGroupWithUserSet class]];
[mapping mapAttributes:@"name", nil];
RKObjectMapping* userMapping = [RKObjectMapping mappingForClass:[RKExampleUser class]];
userMapping.forceCollectionMapping = YES;
[userMapping mapKeyOfNestedDictionaryToAttribute:@"name"];
[mapping mapKeyPath:@"users" toRelationship:@"users" withMapping:userMapping];
RKObjectMapping* addressMapping = [RKObjectMapping mappingForClass:[RKSpecAddress class]];
[addressMapping mapAttributes:
@"city", @"city",
@"state", @"state",
@"country", @"country",
nil
];
[userMapping mapKeyPath:@"(name).address" toRelationship:@"address" withMapping:addressMapping];
RKObjectMappingProvider* provider = [[RKObjectMappingProvider new] autorelease];
[provider setMapping:mapping forKeyPath:@"groups"];
id userInfo = RKSpecParseFixture(@"DynamicKeysWithNestedRelationship.json");
RKObjectMapper* mapper = [RKObjectMapper mapperWithObject:userInfo mappingProvider:provider];
RKObjectMappingResult* result = [mapper performMapping];
NSArray* groups = [result asCollection];
[expectThat([groups isKindOfClass:[NSArray class]]) should:be(YES)];
[expectThat([groups count]) should:be(2)];
RKExampleGroupWithUserSet* group = [groups objectAtIndex:0];
[expectThat([group isKindOfClass:[RKExampleGroupWithUserSet class]]) should:be(YES)];
[expectThat(group.name) should:be(@"restkit")];
NSSortDescriptor * sortByName =[[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES] autorelease];
NSArray * descriptors = [NSArray arrayWithObject:sortByName];;
NSArray * users = [group.users sortedArrayUsingDescriptors:descriptors];
[expectThat([users count]) should:be(2)];
RKExampleUser* user = [users objectAtIndex:0];
[expectThat([user isKindOfClass:[RKExampleUser class]]) should:be(YES)];
[expectThat(user.name) should:be(@"blake")];
user = [users objectAtIndex:1];
[expectThat([user isKindOfClass:[RKExampleUser class]]) should:be(YES)];
[expectThat(user.name) should:be(@"rachit")];
[expectThat(user.address) shouldNot:be(nil)];
[expectThat(user.address.city) should:be(@"New York")];
group = [groups objectAtIndex:1];
[expectThat([group isKindOfClass:[RKExampleGroupWithUserSet class]]) should:be(YES)];
[expectThat(group.name) should:be(@"others")];
users = [group.users sortedArrayUsingDescriptors:descriptors];
[expectThat([users count]) should:be(1)];
user = [users objectAtIndex:0];
[expectThat([user isKindOfClass:[RKExampleUser class]]) should:be(YES)];
[expectThat(user.name) should:be(@"bjorn")];
[expectThat(user.address) shouldNot:be(nil)];
[expectThat(user.address.city) should:be(@"Gothenburg")];
[expectThat(user.address.country) should:be(@"Sweden")];
}
- (void)itShouldBeAbleToMapFromAUserObjectToADictionary {
RKObjectMapping* mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
RKObjectAttributeMapping* idMapping = [RKObjectAttributeMapping mappingFromKeyPath:@"userID" toKeyPath:@"id"];