From f4240804aa29bc12267c7dbfdb53c18e79e70cb2 Mon Sep 17 00:00:00 2001 From: Denys Telezhkin Date: Sun, 7 Dec 2014 16:08:45 +0200 Subject: [PATCH] add CoreData serialization methods, that use NSManagedObjectContext. --- EasyMapping/EKSerializer.h | 30 +++++++++ EasyMapping/EKSerializer.m | 63 +++++++++++++++++++ .../Classes/Models/ManagedPerson.h | 1 + .../Classes/Models/ManagedPerson.m | 1 + .../Providers/ManagedMappingProvider.h | 1 + .../Providers/ManagedMappingProvider.m | 29 +++++++++ .../Tests/Specs/EKSerializerSpec.m | 41 ++++++++++++ 7 files changed, 166 insertions(+) diff --git a/EasyMapping/EKSerializer.h b/EasyMapping/EKSerializer.h index 773b666..3be6147 100644 --- a/EasyMapping/EKSerializer.h +++ b/EasyMapping/EKSerializer.h @@ -23,6 +23,7 @@ #import "EKObjectMapping.h" #import "EKSerializer.h" +#import "EKManagedObjectMapping.h" /** `EKSerializer` is a class, that allows converting objects to their JSON representation, using `EKObjectMapping`. CoreData objects are supported too. @@ -51,4 +52,33 @@ */ + (NSArray *)serializeCollection:(NSArray *)collection withMapping:(EKObjectMapping *)mapping; +/** + Convert CoreData managed object to JSON representation. + + @param object object to convert. + + @param mapping object mapping. + + @param context NSManagedObjectContext objects are in. If you don't use context lookups in reverse blocks, you can simply pass nil. + + @result parsed JSON in a form of NSDictionary. + */ ++ (NSDictionary *)serializeObject:(id)object + withMapping:(EKManagedObjectMapping *)mapping + fromContext:(NSManagedObjectContext *)context; + +/** + Convert CoreData managed objects to JSON representation. + + @param collection objects to convert. + + @param mapping object mapping. + + @param context NSManagedObjectContext objects are in. If you don't use context lookups in reverse blocks, you can simply pass nil. + + @result parsed JSON in a form of NSArray. + */ ++ (NSArray *)serializeCollection:(NSArray *)collection + withMapping:(EKManagedObjectMapping*)mapping + fromContext:(NSManagedObjectContext *)context; @end diff --git a/EasyMapping/EKSerializer.m b/EasyMapping/EKSerializer.m index 19e4c05..d8deb3b 100644 --- a/EasyMapping/EKSerializer.m +++ b/EasyMapping/EKSerializer.m @@ -73,6 +73,69 @@ + (NSArray *)serializeCollection:(NSArray *)collection withMapping:(EKObjectMapp return [NSArray arrayWithArray:array]; } ++(NSDictionary *)serializeObject:(id)object withMapping:(EKManagedObjectMapping *)mapping fromContext:(NSManagedObjectContext *)context +{ + NSMutableDictionary *representation = [NSMutableDictionary dictionary]; + + [mapping.propertyMappings enumerateKeysAndObjectsUsingBlock:^(id key, EKPropertyMapping *propertyMapping, BOOL *stop) { + [self setValueOnRepresentation:representation + fromManagedObject:object + withPropertyMapping:propertyMapping + inContext:context]; + }]; + [mapping.hasOneMappings enumerateKeysAndObjectsUsingBlock:^(id key, EKRelationshipMapping *mapping, BOOL *stop) { + id hasOneObject = [object valueForKey:mapping.property]; + + if (hasOneObject) { + NSDictionary *hasOneRepresentation = [self serializeObject:hasOneObject + withMapping:(EKManagedObjectMapping *)[mapping objectMapping] + fromContext:context]; + [representation setObject:hasOneRepresentation forKey:mapping.keyPath]; + } + }]; + [mapping.hasManyMappings enumerateKeysAndObjectsUsingBlock:^(id key, EKRelationshipMapping *mapping, BOOL *stop) { + + id hasManyObject = [object valueForKey:mapping.property]; + if (hasManyObject) { + NSArray *hasManyRepresentation = [self serializeCollection:hasManyObject + withMapping:(EKManagedObjectMapping *)[mapping objectMapping] + fromContext:context]; + [representation setObject:hasManyRepresentation forKey:mapping.keyPath]; + } + }]; + + if (mapping.rootPath.length > 0) { + representation = [@{mapping.rootPath : representation} mutableCopy]; + } + return representation; +} + ++(NSArray *)serializeCollection:(NSArray *)collection withMapping:(EKManagedObjectMapping *)mapping fromContext:(NSManagedObjectContext *)context +{ + NSMutableArray *array = [NSMutableArray array]; + + for (id object in collection) { + NSDictionary *objectRepresentation = [self serializeObject:object withMapping:mapping fromContext:context]; + [array addObject:objectRepresentation]; + } + + return [NSArray arrayWithArray:array]; +} + ++(void)setValueOnRepresentation:(NSMutableDictionary *)representation fromManagedObject:(id)object + withPropertyMapping:(EKPropertyMapping *)propertyMapping inContext:(NSManagedObjectContext *)context +{ + id returnedValue = [object valueForKey:propertyMapping.property]; + + if (returnedValue) { + + if (propertyMapping.managedReverseBlock) { + returnedValue = propertyMapping.managedReverseBlock(returnedValue,context); + } + [self setValue:returnedValue forKeyPath:propertyMapping.keyPath inRepresentation:representation]; + } +} + + (void)setValueOnRepresentation:(NSMutableDictionary *)representation fromObject:(id)object withPropertyMapping:(EKPropertyMapping *)propertyMapping { id returnedValue = [object valueForKey:propertyMapping.property]; diff --git a/EasyMappingExample/Classes/Models/ManagedPerson.h b/EasyMappingExample/Classes/Models/ManagedPerson.h index dc80af6..dbeab8e 100644 --- a/EasyMappingExample/Classes/Models/ManagedPerson.h +++ b/EasyMappingExample/Classes/Models/ManagedPerson.h @@ -19,6 +19,7 @@ @property (nonatomic, retain) NSString * email; @property (nonatomic, retain) ManagedCar *car; @property (nonatomic, retain) NSSet *phones; +@property (nonatomic, retain) NSString * gender; @end @interface ManagedPerson (CoreDataGeneratedAccessors) diff --git a/EasyMappingExample/Classes/Models/ManagedPerson.m b/EasyMappingExample/Classes/Models/ManagedPerson.m index 0000dbc..262e9ac 100644 --- a/EasyMappingExample/Classes/Models/ManagedPerson.m +++ b/EasyMappingExample/Classes/Models/ManagedPerson.m @@ -17,6 +17,7 @@ @implementation ManagedPerson @dynamic email; @dynamic car; @dynamic phones; +@dynamic gender; static EKManagedObjectMapping * mapping = nil; diff --git a/EasyMappingExample/Classes/Providers/ManagedMappingProvider.h b/EasyMappingExample/Classes/Providers/ManagedMappingProvider.h index fba2fe9..15234cc 100644 --- a/EasyMappingExample/Classes/Providers/ManagedMappingProvider.h +++ b/EasyMappingExample/Classes/Providers/ManagedMappingProvider.h @@ -21,6 +21,7 @@ + (EKManagedObjectMapping *)personWithCarMapping; + (EKManagedObjectMapping *)personWithPhonesMapping; + (EKManagedObjectMapping *)personWithOnlyValueBlockMapping; ++ (EKManagedObjectMapping *)personWithReverseBlocksMapping; // Fake mapping, is not backed up by CoreData model + (EKManagedObjectMapping *)complexPlaneMapping; diff --git a/EasyMappingExample/Classes/Providers/ManagedMappingProvider.m b/EasyMappingExample/Classes/Providers/ManagedMappingProvider.m index fe6254f..d828688 100644 --- a/EasyMappingExample/Classes/Providers/ManagedMappingProvider.m +++ b/EasyMappingExample/Classes/Providers/ManagedMappingProvider.m @@ -84,6 +84,35 @@ + (EKManagedObjectMapping *)personMapping }]; } ++(EKManagedObjectMapping *)personWithReverseBlocksMapping +{ + EKManagedObjectMapping * personMapping = [self personWithCarMapping]; + [personMapping mapKeyPath:@"gender" toProperty:@"gender" + withValueBlock:^id(NSString *key, id value, NSManagedObjectContext *context) { + if ([value isEqualToString:@"male"]) + { + return @"husband"; + } + else if ([value isEqualToString:@"female"]) + { + return @"wife"; + } + return nil; + } reverseBlock:^id(id value, NSManagedObjectContext *context) { + if ([value isEqualToString:@"husband"]) + { + return @"male"; + } + else if ([value isEqualToString:@"wife"]) + { + return @"female"; + } + return nil; + }]; + + return personMapping; +} + + (EKManagedObjectMapping *)personWithCarMapping { return [EKManagedObjectMapping mappingForEntityName:NSStringFromClass([ManagedPerson class]) diff --git a/EasyMappingExample/Tests/Specs/EKSerializerSpec.m b/EasyMappingExample/Tests/Specs/EKSerializerSpec.m index c314e7c..153b1c5 100644 --- a/EasyMappingExample/Tests/Specs/EKSerializerSpec.m +++ b/EasyMappingExample/Tests/Specs/EKSerializerSpec.m @@ -18,6 +18,9 @@ #import "Native.h" #import "NativeChild.h" #import +#import +#import "ManagedMappingProvider.h" +#import "ManagedPerson.h" SPEC_BEGIN(EKSerializerSpec) @@ -33,6 +36,13 @@ [[EKSerializer should] respondToSelector:@selector(serializeCollection:withMapping:)]; }); + specify(^{ + [[EKSerializer should] respondToSelector:@selector(serializeObject:withMapping:fromContext:)]; + }); + + specify(^{ + [[EKSerializer should] respondToSelector:@selector(serializeCollection:withMapping:fromContext:)]; + }); }); describe(@".serializeObject:withMapping:", ^{ @@ -557,6 +567,37 @@ }); + describe(@"CoreData reverse mapping blocks", ^{ + + beforeEach(^{ + [MagicalRecord setDefaultModelFromClass:[self class]]; + [MagicalRecord setupCoreDataStackWithInMemoryStore]; + }); + + context(@"object", ^{ + + __block ManagedPerson * person = nil; + __block NSDictionary * representation = nil; + + beforeEach(^{ + NSDictionary * info = [CMFixture buildUsingFixture:@"Person"]; + NSManagedObjectContext * context = [NSManagedObjectContext MR_defaultContext]; + + person = [EKManagedObjectMapper objectFromExternalRepresentation:info + withMapping:[ManagedMappingProvider personWithReverseBlocksMapping] + inManagedObjectContext:context]; + representation = [EKSerializer serializeObject:person + withMapping:[ManagedMappingProvider personWithReverseBlocksMapping] + fromContext:context]; + }); + + specify(^{ + [[person.gender should] equal:@"husband"]; + [[[representation objectForKey:@"gender"] should] equal:@"male"]; + }); + }); + }); + }); SPEC_END