From 0e997c5a6460ac1b4bac753ad1a527c3063db8a0 Mon Sep 17 00:00:00 2001 From: Delisa Mason Date: Fri, 10 Jan 2014 16:03:33 -0800 Subject: [PATCH 1/4] Add spec --- Example/SampleProjectTests/MappingsTests.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Example/SampleProjectTests/MappingsTests.m b/Example/SampleProjectTests/MappingsTests.m index ed6d290..a623d0d 100644 --- a/Example/SampleProjectTests/MappingsTests.m +++ b/Example/SampleProjectTests/MappingsTests.m @@ -73,6 +73,11 @@ Person *bob = [Person findOrCreate:@{ @"first_name": @"Bob" }]; [[bob.firstName should] equal:@"Bob"]; }); + + it(@"uses mappings to transform values", ^{ + Car *car = [Car create:@{ @"hp": @150, @"insurance_company": @{ @"name" : @"Farmers", @"remoteID" : @4567 } }]; + [[car.insuranceCompany.name should] equal:@"Farmers"]; + }); it(@"supports creating a parent object using just ID from the server", ^{ Car *car = [Car create:@{ @"hp": @150, @"insurance_id": @1234 }]; From 2d3986fcf233898ed467a37563b306ae9816476f Mon Sep 17 00:00:00 2001 From: Delisa Mason Date: Fri, 10 Jan 2014 16:16:33 -0800 Subject: [PATCH 2/4] Support generic value transformation in mappings --- Classes/NSManagedObject+ActiveRecord.m | 1 - Classes/NSManagedObject+Mappings.m | 9 ++++++++- .../xcshareddata/xcschemes/SampleProject.xcscheme | 4 ++-- Example/SampleProject/Models/Categories/Car+Mappings.m | 10 ++++++---- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Classes/NSManagedObject+ActiveRecord.m b/Classes/NSManagedObject+ActiveRecord.m index 478d5f9..5229550 100644 --- a/Classes/NSManagedObject+ActiveRecord.m +++ b/Classes/NSManagedObject+ActiveRecord.m @@ -173,7 +173,6 @@ - (void)update:(NSDictionary *)attributes { unless([attributes exists]) return; NSDictionary *transformed = [[self class] transformProperties:attributes withContext:self.managedObjectContext]; - for (NSString *key in transformed) [self willChangeValueForKey:key]; [transformed each:^(NSString *key, id value) { [self setSafeValue:value forKey:key]; diff --git a/Classes/NSManagedObject+Mappings.m b/Classes/NSManagedObject+Mappings.m index 52adc45..a7a3981 100644 --- a/Classes/NSManagedObject+Mappings.m +++ b/Classes/NSManagedObject+Mappings.m @@ -24,6 +24,8 @@ #import "NSManagedObject+ActiveRecord.h" #import "ObjectiveSugar.h" +typedef id (^TransformBlock)(id value); + @implementation NSManagedObject (Mappings) + (NSString *)keyForRemoteKey:(NSString *)remoteKey inContext:(NSManagedObjectContext *)context { @@ -59,8 +61,13 @@ + (id)objectOrSetOfObjectsFromValue:(id)value ofClass:class inContext:(NSManaged if ([value isKindOfClass:class]) return value; - if ([value isKindOfClass:[NSDictionary class]]) + if ([value isKindOfClass:[NSDictionary class]]) { + if (value[@"transform"]) { + TransformBlock transformer = value[@"transform"]; + return transformer(value); + } return [class findOrCreate:value inContext:context]; + } if ([value isKindOfClass:[NSArray class]]) return [NSSet setWithArray:[value map:^id(id object) { diff --git a/Example/SampleProject.xcodeproj/xcshareddata/xcschemes/SampleProject.xcscheme b/Example/SampleProject.xcodeproj/xcshareddata/xcschemes/SampleProject.xcscheme index 7c18f63..56081db 100644 --- a/Example/SampleProject.xcodeproj/xcshareddata/xcschemes/SampleProject.xcscheme +++ b/Example/SampleProject.xcodeproj/xcshareddata/xcschemes/SampleProject.xcscheme @@ -14,7 +14,7 @@ buildForAnalyzing = "YES"> @@ -28,7 +28,7 @@ buildForAnalyzing = "YES"> diff --git a/Example/SampleProject/Models/Categories/Car+Mappings.m b/Example/SampleProject/Models/Categories/Car+Mappings.m index 098dbae..016d7f4 100644 --- a/Example/SampleProject/Models/Categories/Car+Mappings.m +++ b/Example/SampleProject/Models/Categories/Car+Mappings.m @@ -23,10 +23,12 @@ + (NSDictionary *)mappings { @"class": [InsuranceCompany class] }, @"insurance_company": @{ - @"key": @"insuranceCompany", - @"class": [InsuranceCompany class] - } - + @"key": @"insuranceCompany", + @"class": [InsuranceCompany class], + @"transform": ^id(NSDictionary * value) { + return [InsuranceCompany create:value]; + } + } }; } From 5c7f2729bdfe4e10d9d097e6b7ffa2a0f4a1f5a0 Mon Sep 17 00:00:00 2001 From: Delisa Mason Date: Fri, 10 Jan 2014 16:27:02 -0800 Subject: [PATCH 3/4] Use findOrCreate in transform test example --- Classes/NSManagedObject+Mappings.m | 14 +++++++------- .../SampleProject/Models/Categories/Car+Mappings.m | 7 ++++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Classes/NSManagedObject+Mappings.m b/Classes/NSManagedObject+Mappings.m index a7a3981..b593a92 100644 --- a/Classes/NSManagedObject+Mappings.m +++ b/Classes/NSManagedObject+Mappings.m @@ -24,7 +24,7 @@ #import "NSManagedObject+ActiveRecord.h" #import "ObjectiveSugar.h" -typedef id (^TransformBlock)(id value); +typedef id (^TransformBlock)(id value, NSManagedObjectContext *context); @implementation NSManagedObject (Mappings) @@ -48,6 +48,11 @@ + (NSString *)keyForRemoteKey:(NSString *)remoteKey inContext:(NSManagedObjectCo } + (id)transformValue:(id)value forRemoteKey:(NSString *)remoteKey inContext:(NSManagedObjectContext *)context { + if ([self cachedMappings][remoteKey][@"transform"]) { + TransformBlock transformer = [self cachedMappings][remoteKey][@"transform"]; + return transformer(value, context); + } + Class class = [self cachedMappings][remoteKey][@"class"]; if (class) return [self objectOrSetOfObjectsFromValue:value ofClass:class inContext:context]; @@ -61,13 +66,8 @@ + (id)objectOrSetOfObjectsFromValue:(id)value ofClass:class inContext:(NSManaged if ([value isKindOfClass:class]) return value; - if ([value isKindOfClass:[NSDictionary class]]) { - if (value[@"transform"]) { - TransformBlock transformer = value[@"transform"]; - return transformer(value); - } + if ([value isKindOfClass:[NSDictionary class]]) return [class findOrCreate:value inContext:context]; - } if ([value isKindOfClass:[NSArray class]]) return [NSSet setWithArray:[value map:^id(id object) { diff --git a/Example/SampleProject/Models/Categories/Car+Mappings.m b/Example/SampleProject/Models/Categories/Car+Mappings.m index 016d7f4..cde3efd 100644 --- a/Example/SampleProject/Models/Categories/Car+Mappings.m +++ b/Example/SampleProject/Models/Categories/Car+Mappings.m @@ -24,9 +24,10 @@ + (NSDictionary *)mappings { }, @"insurance_company": @{ @"key": @"insuranceCompany", - @"class": [InsuranceCompany class], - @"transform": ^id(NSDictionary * value) { - return [InsuranceCompany create:value]; + @"transform": ^id(NSDictionary *value, NSManagedObjectContext *context) { + InsuranceCompany * company = [InsuranceCompany findOrCreate:@{@"remoteID": value[@"id"] ?: value[@"remoteID"]} inContext:context]; + [company update:value]; + return company; } } }; From cae549d9b615c332f376f795cbfcd7b01526e6d2 Mon Sep 17 00:00:00 2001 From: Delisa Mason Date: Wed, 26 Mar 2014 12:46:15 -0700 Subject: [PATCH 4/4] Provide current NSManagedObjectContext to transform block * In the case that the transform is not operating on the same thread as the main managed object context, the current context is provided to avoid operating on a context from a different thread. --- Classes/NSManagedObject+ActiveRecord.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Classes/NSManagedObject+ActiveRecord.m b/Classes/NSManagedObject+ActiveRecord.m index 5229550..478d5f9 100644 --- a/Classes/NSManagedObject+ActiveRecord.m +++ b/Classes/NSManagedObject+ActiveRecord.m @@ -173,6 +173,7 @@ - (void)update:(NSDictionary *)attributes { unless([attributes exists]) return; NSDictionary *transformed = [[self class] transformProperties:attributes withContext:self.managedObjectContext]; + for (NSString *key in transformed) [self willChangeValueForKey:key]; [transformed each:^(NSString *key, id value) { [self setSafeValue:value forKey:key];