Skip to content

Commit

Permalink
implement non-nested one mapping.
Browse files Browse the repository at this point in the history
  • Loading branch information
DenTelezhkin committed Jan 7, 2015
1 parent 31483a6 commit 73ce041
Show file tree
Hide file tree
Showing 16 changed files with 232 additions and 8 deletions.
2 changes: 1 addition & 1 deletion EasyMapping/EKManagedObjectMapper.m
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ - (id)fillObject:(id)object fromExternalRepresentation:(NSDictionary *)externalR
}];
[mapping.hasOneMappings enumerateKeysAndObjectsUsingBlock:^(id key, EKRelationshipMapping * mapping, BOOL * stop)
{
NSDictionary * value = [representation valueForKeyPath:key];
NSDictionary * value = [mapping extractObjectFromRepresentation:representation];
if (value && value != (id)[NSNull null])
{
id result = [self objectFromExternalRepresentation:value withMapping:(EKManagedObjectMapping *)[mapping objectMapping]];
Expand Down
3 changes: 1 addition & 2 deletions EasyMapping/EKMapper.m
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ + (id)fillObject:(id)object fromExternalRepresentation:(NSDictionary *)externalR
fromRepresentation:representation];
}];
[mapping.hasOneMappings enumerateKeysAndObjectsUsingBlock:^(id key, EKRelationshipMapping * valueMapping, BOOL *stop) {

NSDictionary* value = [representation valueForKeyPath:key];
NSDictionary * value = [valueMapping extractObjectFromRepresentation:representation];
if (value && value != (id)[NSNull null]) {
id result = [self objectFromExternalRepresentation:value withMapping:[valueMapping objectMapping]];
[object setValue:result forKeyPath:valueMapping.property];
Expand Down
18 changes: 18 additions & 0 deletions EasyMapping/EKObjectMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,24 @@
*/
- (void)hasOne:(Class)objectClass forKeyPath:(NSString *)keyPath forProperty:(NSString *)property;

/**
Map to-one relationship, using keys that are on the same level as current object. They are collected into dictionary and passed along, as like they were in separate JSON dictionary.
@param objectClass class, instance of which will be created as a result of mapping
@param keyPaths Array of properties to collect from representation
@param property name of the property, that will receive mapped object
@param objectMapping optional mapping override for child object
@warning If you have recursive mappings, do not use this method, cause it can cause infinite recursion to happen. Or you need to handle recursive mappings situation by yourself, subclassing EKObjectMapping and providing different mappings for different mapping levels.
*/
- (void) hasOne:(Class)objectClass
forDictionaryFromKeyPaths:(NSArray *)keyPaths
forProperty:(NSString *)property
withObjectMapping:(EKObjectMapping *)objectMapping;

/**
Map to-one relationship for keyPath.
Expand Down
18 changes: 18 additions & 0 deletions EasyMapping/EKObjectMapping.m
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,24 @@ -(void)hasOne:(Class)objectClass forKeyPath:(NSString *)keyPath forProperty:(NSS
[self.hasOneMappings setObject:relationship forKey:keyPath];
}

-(void)hasOne:(Class)objectClass forDictionaryFromKeyPaths:(NSArray *)keyPaths forProperty:(NSString *)property withObjectMapping:(EKObjectMapping *)mapping
{
if (!mapping) {
NSParameterAssert([objectClass conformsToProtocol:@protocol(EKMappingProtocol)] ||
[objectClass conformsToProtocol:@protocol(EKManagedMappingProtocol)]);
}
NSParameterAssert(keyPaths);
NSParameterAssert(property);

EKRelationshipMapping * relationship = [EKRelationshipMapping new];
relationship.objectClass = objectClass;
relationship.nonNestedKeyPaths = keyPaths;
relationship.property = property;
relationship.objectMapping = mapping;

self.hasOneMappings[keyPaths.firstObject] = relationship;
}

-(void)hasMany:(Class)objectClass forKeyPath:(NSString *)keyPath
{
[self hasMany:objectClass forKeyPath:keyPath forProperty:keyPath withObjectMapping:nil];
Expand Down
4 changes: 4 additions & 0 deletions EasyMapping/EKRelationshipMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@

@property (nonatomic, strong) EKObjectMapping *objectMapping;

@property (nonatomic, strong) NSArray * nonNestedKeyPaths;

- (NSDictionary *)extractObjectFromRepresentation:(NSDictionary *)representation;

@end
21 changes: 21 additions & 0 deletions EasyMapping/EKRelationshipMapping.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,25 @@ -(EKObjectMapping*)objectMapping
return (_objectMapping == nil) ? [_objectClass objectMapping] : _objectMapping;
}

-(NSDictionary *)extractObjectFromRepresentation:(NSDictionary *)representation
{
if (self.nonNestedKeyPaths == nil)
{
return [representation valueForKeyPath:self.keyPath];
}
else {
NSMutableDictionary * values = [NSMutableDictionary dictionaryWithCapacity:self.nonNestedKeyPaths.count];

for (NSString * keyPath in self.nonNestedKeyPaths)
{
id value = [representation valueForKeyPath:keyPath];
if (value && value!=(id)[NSNull null])
{
values[keyPath] = value;
}
}
return [values copy];
}
}

@end
24 changes: 22 additions & 2 deletions EasyMapping/EKSerializer.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,17 @@ + (NSDictionary *)serializeObject:(id)object withMapping:(EKObjectMapping *)mapp
if (hasOneObject) {
NSDictionary *hasOneRepresentation = [self serializeObject:hasOneObject
withMapping:[mapping objectMapping]];
[representation setObject:hasOneRepresentation forKey:mapping.keyPath];

if (mapping.nonNestedKeyPaths)
{
for (NSString * key in hasOneRepresentation.allKeys)
{
representation[key]=hasOneRepresentation[key];
}
}
else {
[representation setObject:hasOneRepresentation forKey:mapping.keyPath];
}
}
}];
[mapping.hasManyMappings enumerateKeysAndObjectsUsingBlock:^(id key, EKRelationshipMapping *mapping, BOOL *stop) {
Expand Down Expand Up @@ -90,7 +100,17 @@ +(NSDictionary *)serializeObject:(id)object withMapping:(EKManagedObjectMapping
NSDictionary *hasOneRepresentation = [self serializeObject:hasOneObject
withMapping:(EKManagedObjectMapping *)[mapping objectMapping]
fromContext:context];
[representation setObject:hasOneRepresentation forKey:mapping.keyPath];

if (mapping.nonNestedKeyPaths)
{
for (NSString * key in hasOneRepresentation.allKeys)
{
representation[key]=hasOneRepresentation[key];
}
}
else {
[representation setObject:hasOneRepresentation forKey:mapping.keyPath];
}
}
}];
[mapping.hasManyMappings enumerateKeysAndObjectsUsingBlock:^(id key, EKRelationshipMapping *mapping, BOOL *stop) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
+ (EKManagedObjectMapping *)carNestedAttributesMapping;
+ (EKManagedObjectMapping *)carWithDateMapping;
+ (EKManagedObjectMapping *)phoneMapping;
+ (EKManagedObjectMapping *)personNonNestedMapping;
+ (EKManagedObjectMapping *)personMapping;
+ (EKManagedObjectMapping *)personWithCarMapping;
+ (EKManagedObjectMapping *)personWithPhonesMapping;
+ (EKManagedObjectMapping *)personWithOnlyValueBlockMapping;
+ (EKManagedObjectMapping *)personWithPhonesMapping;
+ (EKManagedObjectMapping *)personWithReverseBlocksMapping;

// Fake mapping, is not backed up by CoreData model
Expand Down
23 changes: 23 additions & 0 deletions EasyMappingExample/Classes/Providers/ManagedMappingProvider.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ + (EKManagedObjectMapping *)carWithRootKeyMapping
}];
}

+ (EKManagedObjectMapping *)carNonNestedMapping {
return [EKManagedObjectMapping mappingForEntityName:NSStringFromClass([ManagedCar class]) withBlock:^(EKManagedObjectMapping *mapping) {
[mapping mapPropertiesFromDictionary:@{
@"carId": @"carID",
@"carModel":@"model",
@"carYear":@"year"
}];
mapping.primaryKey = @"carID";
}];
}

+ (EKManagedObjectMapping *)carNestedAttributesMapping
{
return [EKManagedObjectMapping mappingForEntityName:NSStringFromClass([ManagedCar class])
Expand Down Expand Up @@ -72,6 +83,18 @@ + (EKManagedObjectMapping *)phoneMapping
}];
}

+(EKManagedObjectMapping *)personNonNestedMapping
{
return [EKManagedObjectMapping mappingForEntityName:NSStringFromClass([ManagedPerson class]) withBlock:
^(EKManagedObjectMapping *mapping) {
[mapping mapPropertiesFromArray:@[@"name", @"email", @"gender"]];

[mapping hasOne:[ManagedCar class] forDictionaryFromKeyPaths:@[@"carId",@"carModel",@"carYear"]
forProperty:@"car" withObjectMapping:[self carNonNestedMapping]];
mapping.primaryKey = @"personID";
}];
}

+ (EKManagedObjectMapping *)personMapping
{
return [EKManagedObjectMapping mappingForEntityName:NSStringFromClass([ManagedPerson class])
Expand Down
3 changes: 2 additions & 1 deletion EasyMappingExample/Classes/Providers/MappingProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@
+ (EKObjectMapping *)carNestedAttributesMapping;
+ (EKObjectMapping *)carWithDateMapping;
+ (EKObjectMapping *)phoneMapping;
+ (EKObjectMapping *)personNonNestedMapping;
+ (EKObjectMapping *)personMapping;
+ (EKObjectMapping *)personWithCarMapping;
+ (EKObjectMapping *)personWithPhonesMapping;
+ (EKObjectMapping *)personWithOnlyValueBlockMapping;
+ (EKObjectMapping *)personWithPhonesMapping;
+ (EKObjectMapping *)personWithRelativeMapping;
+ (EKObjectMapping *)addressMapping;
+ (EKObjectMapping *)nativeMappingWithNullPropertie;
Expand Down
27 changes: 27 additions & 0 deletions EasyMappingExample/Classes/Providers/MappingProvider.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ @implementation MappingProvider
+ (EKObjectMapping *)carMapping
{
return [EKObjectMapping mappingForClass:[Car class] withBlock:^(EKObjectMapping *mapping) {
[mapping mapKeyPath:@"id" toProperty:@"carId"];
[mapping mapPropertiesFromArray:@[@"model", @"year"]];
}];
}
Expand All @@ -48,6 +49,16 @@ + (EKObjectMapping *)carNestedAttributesMapping
}];
}

+(EKObjectMapping *)carNonNestedMapping {
return [EKObjectMapping mappingForClass:[Car class] withBlock:^(EKObjectMapping *mapping) {
[mapping mapPropertiesFromDictionary:@{
@"carId": @"carId",
@"carModel":@"model",
@"carYear":@"year"
}];
}];
}

+ (EKObjectMapping *)carWithDateMapping
{
return [EKObjectMapping mappingForClass:[Car class] withBlock:^(EKObjectMapping *mapping) {
Expand All @@ -67,6 +78,22 @@ + (EKObjectMapping *)phoneMapping
}];
}

+(EKObjectMapping *)personNonNestedMapping
{
return [EKObjectMapping mappingForClass:[Person class] withBlock:^(EKObjectMapping *mapping) {
NSDictionary *genders = @{ @"male": @(GenderMale), @"female": @(GenderFemale) };
[mapping mapPropertiesFromArray:@[@"name", @"email"]];
[mapping mapKeyPath:@"gender" toProperty:@"gender" withValueBlock:^(NSString *key, id value) {
return genders[value];
} reverseBlock:^id(id value) {
return [genders allKeysForObject:value].lastObject;
}];

[mapping hasOne:[Car class] forDictionaryFromKeyPaths:@[@"carId",@"carModel",@"carYear"]
forProperty:@"car" withObjectMapping:[self carNonNestedMapping]];
}];
}

+ (EKObjectMapping *)personMapping
{
return [EKObjectMapping mappingForClass:[Person class] withBlock:^(EKObjectMapping *mapping) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@
9A4512F519166366006E6022 /* PersonWithNullPhones.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A45121119164705006E6022 /* PersonWithNullPhones.json */; };
9A4512F619166366006E6022 /* Plane.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A45121219164705006E6022 /* Plane.json */; };
9A4512F819166B8E006E6022 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9A4512F719166B8E006E6022 /* MainMenu.xib */; };
9A4B86521A5D463500EE9135 /* PersonNonNested.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A4B86511A5D463500EE9135 /* PersonNonNested.json */; };
9A4B86531A5D463500EE9135 /* PersonNonNested.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A4B86511A5D463500EE9135 /* PersonNonNested.json */; };
9A8420DC19570689006DDDE3 /* BaseManagedTestModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2056A41956E0EE00499FC3 /* BaseManagedTestModel.m */; };
9A8420DD1957068A006DDDE3 /* BaseManagedTestModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2056A41956E0EE00499FC3 /* BaseManagedTestModel.m */; };
9A8420DE1957068D006DDDE3 /* BaseTestModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2056A01956DF7900499FC3 /* BaseTestModel.m */; };
Expand Down Expand Up @@ -380,6 +382,7 @@
9A4512D219165B46006E6022 /* EKCoreDataBenchmarkSuite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EKCoreDataBenchmarkSuite.h; path = Benchmarks/Classes/Becnhmark/EKCoreDataBenchmarkSuite.h; sourceTree = "<group>"; };
9A4512D319165B46006E6022 /* EKCoreDataBenchmarkSuite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EKCoreDataBenchmarkSuite.m; path = Benchmarks/Classes/Becnhmark/EKCoreDataBenchmarkSuite.m; sourceTree = "<group>"; };
9A4512F719166B8E006E6022 /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = MainMenu.xib; path = "Benchmarks/Targets/MacOS Benchmark/MainMenu.xib"; sourceTree = SOURCE_ROOT; };
9A4B86511A5D463500EE9135 /* PersonNonNested.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = PersonNonNested.json; sourceTree = SOURCE_ROOT; };
9A8420E01957164E006DDDE3 /* EKObjectModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EKObjectModel.h; sourceTree = "<group>"; };
9A8420E11957164E006DDDE3 /* EKObjectModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EKObjectModel.m; sourceTree = "<group>"; };
9A8420E6195718A2006DDDE3 /* EKManagedObjectModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EKManagedObjectModel.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -493,6 +496,7 @@
9A45120C19164705006E6022 /* Native.json */,
9A45120D19164705006E6022 /* NativeChild.json */,
9A45120E19164705006E6022 /* Person.json */,
9A4B86511A5D463500EE9135 /* PersonNonNested.json */,
9A210F391944B81500871071 /* PersonRecursive.json */,
9A45120F19164705006E6022 /* PersonWithDifferentNaming.json */,
9A45121019164705006E6022 /* PersonWithNullCar.json */,
Expand Down Expand Up @@ -1018,6 +1022,7 @@
9A45124319164705006E6022 /* PersonWithDifferentNaming.json in Resources */,
9A45124F19164705006E6022 /* Plane.json in Resources */,
9A45123B19164705006E6022 /* NativeChild.json in Resources */,
9A4B86521A5D463500EE9135 /* PersonNonNested.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1046,6 +1051,7 @@
9A45124419164705006E6022 /* PersonWithDifferentNaming.json in Resources */,
9A45125019164705006E6022 /* Plane.json in Resources */,
9A45123C19164705006E6022 /* NativeChild.json in Resources */,
9A4B86531A5D463500EE9135 /* PersonNonNested.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
10 changes: 10 additions & 0 deletions EasyMappingExample/PersonNonNested.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id":23,
"name": "Lucas",
"email": "[email protected]",
"gender" : "male",
"carId":3,
"carModel":"i30",
"carYear":"2013",
"phones": null
}
27 changes: 26 additions & 1 deletion EasyMappingExample/Tests/Specs/EKManagedObjectMapperSpec.m
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,32 @@
describe(@".syncArrayOfObjectsFromExternalRepresentation:withMapping:fetchRequest:", ^{

});


context(@"hasOneMapping with several non nested keys", ^{
__block ManagedPerson * person = nil;

beforeEach(^{
NSDictionary * externalRepresentation = [CMFixture buildUsingFixture:@"PersonNonNested"];
[ManagedPerson registerMapping:[ManagedMappingProvider personNonNestedMapping]];
person = [EKManagedObjectMapper objectFromExternalRepresentation:externalRepresentation
withMapping:[ManagedMappingProvider personNonNestedMapping]
inManagedObjectContext:[NSManagedObjectContext MR_defaultContext]];
});

it(@"should contain car", ^{
[[person.car should] beKindOfClass:[ManagedCar class]];
});

it(@"should have correct name", ^{
[[person.name should] equal:@"Lucas"];
});

it(@"should have correct car properties", ^{
[[person.car.carID should] equal:@3];
[[person.car.model should] equal:@"i30"];
[[person.car.year should] equal:@"2013"];
});
});
});

SPEC_END
24 changes: 24 additions & 0 deletions EasyMappingExample/Tests/Specs/EKMapperSpec.m
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,30 @@

});

context(@"hasOneMapping with several non nested keys", ^{
__block Person * person = nil;

beforeEach(^{
NSDictionary * externalRepresentation = [CMFixture buildUsingFixture:@"PersonNonNested"];
[Person registerMapping:[MappingProvider personNonNestedMapping]];
person = [EKMapper objectFromExternalRepresentation:externalRepresentation
withMapping:[MappingProvider personNonNestedMapping]];
});

it(@"should contain car", ^{
[[person.car should] beKindOfClass:[Car class]];
});

it(@"should have correct name", ^{
[[person.name should] equal:@"Lucas"];
});

it(@"should have correct car properties", ^{
[[@(person.car.carId) should] equal:@3];
[[person.car.model should] equal:@"i30"];
[[person.car.year should] equal:@"2013"];
});
});
});

SPEC_END
Expand Down
Loading

0 comments on commit 73ce041

Please sign in to comment.