From a69f06c27806c882a90a883738d5b0ea81ead009 Mon Sep 17 00:00:00 2001 From: Blake Watters Date: Thu, 29 Nov 2012 07:41:44 -0500 Subject: [PATCH 01/11] Update references to `RKConnectionMapping` -> `RKConnectionDescription` in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 299d965ed3..62fdbae574 100644 --- a/README.md +++ b/README.md @@ -130,12 +130,12 @@ RestKit is broken into several modules that cleanly separate the mapping engine Models a mapping for transforming an object representation into a NSManagedObject instance for a given NSEntityDescription. - RKConnectionMapping + RKConnectionDescription Describes a mapping for establishing a relationship between Core Data entities using foreign key attributes. RKManagedObjectRequestOperation - An NSOperation subclass that sends an HTTP request and performs object mapping on the parsed response body to create NSManagedObject instances, establishes relationships between objects using RKConnectionMapping objects, and cleans up orphaned objects that no longer exist in the remote backend system. + An NSOperation subclass that sends an HTTP request and performs object mapping on the parsed response body to create NSManagedObject instances, establishes relationships between objects using RKConnectionDescription objects, and cleans up orphaned objects that no longer exist in the remote backend system. RKManagedObjectImporter From 648b159f9a80fb926e5257fbeaa9bfce09db2569 Mon Sep 17 00:00:00 2001 From: Blake Watters Date: Thu, 29 Nov 2012 23:33:48 -0500 Subject: [PATCH 02/11] Remove dead code --- Code/ObjectMapping/RKMappingOperation.m | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/Code/ObjectMapping/RKMappingOperation.m b/Code/ObjectMapping/RKMappingOperation.m index 1bc624e755..d334f4963b 100644 --- a/Code/ObjectMapping/RKMappingOperation.m +++ b/Code/ObjectMapping/RKMappingOperation.m @@ -295,30 +295,10 @@ - (BOOL)shouldSetValue:(id *)value atKeyPath:(NSString *)keyPath return NO; } -// TODO: - (NSArray *)applyNestingToMappings:(NSArray *)mappings { if (_nestedAttributeSubstitution) { return RKApplyNestingAttributeValueToMappings([[_nestedAttributeSubstitution allKeys] lastObject], [[_nestedAttributeSubstitution allValues] lastObject], mappings); - -// NSString *searchString = [NSString stringWithFormat:@"(%@)", [[_nestedAttributeSubstitution allKeys] lastObject]]; -// NSString *replacementString = [[_nestedAttributeSubstitution allValues] lastObject]; -// NSMutableArray *array = [NSMutableArray arrayWithCapacity:[self.objectMapping.attributeMappings count]]; -// for (RKPropertyMapping *mapping in mappings) { -// NSString *sourceKeyPath = [mapping.sourceKeyPath stringByReplacingOccurrencesOfString:searchString withString:replacementString]; -// NSString *destinationKeyPath = [mapping.destinationKeyPath stringByReplacingOccurrencesOfString:searchString withString:replacementString]; -// RKPropertyMapping *nestedMapping = nil; -// if ([mapping isKindOfClass:[RKAttributeMapping class]]) { -// nestedMapping = [RKAttributeMapping attributeMappingFromKeyPath:sourceKeyPath toKeyPath:mapping.destinationKeyPath]; -// } else if ([mapping isKindOfClass:[RKRelationshipMapping class]]) { -// nestedMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:sourceKeyPath -// toKeyPath:destinationKeyPath -// withMapping:[(RKRelationshipMapping *)mapping mapping]]; -// } -// [array addObject:nestedMapping]; -// } -// -// return array; } return mappings; From 89d0294dcd3ee17d11ca76294106bdcfb270b2a2 Mon Sep 17 00:00:00 2001 From: Blake Watters Date: Thu, 29 Nov 2012 23:34:35 -0500 Subject: [PATCH 03/11] Expose access to the `RKMapperOperationDelegate` to `RKObjectRequestOperation` subclasses. closes #1009 --- Code/Network/RKManagedObjectRequestOperation.m | 13 ++----------- Code/Network/RKObjectRequestOperation.h | 7 ++++++- Code/Network/RKObjectRequestOperation.m | 1 + 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Code/Network/RKManagedObjectRequestOperation.m b/Code/Network/RKManagedObjectRequestOperation.m index 74930250e9..acb5894636 100644 --- a/Code/Network/RKManagedObjectRequestOperation.m +++ b/Code/Network/RKManagedObjectRequestOperation.m @@ -84,11 +84,10 @@ return URL; } -@interface RKManagedObjectRequestOperation () +@interface RKManagedObjectRequestOperation () // Core Data specific @property (nonatomic, strong) NSManagedObjectContext *privateContext; @property (nonatomic, copy) NSManagedObjectID *targetObjectID; -@property (nonatomic, strong) NSMutableDictionary *managedObjectsByKeyPath; @property (nonatomic, strong) RKManagedObjectResponseMapperOperation *responseMapperOperation; @property (nonatomic, strong, readwrite) NSError *error; @property (nonatomic, strong, readwrite) RKMappingResult *mappingResult; @@ -136,15 +135,6 @@ - (void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext } } -#pragma mark - RKMapperOperationDelegate methods - -- (void)mapper:(RKMapperOperation *)mapper didFinishMappingOperation:(RKMappingOperation *)mappingOperation forKeyPath:(NSString *)keyPath -{ - if ([mappingOperation.destinationObject isKindOfClass:[NSManagedObject class]]) { - [self.managedObjectsByKeyPath setObject:mappingOperation.destinationObject forKey:keyPath]; - } -} - #pragma mark - RKObjectRequestOperation Overrides - (void)cancel @@ -177,6 +167,7 @@ - (RKMappingResult *)performMappingOnResponse:(NSError **)error self.responseMapperOperation = [[RKManagedObjectResponseMapperOperation alloc] initWithResponse:self.HTTPRequestOperation.response data:self.HTTPRequestOperation.responseData responseDescriptors:self.responseDescriptors]; + self.responseMapperOperation.mapperDelegate = self; self.responseMapperOperation.targetObjectID = self.targetObjectID; self.responseMapperOperation.managedObjectContext = self.privateContext; self.responseMapperOperation.managedObjectCache = self.managedObjectCache; diff --git a/Code/Network/RKObjectRequestOperation.h b/Code/Network/RKObjectRequestOperation.h index d6326cff40..e1e725e2d8 100644 --- a/Code/Network/RKObjectRequestOperation.h +++ b/Code/Network/RKObjectRequestOperation.h @@ -20,6 +20,7 @@ #import "RKHTTPRequestOperation.h" #import "RKMappingResult.h" +#import "RKMapperOperation.h" /** `RKObjectRequestOperation` is an `NSOperation` subclass that implements object mapping on the response body of an `NSHTTPResponse` loaded via an `RKHTTPRequestOperation`. @@ -48,12 +49,16 @@ `RKObjectRequestOperation` is not able to perform object mapping that targets Core Data destination entities. Please refer to the `RKManagedObjectRequestOperation` subclass for details regarding performing a Core Data object request operation. + ## Subclassing Notes + + The `RKObjectRequestOperation` is a non-current `NSOperation` subclass and can be extended by subclassing and providing an implementation of the `main` method. It conforms to the `RKMapperOperationDelegate` protocol, providing access to the lifecycle of the mapping process to subclasses. + @see `RKResponseDescriptor` @see `RKHTTPRequestOperation` @see `RKMIMETypeSerialization` @see `RKManagedObjectRequestOperation` */ -@interface RKObjectRequestOperation : NSOperation +@interface RKObjectRequestOperation : NSOperation ///----------------------------------------------- /// @name Initializing an Object Request Operation diff --git a/Code/Network/RKObjectRequestOperation.m b/Code/Network/RKObjectRequestOperation.m index 5601ba32e9..9d18f5a934 100644 --- a/Code/Network/RKObjectRequestOperation.m +++ b/Code/Network/RKObjectRequestOperation.m @@ -235,6 +235,7 @@ - (RKMappingResult *)performMappingOnResponse:(NSError **)error data:self.HTTPRequestOperation.responseData responseDescriptors:self.responseDescriptors]; self.responseMapperOperation.targetObject = self.targetObject; + self.responseMapperOperation.mapperDelegate = self; [self.responseMapperOperation setQueuePriority:[self queuePriority]]; [self.responseMapperOperation setWillMapDeserializedResponseBlock:self.willMapDeserializedResponseBlock]; [[RKObjectRequestOperation responseMappingQueue] addOperation:self.responseMapperOperation]; From c9e222fdc61b25230fa35059ef5991f0922f3ac1 Mon Sep 17 00:00:00 2001 From: Blake Watters Date: Sat, 1 Dec 2012 16:34:14 -0500 Subject: [PATCH 04/11] Fix documentation error in RKDynamicMapping header --- Code/ObjectMapping/RKDynamicMapping.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/ObjectMapping/RKDynamicMapping.h b/Code/ObjectMapping/RKDynamicMapping.h index 48d3f5cba1..455e358a3f 100644 --- a/Code/ObjectMapping/RKDynamicMapping.h +++ b/Code/ObjectMapping/RKDynamicMapping.h @@ -46,7 +46,7 @@ typedef RKObjectMapping *(^RKDynamicMappingDelegateBlock)(id representation); RKDynamicMapping *mapping = [RKDynamicMapping new]; [mapping setObjectMapping:boyMapping whenValueOfKeyPath:@"gender" isEqualTo:@"male"]; - [mapping setObjectMapping:boyMapping whenValueOfKeyPath:@"gender" isEqualTo:@"female"]; + [mapping setObjectMapping:girlMapping whenValueOfKeyPath:@"gender" isEqualTo:@"female"]; @param objectMapping The mapping to be used when the value at the given key path is equal to the given value. @param keyPath The key path to retrieve the comparison value from in the object representation being mapped. From ddbd1e1f956522bb31f5c516ca9171d6026f5ae0 Mon Sep 17 00:00:00 2001 From: Blake Watters Date: Sun, 2 Dec 2012 00:23:49 -0500 Subject: [PATCH 05/11] Fix inappropriate managed object context reference in `[RKEntityByAttributeCache addObject:]` --- Code/CoreData/RKEntityByAttributeCache.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/CoreData/RKEntityByAttributeCache.m b/Code/CoreData/RKEntityByAttributeCache.m index f0402d602f..05198761c9 100644 --- a/Code/CoreData/RKEntityByAttributeCache.m +++ b/Code/CoreData/RKEntityByAttributeCache.m @@ -270,7 +270,7 @@ - (void)addObject:(NSManagedObject *)object __block NSEntityDescription *entity; __block NSDictionary *attributeValues; __block NSManagedObjectID *objectID; - [self.managedObjectContext performBlockAndWait:^{ + [object.managedObjectContext performBlockAndWait:^{ entity = object.entity; objectID = [object objectID]; attributeValues = [object dictionaryWithValuesForKeys:self.attributes]; From 80f5f7af56bf9809b34d8198e299b6fef062ba07 Mon Sep 17 00:00:00 2001 From: Blake Watters Date: Sun, 2 Dec 2012 00:24:14 -0500 Subject: [PATCH 06/11] Update README to match updated method signature for the entity by attribute cache --- Code/Search/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Search/README.md b/Code/Search/README.md index 785c64027a..674b489786 100644 --- a/Code/Search/README.md +++ b/Code/Search/README.md @@ -89,7 +89,7 @@ To configure an `RKEntityByAttributeCache` for indexing your application, add th self = [super init]; if (self) { NSEntityDescription *searchWordEntity = [[self.managedObjectModel entitiesByName] objectForKey:RKSearchWordEntityName]; - self.searchWordCache = [[RKEntityByAttributeCache alloc] initWithEntity:searchWordEntity attribute:@"word" managedObjectContext:indexingContext]; + self.searchWordCache = [[RKEntityByAttributeCache alloc] initWithEntity:searchWordEntity attributes:@[ @"word" ] managedObjectContext:indexingContext]; [self.searchWordCache load]; } From ff1de2b740c7110c27100a0aec3506e8a5d72970 Mon Sep 17 00:00:00 2001 From: Blake Watters Date: Sun, 2 Dec 2012 00:28:19 -0500 Subject: [PATCH 07/11] Fix incorrect header comment in documentation of RKRequestDescriptor. fixes #1048 --- Code/Network/RKRequestDescriptor.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Network/RKRequestDescriptor.h b/Code/Network/RKRequestDescriptor.h index 1bc20bf77b..44072d32d6 100644 --- a/Code/Network/RKRequestDescriptor.h +++ b/Code/Network/RKRequestDescriptor.h @@ -31,9 +31,9 @@ */ @interface RKRequestDescriptor : NSObject -///------------------------------------- -/// @name Creating a Response Descriptor -///------------------------------------- +///------------------------------------ +/// @name Creating a Request Descriptor +///------------------------------------ /** Creates and returns a new `RKRequestDescriptor` object. From 6e03b0cac2025a352dae39f93ade620a7d492ab2 Mon Sep 17 00:00:00 2001 From: Blake Watters Date: Sun, 2 Dec 2012 10:15:05 -0500 Subject: [PATCH 08/11] Set numerous files in the RestKitFramework target to Public. closes #1050 --- RestKit.xcodeproj/project.pbxproj | 60 ++++++++++++++----------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/RestKit.xcodeproj/project.pbxproj b/RestKit.xcodeproj/project.pbxproj index 8ff75fcaae..8340e44546 100644 --- a/RestKit.xcodeproj/project.pbxproj +++ b/RestKit.xcodeproj/project.pbxproj @@ -13,17 +13,17 @@ 25019497166406E30081D68A /* RKValueTransformers.m in Sources */ = {isa = PBXBuildFile; fileRef = 25019494166406E30081D68A /* RKValueTransformers.m */; }; 25019498166406E30081D68A /* RKValueTransformers.m in Sources */ = {isa = PBXBuildFile; fileRef = 25019494166406E30081D68A /* RKValueTransformers.m */; }; 2502C8ED15F79CF70060FD75 /* CoreData.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8E715F79CF70060FD75 /* CoreData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2502C8EE15F79CF70060FD75 /* CoreData.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8E715F79CF70060FD75 /* CoreData.h */; }; + 2502C8EE15F79CF70060FD75 /* CoreData.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8E715F79CF70060FD75 /* CoreData.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2502C8EF15F79CF70060FD75 /* Network.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8E815F79CF70060FD75 /* Network.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2502C8F015F79CF70060FD75 /* Network.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8E815F79CF70060FD75 /* Network.h */; }; + 2502C8F015F79CF70060FD75 /* Network.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8E815F79CF70060FD75 /* Network.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2502C8F115F79CF70060FD75 /* ObjectMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8E915F79CF70060FD75 /* ObjectMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2502C8F215F79CF70060FD75 /* ObjectMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8E915F79CF70060FD75 /* ObjectMapping.h */; }; + 2502C8F215F79CF70060FD75 /* ObjectMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8E915F79CF70060FD75 /* ObjectMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2502C8F315F79CF70060FD75 /* Search.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8EA15F79CF70060FD75 /* Search.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2502C8F415F79CF70060FD75 /* Search.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8EA15F79CF70060FD75 /* Search.h */; }; + 2502C8F415F79CF70060FD75 /* Search.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8EA15F79CF70060FD75 /* Search.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2502C8F515F79CF70060FD75 /* Support.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8EB15F79CF70060FD75 /* Support.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2502C8F615F79CF70060FD75 /* Support.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8EB15F79CF70060FD75 /* Support.h */; }; + 2502C8F615F79CF70060FD75 /* Support.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8EB15F79CF70060FD75 /* Support.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2502C8F715F79CF70060FD75 /* Testing.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8EC15F79CF70060FD75 /* Testing.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2502C8F815F79CF70060FD75 /* Testing.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8EC15F79CF70060FD75 /* Testing.h */; }; + 2502C8F815F79CF70060FD75 /* Testing.h in Headers */ = {isa = PBXBuildFile; fileRef = 2502C8EC15F79CF70060FD75 /* Testing.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25055B8414EEF32A00B9C4DD /* RKMappingTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 25055B8014EEF32A00B9C4DD /* RKMappingTest.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25055B8514EEF32A00B9C4DD /* RKMappingTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 25055B8014EEF32A00B9C4DD /* RKMappingTest.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25055B8614EEF32A00B9C4DD /* RKMappingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25055B8114EEF32A00B9C4DD /* RKMappingTest.m */; }; @@ -44,7 +44,7 @@ 2507C329161BD5C700EA71FF /* RKTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 2507C326161BD5C700EA71FF /* RKTestHelpers.m */; }; 2507C32A161BD5C700EA71FF /* RKTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 2507C326161BD5C700EA71FF /* RKTestHelpers.m */; }; 25104F1F15C30CD900829135 /* RKSearchWord.h in Headers */ = {isa = PBXBuildFile; fileRef = 25104F1315C30CD900829135 /* RKSearchWord.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 25104F2015C30CD900829135 /* RKSearchWord.h in Headers */ = {isa = PBXBuildFile; fileRef = 25104F1315C30CD900829135 /* RKSearchWord.h */; }; + 25104F2015C30CD900829135 /* RKSearchWord.h in Headers */ = {isa = PBXBuildFile; fileRef = 25104F1315C30CD900829135 /* RKSearchWord.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25104F2115C30CD900829135 /* RKSearchWord.m in Sources */ = {isa = PBXBuildFile; fileRef = 25104F1415C30CD900829135 /* RKSearchWord.m */; }; 25104F2215C30CD900829135 /* RKSearchWord.m in Sources */ = {isa = PBXBuildFile; fileRef = 25104F1415C30CD900829135 /* RKSearchWord.m */; }; 25104F2915C30D1700829135 /* RKManagedObjectStore+RKSearchAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 25104F2715C30D1700829135 /* RKManagedObjectStore+RKSearchAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -60,7 +60,7 @@ 25104F3715C30EF500829135 /* RKSearchPredicate.m in Sources */ = {isa = PBXBuildFile; fileRef = 25104F3415C30EF500829135 /* RKSearchPredicate.m */; }; 25104F3815C30EF500829135 /* RKSearchPredicate.m in Sources */ = {isa = PBXBuildFile; fileRef = 25104F3415C30EF500829135 /* RKSearchPredicate.m */; }; 25104F3B15C30F2100829135 /* RKSearchWordEntity.h in Headers */ = {isa = PBXBuildFile; fileRef = 25104F3915C30F2000829135 /* RKSearchWordEntity.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 25104F3C15C30F2100829135 /* RKSearchWordEntity.h in Headers */ = {isa = PBXBuildFile; fileRef = 25104F3915C30F2000829135 /* RKSearchWordEntity.h */; }; + 25104F3C15C30F2100829135 /* RKSearchWordEntity.h in Headers */ = {isa = PBXBuildFile; fileRef = 25104F3915C30F2000829135 /* RKSearchWordEntity.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25104F3D15C30F2100829135 /* RKSearchWordEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 25104F3A15C30F2100829135 /* RKSearchWordEntity.m */; }; 25104F3E15C30F2100829135 /* RKSearchWordEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 25104F3A15C30F2100829135 /* RKSearchWordEntity.m */; }; 25119FB6154A34B400C6BC58 /* parents_and_children.json in Resources */ = {isa = PBXBuildFile; fileRef = 25119FB5154A34B400C6BC58 /* parents_and_children.json */; }; @@ -85,7 +85,7 @@ 25160E10145650490060A5C5 /* RKAttributeMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 25160D83145650490060A5C5 /* RKAttributeMapping.m */; }; 25160E16145650490060A5C5 /* RKMapperOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 25160D89145650490060A5C5 /* RKMapperOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25160E17145650490060A5C5 /* RKMapperOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25160D8A145650490060A5C5 /* RKMapperOperation.m */; }; - 25160E18145650490060A5C5 /* RKMapperOperation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 25160D8B145650490060A5C5 /* RKMapperOperation_Private.h */; settings = {ATTRIBUTES = (); }; }; + 25160E18145650490060A5C5 /* RKMapperOperation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 25160D8B145650490060A5C5 /* RKMapperOperation_Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 25160E1A145650490060A5C5 /* RKObjectMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 25160D8D145650490060A5C5 /* RKObjectMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25160E1B145650490060A5C5 /* RKObjectMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 25160D8E145650490060A5C5 /* RKObjectMapping.m */; }; 25160E1C145650490060A5C5 /* RKMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 25160D8F145650490060A5C5 /* RKMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -135,7 +135,7 @@ 25160F4B145655C60060A5C5 /* RKAttributeMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 25160D83145650490060A5C5 /* RKAttributeMapping.m */; }; 25160F51145655C60060A5C5 /* RKMapperOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 25160D89145650490060A5C5 /* RKMapperOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25160F52145655C60060A5C5 /* RKMapperOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25160D8A145650490060A5C5 /* RKMapperOperation.m */; }; - 25160F53145655C60060A5C5 /* RKMapperOperation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 25160D8B145650490060A5C5 /* RKMapperOperation_Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 25160F53145655C60060A5C5 /* RKMapperOperation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 25160D8B145650490060A5C5 /* RKMapperOperation_Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 25160F55145655C60060A5C5 /* RKObjectMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 25160D8D145650490060A5C5 /* RKObjectMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25160F56145655C60060A5C5 /* RKObjectMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 25160D8E145650490060A5C5 /* RKObjectMapping.m */; }; 25160F57145655C60060A5C5 /* RKMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 25160D8F145650490060A5C5 /* RKMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -326,35 +326,35 @@ 254372A815F54995006E8424 /* RKObjectParameterization.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372A615F54995006E8424 /* RKObjectParameterization.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254372A915F54995006E8424 /* RKObjectParameterization.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372A715F54995006E8424 /* RKObjectParameterization.m */; }; 254372B815F54C3F006E8424 /* RKHTTPRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AA15F54C3F006E8424 /* RKHTTPRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 254372B915F54C3F006E8424 /* RKHTTPRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AA15F54C3F006E8424 /* RKHTTPRequestOperation.h */; }; + 254372B915F54C3F006E8424 /* RKHTTPRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AA15F54C3F006E8424 /* RKHTTPRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254372BA15F54C3F006E8424 /* RKHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372AB15F54C3F006E8424 /* RKHTTPRequestOperation.m */; }; 254372BB15F54C3F006E8424 /* RKHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372AB15F54C3F006E8424 /* RKHTTPRequestOperation.m */; }; 254372BC15F54C3F006E8424 /* RKObjectManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AC15F54C3F006E8424 /* RKObjectManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 254372BD15F54C3F006E8424 /* RKObjectManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AC15F54C3F006E8424 /* RKObjectManager.h */; }; + 254372BD15F54C3F006E8424 /* RKObjectManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AC15F54C3F006E8424 /* RKObjectManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254372BE15F54C3F006E8424 /* RKObjectManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372AD15F54C3F006E8424 /* RKObjectManager.m */; }; 254372BF15F54C3F006E8424 /* RKObjectManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372AD15F54C3F006E8424 /* RKObjectManager.m */; }; 254372C015F54C3F006E8424 /* RKPaginator.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AE15F54C3F006E8424 /* RKPaginator.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 254372C115F54C3F006E8424 /* RKPaginator.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AE15F54C3F006E8424 /* RKPaginator.h */; }; + 254372C115F54C3F006E8424 /* RKPaginator.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AE15F54C3F006E8424 /* RKPaginator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254372C215F54C3F006E8424 /* RKPaginator.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372AF15F54C3F006E8424 /* RKPaginator.m */; }; 254372C315F54C3F006E8424 /* RKPaginator.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372AF15F54C3F006E8424 /* RKPaginator.m */; }; 254372C415F54C3F006E8424 /* RKObjectRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B015F54C3F006E8424 /* RKObjectRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 254372C515F54C3F006E8424 /* RKObjectRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B015F54C3F006E8424 /* RKObjectRequestOperation.h */; }; + 254372C515F54C3F006E8424 /* RKObjectRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B015F54C3F006E8424 /* RKObjectRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254372C615F54C3F006E8424 /* RKObjectRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372B115F54C3F006E8424 /* RKObjectRequestOperation.m */; }; 254372C715F54C3F006E8424 /* RKObjectRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372B115F54C3F006E8424 /* RKObjectRequestOperation.m */; }; 254372C815F54C3F006E8424 /* RKRequestDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B215F54C3F006E8424 /* RKRequestDescriptor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 254372C915F54C3F006E8424 /* RKRequestDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B215F54C3F006E8424 /* RKRequestDescriptor.h */; }; + 254372C915F54C3F006E8424 /* RKRequestDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B215F54C3F006E8424 /* RKRequestDescriptor.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254372CA15F54C3F006E8424 /* RKRequestDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372B315F54C3F006E8424 /* RKRequestDescriptor.m */; }; 254372CB15F54C3F006E8424 /* RKRequestDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372B315F54C3F006E8424 /* RKRequestDescriptor.m */; }; 254372CC15F54C3F006E8424 /* RKResponseDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B415F54C3F006E8424 /* RKResponseDescriptor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 254372CD15F54C3F006E8424 /* RKResponseDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B415F54C3F006E8424 /* RKResponseDescriptor.h */; }; + 254372CD15F54C3F006E8424 /* RKResponseDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B415F54C3F006E8424 /* RKResponseDescriptor.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254372CE15F54C3F006E8424 /* RKResponseDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372B515F54C3F006E8424 /* RKResponseDescriptor.m */; }; 254372CF15F54C3F006E8424 /* RKResponseDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372B515F54C3F006E8424 /* RKResponseDescriptor.m */; }; 254372D015F54C3F006E8424 /* RKResponseMapperOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B615F54C3F006E8424 /* RKResponseMapperOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 254372D115F54C3F006E8424 /* RKResponseMapperOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B615F54C3F006E8424 /* RKResponseMapperOperation.h */; }; + 254372D115F54C3F006E8424 /* RKResponseMapperOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B615F54C3F006E8424 /* RKResponseMapperOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254372D215F54C3F006E8424 /* RKResponseMapperOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372B715F54C3F006E8424 /* RKResponseMapperOperation.m */; }; 254372D315F54C3F006E8424 /* RKResponseMapperOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372B715F54C3F006E8424 /* RKResponseMapperOperation.m */; }; 254372D615F54CE3006E8424 /* RKManagedObjectRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372D415F54CE3006E8424 /* RKManagedObjectRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 254372D715F54CE3006E8424 /* RKManagedObjectRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372D415F54CE3006E8424 /* RKManagedObjectRequestOperation.h */; }; + 254372D715F54CE3006E8424 /* RKManagedObjectRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372D415F54CE3006E8424 /* RKManagedObjectRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254372D815F54CE3006E8424 /* RKManagedObjectRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372D515F54CE3006E8424 /* RKManagedObjectRequestOperation.m */; }; 254372D915F54CE3006E8424 /* RKManagedObjectRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372D515F54CE3006E8424 /* RKManagedObjectRequestOperation.m */; }; 2543A25D1664FD3100821D5B /* RKResponseDescriptorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25CC5C58161DDADD0008BD21 /* RKResponseDescriptorTest.m */; }; @@ -369,6 +369,9 @@ 25565959161FC3CD00F5BB20 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25565958161FC3CD00F5BB20 /* SystemConfiguration.framework */; }; 25565965161FDD8800F5BB20 /* RKResponseMapperOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25565964161FDD8800F5BB20 /* RKResponseMapperOperationTest.m */; }; 25565966161FDD8800F5BB20 /* RKResponseMapperOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25565964161FDD8800F5BB20 /* RKResponseMapperOperationTest.m */; }; + 255893E3166BA6A20010C70B /* RKObjectParameterization.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372A615F54995006E8424 /* RKObjectParameterization.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 255893E4166BA7400010C70B /* RestKit-Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 25160DBB145650490060A5C5 /* RestKit-Prefix.pch */; }; + 255893E5166BA7700010C70B /* RKTestFixture.h in Headers */ = {isa = PBXBuildFile; fileRef = 252EFB2014D9B35D004863C8 /* RKTestFixture.h */; settings = {ATTRIBUTES = (Public, ); }; }; 255F87911656B22D00914D57 /* RKPaginatorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 254A62BF14AD591C00939BEE /* RKPaginatorTest.m */; }; 255F87921656B22F00914D57 /* RKPaginatorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 254A62BF14AD591C00939BEE /* RKPaginatorTest.m */; }; 2564E40B16173F7B00C12D7D /* RKRelationshipConnectionOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2564E40A16173F7B00C12D7D /* RKRelationshipConnectionOperationTest.m */; }; @@ -400,7 +403,7 @@ 2595B47515F670530087A59B /* RKNSJSONSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 2595B46E15F670530087A59B /* RKNSJSONSerialization.m */; }; 2595B47615F670530087A59B /* RKNSJSONSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 2595B46E15F670530087A59B /* RKNSJSONSerialization.m */; }; 2597F99C15AF6DC400E547D7 /* RKRelationshipConnectionOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 2597F99A15AF6DC400E547D7 /* RKRelationshipConnectionOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2597F99D15AF6DC400E547D7 /* RKRelationshipConnectionOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 2597F99A15AF6DC400E547D7 /* RKRelationshipConnectionOperation.h */; }; + 2597F99D15AF6DC400E547D7 /* RKRelationshipConnectionOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 2597F99A15AF6DC400E547D7 /* RKRelationshipConnectionOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2597F99E15AF6DC400E547D7 /* RKRelationshipConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 2597F99B15AF6DC400E547D7 /* RKRelationshipConnectionOperation.m */; }; 2597F99F15AF6DC400E547D7 /* RKRelationshipConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 2597F99B15AF6DC400E547D7 /* RKRelationshipConnectionOperation.m */; }; 2598888D15EC169E006CAE95 /* RKPropertyMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 2598888B15EC169E006CAE95 /* RKPropertyMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -550,8 +553,8 @@ 25F53AE315E7B612008B54E6 /* RKHTTPUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 25F53AE015E7B611008B54E6 /* RKHTTPUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25F53AE415E7B612008B54E6 /* RKHTTPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 25F53AE115E7B612008B54E6 /* RKHTTPUtilities.m */; }; 25F53AE515E7B612008B54E6 /* RKHTTPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 25F53AE115E7B612008B54E6 /* RKHTTPUtilities.m */; }; - 25F53F391606269400A093BE /* RKRequestOperationSubclass.h in Headers */ = {isa = PBXBuildFile; fileRef = 25F53F381606269400A093BE /* RKRequestOperationSubclass.h */; }; - 25F53F3A1606269400A093BE /* RKRequestOperationSubclass.h in Headers */ = {isa = PBXBuildFile; fileRef = 25F53F381606269400A093BE /* RKRequestOperationSubclass.h */; }; + 25F53F391606269400A093BE /* RKRequestOperationSubclass.h in Headers */ = {isa = PBXBuildFile; fileRef = 25F53F381606269400A093BE /* RKRequestOperationSubclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 25F53F3A1606269400A093BE /* RKRequestOperationSubclass.h in Headers */ = {isa = PBXBuildFile; fileRef = 25F53F381606269400A093BE /* RKRequestOperationSubclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25FABED014E3796400E609E7 /* RKTestNotificationObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 252EFAFD14D8EB30004863C8 /* RKTestNotificationObserver.m */; }; 25FABED114E3796400E609E7 /* RKTestNotificationObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 252EFAFD14D8EB30004863C8 /* RKTestNotificationObserver.m */; }; 25FABED214E3796B00E609E7 /* RKTestNotificationObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 252EFAFC14D8EB30004863C8 /* RKTestNotificationObserver.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -935,14 +938,10 @@ 73D3907114CA19F90093E3D6 /* parent.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = parent.json; sourceTree = ""; }; 73D3907314CA1A4A0093E3D6 /* child.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = child.json; sourceTree = ""; }; 73D3907814CA1D710093E3D6 /* channels.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = channels.xml; sourceTree = ""; }; - 92A418BC16A64A74BF92549F /* Pods.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.xcconfig; path = Pods/Pods.xcconfig; sourceTree = SOURCE_ROOT; }; 93B7B61F0199413CAA60E8A7 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 964648386780496FA49D3DD6 /* Pods.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.xcconfig; path = Pods/Pods.xcconfig; sourceTree = SOURCE_ROOT; }; - C4123D3CDB2C42AE86B273D7 /* Pods.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.xcconfig; path = Pods/Pods.xcconfig; sourceTree = SOURCE_ROOT; }; - C87136726FCA44FBBC18C515 /* Pods.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.xcconfig; path = Pods/Pods.xcconfig; sourceTree = SOURCE_ROOT; }; C8C87FF6727A42D68CA2220E /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; D87B44252FCE4651B291E38A /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; - E79F34A511E54F35B6580DA7 /* Pods.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.xcconfig; path = Pods/Pods.xcconfig; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1043,10 +1042,6 @@ 25160E8D145652E40060A5C5 /* Vendor */, 25160D1814564E810060A5C5 /* Frameworks */, 25160D1714564E810060A5C5 /* Products */, - C4123D3CDB2C42AE86B273D7 /* Pods.xcconfig */, - E79F34A511E54F35B6580DA7 /* Pods.xcconfig */, - C87136726FCA44FBBC18C515 /* Pods.xcconfig */, - 92A418BC16A64A74BF92549F /* Pods.xcconfig */, 964648386780496FA49D3DD6 /* Pods.xcconfig */, ); sourceTree = ""; @@ -1894,6 +1889,9 @@ 25E88C83165C5B580042ABD0 /* RKEntityIdentifier.h in Headers */, 25E88C89165C5CC30042ABD0 /* RKConnectionDescription.h in Headers */, 25019496166406E30081D68A /* RKValueTransformers.h in Headers */, + 255893E3166BA6A20010C70B /* RKObjectParameterization.h in Headers */, + 255893E4166BA7400010C70B /* RestKit-Prefix.pch in Headers */, + 255893E5166BA7700010C70B /* RKTestFixture.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2615,7 +2613,6 @@ }; 25160D3E14564E820060A5C5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 964648386780496FA49D3DD6 /* Pods.xcconfig */; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; FRAMEWORK_SEARCH_PATHS = ( @@ -2640,7 +2637,6 @@ }; 25160D3F14564E820060A5C5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 964648386780496FA49D3DD6 /* Pods.xcconfig */; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; FRAMEWORK_SEARCH_PATHS = ( @@ -2721,7 +2717,6 @@ }; 25160E8B145651060060A5C5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 92A418BC16A64A74BF92549F /* Pods.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; @@ -2746,7 +2741,6 @@ }; 25160E8C145651060060A5C5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 92A418BC16A64A74BF92549F /* Pods.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; From cbb3f705717d7bc3dac73c3bf0501edb7c3f1c60 Mon Sep 17 00:00:00 2001 From: Blake Watters Date: Sun, 2 Dec 2012 13:08:52 -0500 Subject: [PATCH 09/11] Eliminate the `RKEntityIdentifier` class and migrate the functionality into properties on `RKEntityMapping` --- Code/CoreData/RKEntityIdentifier.h | 104 -------- Code/CoreData/RKEntityIdentifier.m | 129 --------- Code/CoreData/RKEntityMapping.h | 87 +++--- Code/CoreData/RKEntityMapping.m | 136 +++++++--- ...KManagedObjectMappingOperationDataSource.m | 16 +- .../Classes/RKTwitterAppDelegate.m | 4 +- RestKit.xcodeproj/project.pbxproj | 22 +- Tests/Logic/CoreData/RKEntityIdentifierTest.m | 225 ---------------- Tests/Logic/CoreData/RKEntityMappingTest.m | 250 +++++++++++++----- .../CoreData/RKFetchRequestMappingCacheTest.m | 4 +- .../CoreData/RKManagedObjectLoaderTest.m | 4 +- ...agedObjectMappingOperationDataSourceTest.m | 32 +-- .../RKManagedObjectMappingOperationTest.m | 70 ++--- .../RKObjectMappingNextGenTest.m | 2 +- 14 files changed, 404 insertions(+), 681 deletions(-) delete mode 100644 Code/CoreData/RKEntityIdentifier.h delete mode 100644 Code/CoreData/RKEntityIdentifier.m delete mode 100644 Tests/Logic/CoreData/RKEntityIdentifierTest.m diff --git a/Code/CoreData/RKEntityIdentifier.h b/Code/CoreData/RKEntityIdentifier.h deleted file mode 100644 index 9019ca09f8..0000000000 --- a/Code/CoreData/RKEntityIdentifier.h +++ /dev/null @@ -1,104 +0,0 @@ -// -// RKEntityIdentifier.h -// RestKit -// -// Created by Blake Watters on 11/20/12. -// Copyright (c) 2012 RestKit. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#import - -/** - The name of a key in the user info dictionary of a `NSEntityDescription` specifying the name or one or more attributes to be used to infer an entity identifier. The value of this string is 'RKEntityIdentifierAttributes'. - */ -extern NSString * const RKEntityIdentifierUserInfoKey; - -@class RKManagedObjectStore; - -/** - The `RKEntityIdentifier` object describes a means for uniquely identifying one or more `NSManagedObject` objects within a Core Data managed object model. Entity identifiers are used by RestKit to identify existing managed objects that are to be updated while performing object mapping with an `RKEntityMapping` object. Entity identifiers identify objects by specifying the attributes that can be used to uniquely differentiate managed objects within a context. - */ -@interface RKEntityIdentifier : NSObject - -///---------------------------------------- -/// @name Initializing an Entity Identifier -///---------------------------------------- - -/** - Creates and returns a new entity identifier with the entity for the given name and attributes in the specified managed object store. - - @param entityName The name of the entity being identified. - @param attributes An array of `NSString` objects containing the names of attributes or `NSAttributeDescription` objects specifying the identifying attributes for the entity. - @param managedObjectStore The managed object store containing the managed object model within which the entity exists. - @return A new entity identifier, configured with the given entity for the given name and the array of attributes. - */ -+ (id)identifierWithEntityName:(NSString *)entityName attributes:(NSArray *)attributes inManagedObjectStore:(RKManagedObjectStore *)managedObjectStore; - -/** - Initializes the receiver with a given entity and array of attributes. - - @param entity The entity being identified. - @param attributes An array of `NSString` objects containing the names of attributes or `NSAttributeDescription` objects specifying the identifying attributes for the entity. - @return The receiver, initialized with the given entity and attributes. - */ -- (id)initWithEntity:(NSEntityDescription *)entity attributes:(NSArray *)attributes; - -///-------------------------------- -/// @name Accessing Entity Identity -///-------------------------------- - -/** - The entity that the receiver identifies. - */ -@property (nonatomic, strong, readonly) NSEntityDescription *entity; - -/** - An array of `NSAttributeDescription` objects specifying the attributes used for identification. - */ -@property (nonatomic, copy, readonly) NSArray *attributes; - -///--------------------------------------- -/// @name Filtering the Identified Objects -///--------------------------------------- - -/** - An optional predicate for filtering identified objects. - */ -@property (nonatomic, copy) NSPredicate *predicate; - -///------------------------------------------- -/// @name Inferring Identifiers from the Model -///------------------------------------------- - -/** - Creates and returns an entity identifier for the given entity inferred from the managed object model. - - When inferring an entity identifier, the entity is first checked for a user info key specifying the identifying attributes. If the user info of the given entity contains a value for the key 'RKEntityIdentifierAttributes', then that value is used to construct an entity identifier. The user info key must contain a string or an array of strings specifying the names of attributes that exist in the given entity. - - If no attributes are specified in the user info, then the entity is searched for an attribute whose name matches the llama-cased name of the entity. For example, an entity named 'Article' would have an inferred identifier attribute of 'articleID' and an entity named 'ApprovedComment' would be inferred as 'approvedCommentID'. If such an attribute is found within the entity, an identifier is returned specifying that attribute. If none is returned, the the attributes are search for the following names: - - 1. 'identifier' - 1. 'ID' - 1. 'URL' - 1. 'url' - - If any of these attributes are found, then an entity identifier is created for that attribute. If all possible inferred attributes are exhausted, then `nil` is returned. - - @param entity The entity to infer an identifier for. - @return An entity identifier inferred from the model for the given entity, or `nil` if none could be inferred. - */ -+ (RKEntityIdentifier *)inferredIdentifierForEntity:(NSEntityDescription *)entity; - -@end diff --git a/Code/CoreData/RKEntityIdentifier.m b/Code/CoreData/RKEntityIdentifier.m deleted file mode 100644 index e3bd319693..0000000000 --- a/Code/CoreData/RKEntityIdentifier.m +++ /dev/null @@ -1,129 +0,0 @@ -// -// RKEntityIdentifier.m -// RestKit -// -// Created by Blake Watters on 11/20/12. -// Copyright (c) 2012 RestKit. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#import "RKEntityIdentifier.h" -#import "RKManagedObjectStore.h" - -NSString * const RKEntityIdentifierUserInfoKey = @"RKEntityIdentifierAttributes"; - -static NSArray *RKEntityIdentifierAttributesFromUserInfoOfEntity(NSEntityDescription *entity) -{ - id userInfoValue = [entity userInfo][RKEntityIdentifierUserInfoKey]; - if (userInfoValue) { - NSArray *attributeNames = [userInfoValue isKindOfClass:[NSArray class]] ? userInfoValue : @[ userInfoValue ]; - NSMutableArray *attributes = [NSMutableArray arrayWithCapacity:[attributeNames count]]; - [attributeNames enumerateObjectsUsingBlock:^(NSString *attributeName, NSUInteger idx, BOOL *stop) { - if (! [attributeName isKindOfClass:[NSString class]]) { - [NSException raise:NSInvalidArgumentException format:@"Invalid value given in user info key '%@' of entity '%@': expected an `NSString` or `NSArray` of strings, instead got '%@' (%@)", RKEntityIdentifierUserInfoKey, [entity name], attributeName, [attributeName class]]; - } - - NSAttributeDescription *attribute = [entity attributesByName][attributeName]; - if (! attribute) { - [NSException raise:NSInvalidArgumentException format:@"Invalid identifier attribute specified in user info key '%@' of entity '%@': no attribue was found with the name '%@'", RKEntityIdentifierUserInfoKey, [entity name], attributeName]; - } - - [attributes addObject:attribute]; - }]; - return attributes; - } - - return nil; -} - -// Given 'Human', returns 'humanID'; Given 'AmenityReview' returns 'amenityReviewID' -static NSString *RKEntityIdentifierAttributeNameForEntity(NSEntityDescription *entity) -{ - NSString *entityName = [entity name]; - NSString *lowerCasedFirstCharacter = [[entityName substringToIndex:1] lowercaseString]; - return [NSString stringWithFormat:@"%@%@ID", lowerCasedFirstCharacter, [entityName substringFromIndex:1]]; -} - -static NSArray *RKEntityIdentifierAttributeNames() -{ - return [NSArray arrayWithObjects:@"identifier", @"ID", @"URL", @"url", nil]; -} - -static NSArray *RKArrayOfAttributesForEntityFromAttributesOrNames(NSEntityDescription *entity, NSArray *attributesOrNames) -{ - NSMutableArray *attributes = [NSMutableArray arrayWithCapacity:[attributesOrNames count]]; - for (id attributeOrName in attributesOrNames) { - if ([attributeOrName isKindOfClass:[NSAttributeDescription class]]) { - if (! [[entity properties] containsObject:attributeOrName]) [NSException raise:NSInvalidArgumentException format:@"Invalid attribute value '%@' given for entity identifer: not found in the '%@' entity", attributeOrName, [entity name]]; - [attributes addObject:attributeOrName]; - } else if ([attributeOrName isKindOfClass:[NSString class]]) { - NSAttributeDescription *attribute = [entity attributesByName][attributeOrName]; - if (!attribute) [NSException raise:NSInvalidArgumentException format:@"Invalid attribute '%@': no attribute was found for the given name in the '%@' entity.", attributeOrName, [entity name]]; - [attributes addObject:attribute]; - } else { - [NSException raise:NSInvalidArgumentException format:@"Invalid value provided for entity identifier attribute: Acceptable values are either `NSAttributeDescription` or `NSString` objects."]; - } - } - - return attributes; -} - -@interface RKEntityIdentifier () -@property (nonatomic, strong, readwrite) NSEntityDescription *entity; -@property (nonatomic, copy, readwrite) NSArray *attributes; -@end - -@implementation RKEntityIdentifier - -+ (id)identifierWithEntityName:(NSString *)entityName attributes:(NSArray *)attributes inManagedObjectStore:(RKManagedObjectStore *)managedObjectStore -{ - NSEntityDescription *entity = [managedObjectStore.managedObjectModel entitiesByName][entityName]; - return [[self alloc] initWithEntity:entity attributes:attributes]; -} - -- (id)initWithEntity:(NSEntityDescription *)entity attributes:(NSArray *)attributes -{ - NSParameterAssert(entity); - NSParameterAssert(attributes); - NSAssert([attributes count], @"At least one attribute must be provided to identify managed objects"); - self = [self init]; - if (self) { - self.entity = entity; - self.attributes = RKArrayOfAttributesForEntityFromAttributesOrNames(entity, attributes); - } - - return self; -} - -#pragma mark - Idetifier Inference - -+ (RKEntityIdentifier *)inferredIdentifierForEntity:(NSEntityDescription *)entity -{ - NSArray *attributes = RKEntityIdentifierAttributesFromUserInfoOfEntity(entity); - if (attributes) { - return [[RKEntityIdentifier alloc] initWithEntity:entity attributes:attributes]; - } - - NSMutableArray *identifyingAttributes = [NSMutableArray arrayWithObject:RKEntityIdentifierAttributeNameForEntity(entity)]; - [identifyingAttributes addObjectsFromArray:RKEntityIdentifierAttributeNames()]; - for (NSString *attributeName in identifyingAttributes) { - NSAttributeDescription *attribute = [entity attributesByName][attributeName]; - if (attribute) { - return [[RKEntityIdentifier alloc] initWithEntity:entity attributes:@[ attribute ]]; - } - } - return nil; -} - -@end diff --git a/Code/CoreData/RKEntityMapping.h b/Code/CoreData/RKEntityMapping.h index 6b11373d2a..f896d1a8ff 100644 --- a/Code/CoreData/RKEntityMapping.h +++ b/Code/CoreData/RKEntityMapping.h @@ -22,7 +22,6 @@ #import "RKObjectMapping.h" #import "RKConnectionDescription.h" #import "RKMacros.h" -#import "RKEntityIdentifier.h" @class RKManagedObjectStore; @@ -31,17 +30,30 @@ ## Entity Identification - One of the fundamental problems when object mapping representations into Core Data entities is determining if a new object should be created or an existing object should be updated. The `RKEntityIdentifier` class describes how existing objects should be identified when an entity mapping is being applied. Entity identifiers specify one or more attributes of the entity that are to be used to identify existing objects. Typically the values of these attributes are populated by attribute mappings. It is common practice to use a single attribute corresponding to the primary key of the remote resource being mapped, but an arbitrary number of attributes may be specified for identification. Identifying attributes have all type transformations support by the mapper applied before the managed object context is search, supporting such use-cases as using an `NSDate` as an identifying attribute whose value is mapped from an `NSString`. + One of the fundamental problems when object mapping representations into Core Data entities is determining if a new object should be created or an existing object should be updated. In an entity mapping, one or more attributes can be designated as being used for identification purposes via the `identificationAttributes` property. Typically the values of these attributes are populated by attribute mappings. It is common practice to use a single attribute corresponding to the primary key of the remote resource being mapped, but an arbitrary number of attributes may be specified for identification. Identifying attributes have all type transformations support by the mapper applied before the managed object context is searched, supporting such use-cases as using an `NSDate` as an identifying attribute whose value is mapped from an `NSString`. Identified objects can be further constrained by configuring an identification predicate via the `identificationPredicate` property. The predicate is applied after the managed object has been searched. - ### Inferring Entity Identifiers + ### Identification Inference - The `RKEntityMapping` class provides support for inferring an entity identifier from the managed object model. When inference is enabled (the default state), the entity is searched for several commonly used identifying attributes and if any is found, an `entityIdentifier` is automatically configured. Inference is performed by the `[RKEntityIdentifier inferredIdentifierForEntity:` method and the inference rules are detailed in the accompanying documentation. + The `RKEntityMapping` class provides support for inferring identification attributes from the managed object model. When inference is enabled (the default state), the entity is searched for several commonly used identifying attributes and if any is found, the value of the `identificationAttributes` property is automatically configured. Inference is performed by the `RKIdentificationAttributesInferredFromEntity` function. + + When `RKIdentificationAttributesInferredFromEntity` is invoked, the entity is first checked for a user info key specifying the identifying attributes. If the user info of the given entity contains a value for the key 'RKEntityIdentificationAttributes', then that value is used to construct an array of attributes. The user info key must contain a string or an array of strings specifying the names of attributes that exist in the given entity. + + If no attributes are specified in the user info, then the entity is searched for an attribute whose name matches the llama-cased name of the entity. For example, an entity named 'Article' would have an inferred identifier attribute of 'articleID' and an entity named 'ApprovedComment' would be inferred as 'approvedCommentID'. If such an attribute is found within the entity, an array is returned containing the attribute. If none is returned, the the attributes are searched for the following names: + + 1. 'identifier' + 1. 'id' + 1. 'ID' + 1. 'URL' + 1. 'url' + + If any of these attributes are found, then an array is returned containing the attribute. If all possible inferred attributes are exhausted, then `nil` is returned. + + Note that inference will only return a single attribute. Compound attributes must be configured manually via the `identificationAttributes` property. ## Connecting Relationships When modeling an API into Core Data representation, a common problem is that managed objects that are semantically related are loaded across discrete requests, leaving the Core Data relationships empty. The `RKConnectionDescription` class provides a means for expressing a connection between entities using corresponding attribute values or by key path. Please refer to the documentation accompanying the `RKConnectionDescription` class and the `addConnectionForRelationship:connectedBy:` method of this class. - @see `RKEntityIdentifier` @see `RKConnectionDescription` */ @interface RKEntityMapping : RKObjectMapping @@ -87,31 +99,21 @@ ///---------------------------------- /** - The entity identifier used to identify `NSManagedObject` instances for the receiver's entity by one or more attributes. + The array of `NSAttributeDescription` objects specifying the attributes of the receiver's entity that are used during mapping to determine whether an existing object should be updated or a new managed object should be inserted. Please see the "Entity Identification" section of this document for more information. - The entity identifier is used during mapping to determine whether an existing object should be updated or a new managed object should be inserted. Please see the "Entity Identification" section of this document for more information. + @return An array of identifying attributes or `nil` if none have been configured. + @raises NSInvalidArgumentException Raised if the setter is invoked with the name of an attribute or an `NSAttributeDescription` that does not exist in the receiver's entity. Also raised if the setter is invoked with an empty array. + @warning Note that for convenience, this property may be set with an array containing `NSAttributeDescription` objects or `NSString` objects specifying the names of attributes that exist within the receiver's entity. The getter will always return an array of `NSAttributeDescription` objects. */ -@property (nonatomic, copy) RKEntityIdentifier *entityIdentifier; +@property (nonatomic, copy) NSArray *identificationAttributes; /** - Sets an entity identifier for the relationship with the given name. + An optional predicate used to filter identified objects during mapping. - When mapping the specified relationship, the given entity identifier will be used to find existing managed object instances. If no identifier is specified, then the entity identifier of the entity mapping is used by default. This method need only be invoked if the relationship has specific identification needs that diverge from the entity. - - @param entityIdentifier The entity identifier to be used when mapping the specified relationship - @param relationshipName The name of the relationship for which the specified identifier is to be used. + @return The identification predicate. */ -- (void)setEntityIdentifier:(RKEntityIdentifier *)entityIdentifier forRelationship:(NSString *)relationshipName; +@property (nonatomic, copy) NSPredicate *identificationPredicate; -/** - Returns the entity identifier for the relationship with the given name. - - This method will return `nil` unless an entity identifier was specified via the `setEntityIdentifier:forRelationship:` method. - - @param relationshipName The name of the relationship to retrieve the entity identifier for. - @return The entity identifier for the specified relationship or `nil` if none was configured. - */ -- (RKEntityIdentifier *)entityIdentifierForRelationship:(NSString *)relationshipName; ///------------------------------------------- /// @name Configuring Relationship Connections @@ -120,7 +122,7 @@ /** Returns the array of `RKConnectionDescripton` objects configured for connecting relationships during object mapping. */ -@property (weak, nonatomic, readonly) NSArray *connections; +@property (nonatomic, copy, readonly) NSArray *connections; /** Adds a connection to the receiver. @@ -185,24 +187,43 @@ */ - (id)defaultValueForAttribute:(NSString *)attributeName; -///---------------------------------------------- -/// @name Configuring Entity Identifier Inference -///---------------------------------------------- +///-------------------------------------------------- +/// @name Configuring Entity Identification Inference +///-------------------------------------------------- /** - Enables or disabled entity identifier inference. + Enables or disabled entity identification inference. **Default:** `YES` - @param enabled A Boolean value indicating if entity identifier inference is to be performed. + @param enabled A Boolean value indicating if entity identification inference is to be performed. */ -+ (void)setEntityIdentifierInferenceEnabled:(BOOL)enabled; ++ (void)setEntityIdentificationInferenceEnabled:(BOOL)enabled; /** - Returns a Boolean value that indicates is entity identifier inference has been enabled. + Returns a Boolean value that indicates if entity identification inference has been enabled. - @return `YES` if entity identifier inference is enabled, else `NO`. + @return `YES` if entity identification inference is enabled, else `NO`. */ -+ (BOOL)isEntityIdentifierInferenceEnabled; ++ (BOOL)isEntityIdentificationInferenceEnabled; @end + +/** + The name of a key in the user info dictionary of a `NSEntityDescription` specifying the name or one or more attributes to be used to infer an entity identifier. The value of this string is 'RKEntityIdentificationAttributes'. + */ +extern NSString * const RKEntityIdentificationAttributesUserInfoKey; + +///---------------- +/// @name Functions +///---------------- + +/** + Returns an array of attributes likely to be usable for identification purposes inferred from the given entity. + + Please see the documentation accompanying the `RKEntityMapping` class for details about the inference rules. + + @param entity The entity to infer identification from. + @return An array containing identifying attributes inferred from the given entity or `nil` if none could be inferred. + */ +NSArray *RKIdentificationAttributesInferredFromEntity(NSEntityDescription *entity); diff --git a/Code/CoreData/RKEntityMapping.m b/Code/CoreData/RKEntityMapping.m index c0990174e8..78d5e56bfb 100644 --- a/Code/CoreData/RKEntityMapping.m +++ b/Code/CoreData/RKEntityMapping.m @@ -30,21 +30,86 @@ #undef RKLogComponent #define RKLogComponent RKlcl_cRestKitCoreData -static BOOL entityIdentifierInferenceEnabled = YES; +NSString * const RKEntityIdentificationAttributesUserInfoKey = @"RKEntityIdentificationAttributes"; -static void RKInferIdentifiersForEntityMapping(RKEntityMapping *entityMapping) +#pragma mark - Functions + +static NSArray *RKEntityIdentificationAttributesFromUserInfoOfEntity(NSEntityDescription *entity) { - if (! [RKEntityMapping isEntityIdentifierInferenceEnabled]) return; + id userInfoValue = [entity userInfo][RKEntityIdentificationAttributesUserInfoKey]; + if (userInfoValue) { + NSArray *attributeNames = [userInfoValue isKindOfClass:[NSArray class]] ? userInfoValue : @[ userInfoValue ]; + NSMutableArray *attributes = [NSMutableArray arrayWithCapacity:[attributeNames count]]; + [attributeNames enumerateObjectsUsingBlock:^(NSString *attributeName, NSUInteger idx, BOOL *stop) { + if (! [attributeName isKindOfClass:[NSString class]]) { + [NSException raise:NSInvalidArgumentException format:@"Invalid value given in user info key '%@' of entity '%@': expected an `NSString` or `NSArray` of strings, instead got '%@' (%@)", RKEntityIdentificationAttributesUserInfoKey, [entity name], attributeName, [attributeName class]]; + } + + NSAttributeDescription *attribute = [entity attributesByName][attributeName]; + if (! attribute) { + [NSException raise:NSInvalidArgumentException format:@"Invalid identifier attribute specified in user info key '%@' of entity '%@': no attribue was found with the name '%@'", RKEntityIdentificationAttributesUserInfoKey, [entity name], attributeName]; + } + + [attributes addObject:attribute]; + }]; + return attributes; + } - entityMapping.entityIdentifier = [RKEntityIdentifier inferredIdentifierForEntity:entityMapping.entity]; - [[entityMapping.entity relationshipsByName] enumerateKeysAndObjectsUsingBlock:^(NSString *relationshipName, NSRelationshipDescription *relationship, BOOL *stop) { - RKEntityIdentifier *entityIdentififer = [RKEntityIdentifier inferredIdentifierForEntity:relationship.destinationEntity]; - if (entityIdentififer) { - [entityMapping setEntityIdentifier:entityIdentififer forRelationship:relationshipName]; + return nil; +} + +// Given 'Human', returns 'humanID'; Given 'AmenityReview' returns 'amenityReviewID' +static NSString *RKEntityIdentificationAttributeNameForEntity(NSEntityDescription *entity) +{ + NSString *entityName = [entity name]; + NSString *lowerCasedFirstCharacter = [[entityName substringToIndex:1] lowercaseString]; + return [NSString stringWithFormat:@"%@%@ID", lowerCasedFirstCharacter, [entityName substringFromIndex:1]]; +} + +static NSArray *RKEntityIdentificationAttributeNames() +{ + return [NSArray arrayWithObjects:@"identifier", @"id", @"ID", @"URL", @"url", nil]; +} + +static NSArray *RKArrayOfAttributesForEntityFromAttributesOrNames(NSEntityDescription *entity, NSArray *attributesOrNames) +{ + NSMutableArray *attributes = [NSMutableArray arrayWithCapacity:[attributesOrNames count]]; + for (id attributeOrName in attributesOrNames) { + if ([attributeOrName isKindOfClass:[NSAttributeDescription class]]) { + if (! [[entity properties] containsObject:attributeOrName]) [NSException raise:NSInvalidArgumentException format:@"Invalid attribute value '%@' given for entity identifer: not found in the '%@' entity", attributeOrName, [entity name]]; + [attributes addObject:attributeOrName]; + } else if ([attributeOrName isKindOfClass:[NSString class]]) { + NSAttributeDescription *attribute = [entity attributesByName][attributeOrName]; + if (!attribute) [NSException raise:NSInvalidArgumentException format:@"Invalid attribute '%@': no attribute was found for the given name in the '%@' entity.", attributeOrName, [entity name]]; + [attributes addObject:attribute]; + } else { + [NSException raise:NSInvalidArgumentException format:@"Invalid value provided for entity identifier attribute: Acceptable values are either `NSAttributeDescription` or `NSString` objects."]; } - }]; + } + + return attributes; } +NSArray *RKIdentificationAttributesInferredFromEntity(NSEntityDescription *entity) +{ + NSArray *attributes = RKEntityIdentificationAttributesFromUserInfoOfEntity(entity); + if (attributes) { + return RKArrayOfAttributesForEntityFromAttributesOrNames(entity, attributes); + } + + NSMutableArray *identifyingAttributes = [NSMutableArray arrayWithObject:RKEntityIdentificationAttributeNameForEntity(entity)]; + [identifyingAttributes addObjectsFromArray:RKEntityIdentificationAttributeNames()]; + for (NSString *attributeName in identifyingAttributes) { + NSAttributeDescription *attribute = [entity attributesByName][attributeName]; + if (attribute) { + return @[ attribute ]; + } + } + return nil; +} + +static BOOL entityIdentificationInferenceEnabled = YES; + @interface RKObjectMapping (Private) - (NSString *)transformSourceKeyPath:(NSString *)keyPath; @end @@ -52,11 +117,12 @@ - (NSString *)transformSourceKeyPath:(NSString *)keyPath; @interface RKEntityMapping () @property (nonatomic, weak, readwrite) Class objectClass; @property (nonatomic, strong) NSMutableArray *mutableConnections; -@property (nonatomic, strong) NSMutableDictionary *relationshipNamesToEntityIdentifiers; @end @implementation RKEntityMapping +@synthesize identificationAttributes = _identificationAttributes; + + (id)mappingForClass:(Class)objectClass { @throw [NSException exceptionWithName:NSInternalInconsistencyException @@ -78,7 +144,7 @@ - (id)initWithEntity:(NSEntityDescription *)entity self = [self initWithClass:objectClass]; if (self) { self.entity = entity; - RKInferIdentifiersForEntityMapping(self); + if ([RKEntityMapping isEntityIdentificationInferenceEnabled]) self.identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); } return self; @@ -89,7 +155,6 @@ - (id)initWithClass:(Class)objectClass self = [super initWithClass:objectClass]; if (self) { self.mutableConnections = [NSMutableArray array]; - self.relationshipNamesToEntityIdentifiers = [NSMutableDictionary dictionary]; } return self; @@ -98,7 +163,8 @@ - (id)initWithClass:(Class)objectClass - (id)copyWithZone:(NSZone *)zone { RKEntityMapping *copy = [super copyWithZone:zone]; - copy.entityIdentifier = [self.entityIdentifier copy]; + copy.identificationAttributes = self.identificationAttributes; + copy.identificationPredicate = self.identificationPredicate; for (RKConnectionDescription *connection in self.connections) { [copy addConnection:[connection copy]]; @@ -107,6 +173,17 @@ - (id)copyWithZone:(NSZone *)zone return copy; } +- (void)setIdentificationAttributes:(NSArray *)attributesOrNames +{ + if (attributesOrNames && [attributesOrNames count] == 0) [NSException raise:NSInvalidArgumentException format:@"At least one attribute must be provided to identify managed objects"]; + _identificationAttributes = attributesOrNames ? RKArrayOfAttributesForEntityFromAttributesOrNames(self.entity, attributesOrNames) : nil; +} + +- (NSArray *)identificationAttributes +{ + return _identificationAttributes; +} + - (RKConnectionDescription *)connectionForRelationship:(id)relationshipOrName { NSAssert([relationshipOrName isKindOfClass:[NSString class]] || [relationshipOrName isKindOfClass:[NSRelationshipDescription class]], @"Relationship specifier must be a name or a relationship description"); @@ -163,31 +240,6 @@ - (void)addConnectionForRelationship:(id)relationshipOrName connectedBy:(id)conn [self.mutableConnections addObject:connection]; } -- (void)setEntityIdentifier:(RKEntityIdentifier *)entityIdentifier -{ - NSAssert(entityIdentifier == nil || [entityIdentifier.entity isKindOfEntity:self.entity], @"Invalid entity identifier value: The identifier given is for the '%@' entity.", [entityIdentifier.entity name]); - _entityIdentifier = entityIdentifier; -} - -- (void)setEntityIdentifier:(RKEntityIdentifier *)entityIdentifier forRelationship:(NSString *)relationshipName -{ - NSRelationshipDescription *relationship = [self.entity relationshipsByName][relationshipName]; - NSAssert(relationship, @"Cannot set entity identififer for relationship '%@': no relationship found for that name.", relationshipName); - NSAssert([[relationship destinationEntity] isKindOfEntity:entityIdentifier.entity], @"Cannot set entity identifier for relationship '%@': the given relationship identifier is for the '%@' entity, but the '%@' entity was expected.", relationshipName, [entityIdentifier.entity name], [[relationship destinationEntity] name]); - self.relationshipNamesToEntityIdentifiers[relationshipName] = entityIdentifier; -} - -- (RKEntityIdentifier *)entityIdentifierForRelationship:(NSString *)relationshipName -{ - RKEntityIdentifier *entityIdentifier = self.relationshipNamesToEntityIdentifiers[relationshipName]; - if (! entityIdentifier) { - RKRelationshipMapping *relationshipMapping = [self propertyMappingsByDestinationKeyPath][relationshipName]; - entityIdentifier = [relationshipMapping.mapping isKindOfClass:[RKEntityIdentifier class]] ? [(RKEntityMapping *)relationshipMapping.mapping entityIdentifier] : nil; - } - - return entityIdentifier; -} - - (id)defaultValueForAttribute:(NSString *)attributeName { NSAttributeDescription *desc = [[self.entity attributesByName] valueForKey:attributeName]; @@ -204,14 +256,14 @@ - (Class)classForProperty:(NSString *)propertyName return propertyClass; } -+ (void)setEntityIdentifierInferenceEnabled:(BOOL)enabled ++ (void)setEntityIdentificationInferenceEnabled:(BOOL)enabled { - entityIdentifierInferenceEnabled = enabled; + entityIdentificationInferenceEnabled = enabled; } -+ (BOOL)isEntityIdentifierInferenceEnabled ++ (BOOL)isEntityIdentificationInferenceEnabled { - return entityIdentifierInferenceEnabled; + return entityIdentificationInferenceEnabled; } @end diff --git a/Code/CoreData/RKManagedObjectMappingOperationDataSource.m b/Code/CoreData/RKManagedObjectMappingOperationDataSource.m index 25dbbd52de..ad00313f29 100644 --- a/Code/CoreData/RKManagedObjectMappingOperationDataSource.m +++ b/Code/CoreData/RKManagedObjectMappingOperationDataSource.m @@ -38,7 +38,7 @@ // Return YES if the entity is identified by an attribute that acts as the nesting key in the source representation static BOOL RKEntityMappingIsIdentifiedByNestingAttribute(RKEntityMapping *entityMapping) { - for (NSAttributeDescription *attribute in entityMapping.entityIdentifier.attributes) { + for (NSAttributeDescription *attribute in [entityMapping identificationAttributes]) { RKAttributeMapping *attributeMapping = [[entityMapping propertyMappingsByDestinationKeyPath] objectForKey:[attribute name]]; if ([attributeMapping.sourceKeyPath isEqualToString:RKObjectMappingNestingAttributeKeyName]) { return YES; @@ -49,10 +49,10 @@ static BOOL RKEntityMappingIsIdentifiedByNestingAttribute(RKEntityMapping *entit } // We always need to map the dynamic nesting attribute first so that sub-key attribute mappings apply cleanly -static NSArray *RKEntityIdentifierAttributesInMappingOrder(RKEntityMapping *entityMapping) +static NSArray *RKEntityIdentificationAttributesInMappingOrder(RKEntityMapping *entityMapping) { - NSMutableArray *orderedAttributes = [NSMutableArray arrayWithCapacity:[entityMapping.entityIdentifier.attributes count]]; - for (NSAttributeDescription *attribute in entityMapping.entityIdentifier.attributes) { + 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 @@ -86,11 +86,11 @@ static id RKValueForAttributeMappingInRepresentation(RKAttributeMapping *attribu /** This function is the workhorse for extracting entity identifier attributes from a dictionary representation. It supports type transformations, compound entity identifier attributes, and dynamic nesting keys within the representation. */ -static NSDictionary *RKEntityIdentifierAttributesForEntityMappingWithRepresentation(RKEntityMapping *entityMapping, NSDictionary *representation) +static NSDictionary *RKEntityIdentificationAttributesForEntityMappingWithRepresentation(RKEntityMapping *entityMapping, NSDictionary *representation) { RKDateToStringValueTransformer *dateToStringTransformer = [[RKDateToStringValueTransformer alloc] initWithDateToStringFormatter:entityMapping.preferredDateFormatter stringToDateFormatters:entityMapping.dateFormatters]; - NSArray *orderedAttributes = RKEntityIdentifierAttributesInMappingOrder(entityMapping); + 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"); @@ -151,7 +151,7 @@ - (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRep } RKEntityMapping *entityMapping = (RKEntityMapping *)mapping; - NSDictionary *entityIdentifierAttributes = RKEntityIdentifierAttributesForEntityMappingWithRepresentation(entityMapping, representation); + NSDictionary *entityIdentifierAttributes = RKEntityIdentificationAttributesForEntityMappingWithRepresentation(entityMapping, representation); if (! self.managedObjectCache) { RKLogWarning(@"Performing managed object mapping with a nil managed object cache:\n" "Unable to update existing object instances by primary key. Duplicate objects may be created."); @@ -164,7 +164,7 @@ - (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRep NSArray *objects = [self.managedObjectCache managedObjectsWithEntity:entity attributeValues:entityIdentifierAttributes inManagedObjectContext:self.managedObjectContext]; - if (entityMapping.entityIdentifier.predicate) objects = [objects filteredArrayUsingPredicate:entityMapping.entityIdentifier.predicate]; + if (entityMapping.identificationPredicate) objects = [objects filteredArrayUsingPredicate:entityMapping.identificationPredicate]; if ([objects count] > 0) { managedObject = objects[0]; if ([objects count] > 1) RKLogWarning(@"Managed object cache returned %ld objects for the identifier configured for the '%@' entity, expected 1.", (long) [objects count], [entity name]); diff --git a/Examples/RKTwitterCoreData/Classes/RKTwitterAppDelegate.m b/Examples/RKTwitterCoreData/Classes/RKTwitterAppDelegate.m index 9c9252401f..54241a784c 100644 --- a/Examples/RKTwitterCoreData/Classes/RKTwitterAppDelegate.m +++ b/Examples/RKTwitterCoreData/Classes/RKTwitterAppDelegate.m @@ -40,7 +40,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( there is no backing model class! */ RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:@"User" inManagedObjectStore:managedObjectStore]; - [userMapping setEntityIdentifier:[RKEntityIdentifier identifierWithEntityName:@"User" attributes:@[ @"userID" ] inManagedObjectStore:managedObjectStore]]; + userMapping.identificationAttributes = @[ @"userID" ]; [userMapping addAttributeMappingsFromDictionary:@{ @"id": @"userID", @"screen_name": @"screenName", @@ -49,7 +49,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [userMapping addAttributeMappingsFromArray:@[ @"name" ]]; RKEntityMapping *tweetMapping = [RKEntityMapping mappingForEntityForName:@"Tweet" inManagedObjectStore:managedObjectStore]; - [tweetMapping setEntityIdentifier:[RKEntityIdentifier identifierWithEntityName:@"Tweet" attributes:@[ @"statusID" ] inManagedObjectStore:managedObjectStore]]; + userMapping.identificationAttributes = @[ @"statusID" ]; [tweetMapping addAttributeMappingsFromDictionary:@{ @"id": @"statusID", @"created_at": @"createdAt", diff --git a/RestKit.xcodeproj/project.pbxproj b/RestKit.xcodeproj/project.pbxproj index 8340e44546..be286dbb12 100644 --- a/RestKit.xcodeproj/project.pbxproj +++ b/RestKit.xcodeproj/project.pbxproj @@ -525,16 +525,10 @@ 25DB7509151BD551009F01AF /* NSManagedObjectContext+RKAdditionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DB7507151BD551009F01AF /* NSManagedObjectContext+RKAdditionsTest.m */; }; 25E36E0215195CED00F9E448 /* RKFetchRequestMappingCacheTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E36E0115195CED00F9E448 /* RKFetchRequestMappingCacheTest.m */; }; 25E36E0315195CED00F9E448 /* RKFetchRequestMappingCacheTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E36E0115195CED00F9E448 /* RKFetchRequestMappingCacheTest.m */; }; - 25E88C82165C5B580042ABD0 /* RKEntityIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E88C80165C5B580042ABD0 /* RKEntityIdentifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 25E88C83165C5B580042ABD0 /* RKEntityIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E88C80165C5B580042ABD0 /* RKEntityIdentifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 25E88C84165C5B580042ABD0 /* RKEntityIdentifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E88C81165C5B580042ABD0 /* RKEntityIdentifier.m */; }; - 25E88C85165C5B580042ABD0 /* RKEntityIdentifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E88C81165C5B580042ABD0 /* RKEntityIdentifier.m */; }; 25E88C88165C5CC30042ABD0 /* RKConnectionDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E88C86165C5CC30042ABD0 /* RKConnectionDescription.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25E88C89165C5CC30042ABD0 /* RKConnectionDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E88C86165C5CC30042ABD0 /* RKConnectionDescription.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25E88C8A165C5CC30042ABD0 /* RKConnectionDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E88C87165C5CC30042ABD0 /* RKConnectionDescription.m */; }; 25E88C8B165C5CC30042ABD0 /* RKConnectionDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E88C87165C5CC30042ABD0 /* RKConnectionDescription.m */; }; - 25E88C8E165C87FF0042ABD0 /* RKEntityIdentifierTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E88C8D165C87FF0042ABD0 /* RKEntityIdentifierTest.m */; }; - 25E88C8F165C87FF0042ABD0 /* RKEntityIdentifierTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E88C8D165C87FF0042ABD0 /* RKEntityIdentifierTest.m */; }; 25E9C8F01612523400647F84 /* RKObjectParameterizationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 251610261456F2330060A5C5 /* RKObjectParameterizationTest.m */; }; 25E9C8F1161290D500647F84 /* RKObjectParameterization.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372A715F54995006E8424 /* RKObjectParameterization.m */; }; 25EC1A3914F72B0900C3CF3F /* RKFetchRequestManagedObjectCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 7394DF3814CF168C00CE7BCE /* RKFetchRequestManagedObjectCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -910,11 +904,8 @@ 25CDA0E2161E821000F583F3 /* RKISODateFormatterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKISODateFormatterTest.m; sourceTree = ""; }; 25DB7507151BD551009F01AF /* NSManagedObjectContext+RKAdditionsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObjectContext+RKAdditionsTest.m"; sourceTree = ""; }; 25E36E0115195CED00F9E448 /* RKFetchRequestMappingCacheTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKFetchRequestMappingCacheTest.m; sourceTree = ""; }; - 25E88C80165C5B580042ABD0 /* RKEntityIdentifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKEntityIdentifier.h; sourceTree = ""; }; - 25E88C81165C5B580042ABD0 /* RKEntityIdentifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKEntityIdentifier.m; sourceTree = ""; }; 25E88C86165C5CC30042ABD0 /* RKConnectionDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKConnectionDescription.h; sourceTree = ""; }; 25E88C87165C5CC30042ABD0 /* RKConnectionDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKConnectionDescription.m; sourceTree = ""; }; - 25E88C8D165C87FF0042ABD0 /* RKEntityIdentifierTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKEntityIdentifierTest.m; sourceTree = ""; }; 25EC1AD814F8022600C3CF3F /* RestKitFramework-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RestKitFramework-Info.plist"; sourceTree = ""; }; 25EC1AD914F8022600C3CF3F /* RestKitFrameworkTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RestKitFrameworkTests-Info.plist"; sourceTree = ""; }; 25EC1ADA14F8022600C3CF3F /* RestKitTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RestKitTests-Info.plist"; sourceTree = ""; }; @@ -1310,7 +1301,6 @@ 25AA23D315AF4F25006EF62D /* RKManagedObjectMappingOperationDataSourceTest.m */, 258EFF7915C0CE1400EE4E0D /* RKManagedObjectSeederTest.m */, 2564E40A16173F7B00C12D7D /* RKRelationshipConnectionOperationTest.m */, - 25E88C8D165C87FF0042ABD0 /* RKEntityIdentifierTest.m */, 2546A95716628EDD0078E044 /* RKConnectionDescriptionTest.m */, ); name = CoreData; @@ -1616,8 +1606,6 @@ 259D98531550C69A008C90F5 /* RKEntityByAttributeCache.m */, 259D985C155218E4008C90F5 /* RKEntityCache.h */, 259D985D155218E4008C90F5 /* RKEntityCache.m */, - 25E88C80165C5B580042ABD0 /* RKEntityIdentifier.h */, - 25E88C81165C5B580042ABD0 /* RKEntityIdentifier.m */, ); name = ManagedObjectCaching; sourceTree = ""; @@ -1785,7 +1773,6 @@ 25A226D61618A57500952D72 /* RKObjectUtilities.h in Headers */, 2507C327161BD5C700EA71FF /* RKTestHelpers.h in Headers */, 25CDA0DC161E7ED400F583F3 /* RKISO8601DateFormatter.h in Headers */, - 25E88C82165C5B580042ABD0 /* RKEntityIdentifier.h in Headers */, 25E88C88165C5CC30042ABD0 /* RKConnectionDescription.h in Headers */, 25019495166406E30081D68A /* RKValueTransformers.h in Headers */, ); @@ -1886,7 +1873,6 @@ 25A226D71618A57500952D72 /* RKObjectUtilities.h in Headers */, 2507C328161BD5C700EA71FF /* RKTestHelpers.h in Headers */, 25CDA0DD161E7ED400F583F3 /* RKISO8601DateFormatter.h in Headers */, - 25E88C83165C5B580042ABD0 /* RKEntityIdentifier.h in Headers */, 25E88C89165C5CC30042ABD0 /* RKConnectionDescription.h in Headers */, 25019496166406E30081D68A /* RKValueTransformers.h in Headers */, 255893E3166BA6A20010C70B /* RKObjectParameterization.h in Headers */, @@ -2289,7 +2275,6 @@ 25A226D81618A57500952D72 /* RKObjectUtilities.m in Sources */, 2507C329161BD5C700EA71FF /* RKTestHelpers.m in Sources */, 25CDA0DE161E7ED400F583F3 /* RKISO8601DateFormatter.m in Sources */, - 25E88C84165C5B580042ABD0 /* RKEntityIdentifier.m in Sources */, 25E88C8A165C5CC30042ABD0 /* RKConnectionDescription.m in Sources */, 25019497166406E30081D68A /* RKValueTransformers.m in Sources */, ); @@ -2352,7 +2337,6 @@ 2506759F162DEA25003210B0 /* RKEntityMappingTest.m in Sources */, 2548AC6D162F5E00009E79BF /* RKManagedObjectRequestOperationTest.m in Sources */, 255F87911656B22D00914D57 /* RKPaginatorTest.m in Sources */, - 25E88C8E165C87FF0042ABD0 /* RKEntityIdentifierTest.m in Sources */, 2546A95816628EDD0078E044 /* RKConnectionDescriptionTest.m in Sources */, 2543A25D1664FD3100821D5B /* RKResponseDescriptorTest.m in Sources */, ); @@ -2438,7 +2422,6 @@ 25A226D91618A57500952D72 /* RKObjectUtilities.m in Sources */, 2507C32A161BD5C700EA71FF /* RKTestHelpers.m in Sources */, 25CDA0DF161E7ED400F583F3 /* RKISO8601DateFormatter.m in Sources */, - 25E88C85165C5B580042ABD0 /* RKEntityIdentifier.m in Sources */, 25E88C8B165C5CC30042ABD0 /* RKConnectionDescription.m in Sources */, 25019498166406E30081D68A /* RKValueTransformers.m in Sources */, ); @@ -2501,7 +2484,6 @@ 250675A1162DEA27003210B0 /* RKEntityMappingTest.m in Sources */, 2548AC6E162F5E00009E79BF /* RKManagedObjectRequestOperationTest.m in Sources */, 255F87921656B22F00914D57 /* RKPaginatorTest.m in Sources */, - 25E88C8F165C87FF0042ABD0 /* RKEntityIdentifierTest.m in Sources */, 2546A95916628EDD0078E044 /* RKConnectionDescriptionTest.m in Sources */, 2543A25E1664FD3200821D5B /* RKResponseDescriptorTest.m in Sources */, ); @@ -2613,6 +2595,7 @@ }; 25160D3E14564E820060A5C5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 964648386780496FA49D3DD6 /* Pods.xcconfig */; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; FRAMEWORK_SEARCH_PATHS = ( @@ -2637,6 +2620,7 @@ }; 25160D3F14564E820060A5C5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 964648386780496FA49D3DD6 /* Pods.xcconfig */; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; FRAMEWORK_SEARCH_PATHS = ( @@ -2717,6 +2701,7 @@ }; 25160E8B145651060060A5C5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 964648386780496FA49D3DD6 /* Pods.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; @@ -2741,6 +2726,7 @@ }; 25160E8C145651060060A5C5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 964648386780496FA49D3DD6 /* Pods.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; diff --git a/Tests/Logic/CoreData/RKEntityIdentifierTest.m b/Tests/Logic/CoreData/RKEntityIdentifierTest.m deleted file mode 100644 index 77914a0561..0000000000 --- a/Tests/Logic/CoreData/RKEntityIdentifierTest.m +++ /dev/null @@ -1,225 +0,0 @@ -// -// RKEntityIndexTest.m -// RestKit -// -// Created by Blake Watters on 11/20/12. -// Copyright (c) 2012 RestKit. All rights reserved. -// - -#import "RKTestEnvironment.h" -#import "RKEntityIdentifier.h" - -@interface RKEntityIdentifierTest : RKTestCase - -@end - -@implementation RKEntityIdentifierTest - -- (void)setUp -{ - [RKTestFactory setUp]; -} - -- (void)testThatInitEntityIdentifierWithNilAttributesRaisesException -{ - RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; - NSEntityDescription *entity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; - NSException *expectedExcepetion = nil; - @try { - RKEntityIdentifier *entityIdentifier __unused = [[RKEntityIdentifier alloc] initWithEntity:entity attributes:nil]; - } - @catch (NSException *exception) { - expectedExcepetion = exception; - } - expect(expectedExcepetion).notTo.beNil(); - expect([expectedExcepetion description]).to.equal(@"Invalid parameter not satisfying: attributes"); -} - -- (void)testThatInitEntityIdentifierWithEmptyAttributesRaisesException -{ - RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; - NSEntityDescription *entity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; - NSException *expectedExcepetion = nil; - @try { - RKEntityIdentifier *entityIdentifier __unused = [[RKEntityIdentifier alloc] initWithEntity:entity attributes:@[]]; - } - @catch (NSException *exception) { - expectedExcepetion = exception; - } - expect(expectedExcepetion).notTo.beNil(); - expect([expectedExcepetion description]).to.equal(@"At least one attribute must be provided to identify managed objects"); -} - -- (void)testThatInitWithInvalidEntityNameRaisesError -{ - RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; - NSException *expectedExcepetion = nil; - @try { - RKEntityIdentifier *entityIdentifier __unused = [RKEntityIdentifier identifierWithEntityName:@"Invalid" attributes:nil inManagedObjectStore:managedObjectStore]; - } - @catch (NSException *exception) { - expectedExcepetion = exception; - } - expect(expectedExcepetion).notTo.beNil(); - expect([expectedExcepetion description]).to.equal(@"Invalid parameter not satisfying: entity"); -} - -- (void)testInitializingEntityIdentifierByName -{ - RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; - NSEntityDescription *entity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; - NSAttributeDescription *railsIDAttribute = entity.attributesByName[@"railsID"]; - RKEntityIdentifier *entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; - expect(entityIdentifier.entity).to.equal(entity); - NSArray *attributes = @[ railsIDAttribute ]; - expect(entityIdentifier.attributes).equal(attributes); -} - -#pragma mark - Entity Identifier Inference - -// TODO: The attributes to auto-detect: entityNameID, ID, identififer, url, URL - -- (void)testEntityIdentifierInferenceForEntityWithLlamaCasedIDAttribute -{ - NSEntityDescription *entity = [[NSEntityDescription alloc] init]; - [entity setName:@"Monkey"]; - NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; - [identifierAttribute setName:@"monkeyID"]; - [entity setProperties:@[ identifierAttribute ]]; - RKEntityIdentifier *entityIdentifier = [RKEntityIdentifier inferredIdentifierForEntity:entity]; - expect(entityIdentifier).notTo.beNil(); - NSArray *attributeNames = @[ @"monkeyID" ]; - expect([[entityIdentifier attributes] valueForKey:@"name"]).to.equal(attributeNames); -} - -- (void)testEntityIdentifierInferenceForEntityWithIDAttribute -{ - NSEntityDescription *entity = [[NSEntityDescription alloc] init]; - [entity setName:@"Monkey"]; - NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; - [identifierAttribute setName:@"ID"]; - [entity setProperties:@[ identifierAttribute ]]; - RKEntityIdentifier *entityIdentifier = [RKEntityIdentifier inferredIdentifierForEntity:entity]; - expect(entityIdentifier).notTo.beNil(); - NSArray *attributeNames = @[ @"ID" ]; - expect([[entityIdentifier attributes] valueForKey:@"name"]).to.equal(attributeNames); -} - -- (void)testEntityIdentifierInferenceForEntityWithIdentifierAttribute -{ - NSEntityDescription *entity = [[NSEntityDescription alloc] init]; - [entity setName:@"Monkey"]; - NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; - [identifierAttribute setName:@"identifier"]; - [entity setProperties:@[ identifierAttribute ]]; - RKEntityIdentifier *entityIdentifier = [RKEntityIdentifier inferredIdentifierForEntity:entity]; - expect(entityIdentifier).notTo.beNil(); - NSArray *attributeNames = @[ @"identifier" ]; - expect([[entityIdentifier attributes] valueForKey:@"name"]).to.equal(attributeNames); -} - -- (void)testEntityIdentifierInferenceForEntityWithURLAttribute -{ - NSEntityDescription *entity = [[NSEntityDescription alloc] init]; - [entity setName:@"Monkey"]; - NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; - [identifierAttribute setName:@"URL"]; - [entity setProperties:@[ identifierAttribute ]]; - RKEntityIdentifier *entityIdentifier = [RKEntityIdentifier inferredIdentifierForEntity:entity]; - expect(entityIdentifier).notTo.beNil(); - NSArray *attributeNames = @[ @"URL" ]; - expect([[entityIdentifier attributes] valueForKey:@"name"]).to.equal(attributeNames); -} - -- (void)testEntityIdentifierInferenceForEntityWithUrlAttribute -{ - NSEntityDescription *entity = [[NSEntityDescription alloc] init]; - [entity setName:@"Monkey"]; - NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; - [identifierAttribute setName:@"url"]; - [entity setProperties:@[ identifierAttribute ]]; - RKEntityIdentifier *entityIdentifier = [RKEntityIdentifier inferredIdentifierForEntity:entity]; - expect(entityIdentifier).notTo.beNil(); - NSArray *attributeNames = @[ @"url" ]; - expect([[entityIdentifier attributes] valueForKey:@"name"]).to.equal(attributeNames); -} - -- (void)testEntityIdentifierInferenceFromUserInfoKeyForSingleValue -{ - NSEntityDescription *entity = [[NSEntityDescription alloc] init]; - [entity setName:@"Monkey"]; - NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; - [identifierAttribute setName:@"monkeyID"]; // We ignore this by specifying the userInfo key - NSAttributeDescription *nameAttribute = [NSAttributeDescription new]; - [nameAttribute setName:@"name"]; - [entity setProperties:@[ identifierAttribute, nameAttribute ]]; - [entity setUserInfo:@{ RKEntityIdentifierUserInfoKey: @"name" }]; - RKEntityIdentifier *entityIdentifier = [RKEntityIdentifier inferredIdentifierForEntity:entity]; - expect(entityIdentifier).notTo.beNil(); - NSArray *attributeNames = @[ @"name" ]; - expect([[entityIdentifier attributes] valueForKey:@"name"]).to.equal(attributeNames); -} - -- (void)testEntityIdentifierInferenceFromUserInfoKeyForArrayOfValues -{ - NSEntityDescription *entity = [[NSEntityDescription alloc] init]; - [entity setName:@"Monkey"]; - NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; - [identifierAttribute setName:@"monkeyID"]; - NSAttributeDescription *nameAttribute = [NSAttributeDescription new]; - [nameAttribute setName:@"name"]; - [entity setProperties:@[ identifierAttribute, nameAttribute ]]; - [entity setUserInfo:@{ RKEntityIdentifierUserInfoKey: @[ @"name", @"monkeyID" ] }]; - RKEntityIdentifier *entityIdentifier = [RKEntityIdentifier inferredIdentifierForEntity:entity]; - expect(entityIdentifier).notTo.beNil(); - NSArray *attributeNames = @[ @"name", @"monkeyID" ]; - expect([[entityIdentifier attributes] valueForKey:@"name"]).to.equal(attributeNames); -} - -- (void)testEntityIdentifierInferenceFromUserInfoKeyRaisesErrorForInvalidValue -{ - NSEntityDescription *entity = [[NSEntityDescription alloc] init]; - [entity setName:@"Monkey"]; - NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; - [identifierAttribute setName:@"monkeyID"]; - NSAttributeDescription *nameAttribute = [NSAttributeDescription new]; - [nameAttribute setName:@"name"]; - [entity setProperties:@[ identifierAttribute, nameAttribute ]]; - [entity setUserInfo:@{ RKEntityIdentifierUserInfoKey: @(12345) }]; - - NSException *caughtException = nil; - @try { - RKEntityIdentifier __unused *entityIdentifier = [RKEntityIdentifier inferredIdentifierForEntity:entity]; - } - @catch (NSException *exception) { - caughtException = exception; - } - @finally { - expect([caughtException name]).to.equal(NSInvalidArgumentException); - expect([caughtException reason]).to.equal(@"Invalid value given in user info key 'RKEntityIdentifierAttributes' of entity 'Monkey': expected an `NSString` or `NSArray` of strings, instead got '12345' (__NSCFNumber)"); - } -} - -- (void)testEntityIdentifierInferenceFromUserInfoKeyRaisesErrorForNonexistantAttributeName -{ - NSEntityDescription *entity = [[NSEntityDescription alloc] init]; - [entity setName:@"Monkey"]; - NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; - [identifierAttribute setName:@"monkeyID"]; - [entity setProperties:@[ identifierAttribute ]]; - [entity setUserInfo:@{ RKEntityIdentifierUserInfoKey: @"nonExistant" }]; - - NSException *caughtException = nil; - @try { - RKEntityIdentifier __unused *entityIdentifier = [RKEntityIdentifier inferredIdentifierForEntity:entity]; - } - @catch (NSException *exception) { - caughtException = exception; - } - @finally { - expect([caughtException name]).to.equal(NSInvalidArgumentException); - expect([caughtException reason]).to.equal(@"Invalid identifier attribute specified in user info key 'RKEntityIdentifierAttributes' of entity 'Monkey': no attribue was found with the name 'nonExistant'"); - } -} - -@end diff --git a/Tests/Logic/CoreData/RKEntityMappingTest.m b/Tests/Logic/CoreData/RKEntityMappingTest.m index ee9549c06e..2576bbd1df 100644 --- a/Tests/Logic/CoreData/RKEntityMappingTest.m +++ b/Tests/Logic/CoreData/RKEntityMappingTest.m @@ -42,7 +42,7 @@ - (void)tearDown { [RKTestFactory tearDown]; - [RKEntityMapping setEntityIdentifierInferenceEnabled:YES]; + [RKEntityMapping setEntityIdentificationInferenceEnabled:YES]; } - (void)testShouldReturnTheDefaultValueForACoreDataAttribute @@ -61,7 +61,7 @@ - (void)testShouldMapACollectionOfObjectsWithDynamicKeys managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; mapping.forceCollectionMapping = YES; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"name" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"name" ]; [mapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"name"]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"(name).id" toKeyPath:@"railsID"]; [mapping addPropertyMapping:idMapping]; @@ -89,11 +89,11 @@ - (void)testShouldPickTheAppropriateMappingBasedOnAnAttributeValue RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKDynamicMapping *dynamicMapping = [RKDynamicMapping new]; RKEntityMapping *childMapping = [RKEntityMapping mappingForEntityForName:@"Child" inManagedObjectStore:managedObjectStore]; - childMapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Child" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + childMapping.identificationAttributes = @[ @"railsID" ]; [childMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping *parentMapping = [RKEntityMapping mappingForEntityForName:@"Parent" inManagedObjectStore:managedObjectStore]; - parentMapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Parent" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + parentMapping.identificationAttributes = @[ @"railsID" ]; [parentMapping addAttributeMappingsFromArray:@[@"name", @"age"]]; [dynamicMapping setObjectMapping:parentMapping whenValueOfKeyPath:@"type" isEqualTo:@"Parent"]; @@ -193,24 +193,6 @@ - (void)testThatMappingAnNullArrayOnToAnExistingToManyRelationshipDisassociatesT expect(blake.cats).to.beEmpty(); } -- (void)testAssignmentOfEntityIdentifierForIncorrectEntityRaisesException -{ - RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; - RKEntityMapping *humanEntityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - RKEntityIdentifier *catIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Cat" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; - NSException *expectedException = nil; - @try { - humanEntityMapping.entityIdentifier = catIdentifier; - } - @catch (NSException *exception) { - expectedException = exception; - } - @finally { - expect(expectedException).notTo.beNil(); - expect([expectedException reason]).to.equal(@"Invalid entity identifier value: The identifier given is for the 'Cat' entity."); - } -} - - (void)testAddingConnectionByAttributeName { RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; @@ -269,80 +251,220 @@ - (void)testAddingConnectionByDictionaryOfAttributes expect(connection.attributes).to.equal(expectedAttributes); } -- (void)testSettingEntityIdentifierForRelationship -{ - RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; - RKEntityMapping *humanEntityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - [humanEntityMapping setEntityIdentifier:[RKEntityIdentifier identifierWithEntityName:@"Cat" attributes:@[ @"name" ] inManagedObjectStore:managedObjectStore] forRelationship:@"cats"]; - RKEntityIdentifier *entityIdentifier = [humanEntityMapping entityIdentifierForRelationship:@"cats"]; - expect(entityIdentifier).notTo.beNil(); - expect([entityIdentifier.attributes valueForKey:@"name"]).to.equal(@[ @"name" ]); -} - -- (void)testSettingEntityIdentifierForInvalidRelationshipRaisesError +- (void)testSettingEntityIdentificationAttributesWithInvalidAttributeNameRaisesException { RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping *humanEntityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; NSException *caughtException = nil; @try { - [humanEntityMapping setEntityIdentifier:[RKEntityIdentifier identifierWithEntityName:@"Cat" attributes:@[ @"name" ] inManagedObjectStore:managedObjectStore] forRelationship:@"invalid"]; + humanEntityMapping.identificationAttributes = @[ @"invalid" ]; } @catch (NSException *exception) { caughtException = exception; } @finally { expect(caughtException).notTo.beNil(); - expect([caughtException reason]).to.equal(@"Cannot set entity identififer for relationship 'invalid': no relationship found for that name."); + expect([caughtException reason]).to.equal(@"Invalid attribute 'invalid': no attribute was found for the given name in the 'Human' entity."); } } -- (void)testSettingEntityIdentifierWithEntityMismatchRaisesError +- (void)testEntityIdentifierInferenceOnInit { + [RKEntityMapping setEntityIdentificationInferenceEnabled:YES]; RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; - RKEntityMapping *humanEntityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - NSException *caughtException = nil; - @try { - [humanEntityMapping setEntityIdentifier:[RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"name" ] inManagedObjectStore:managedObjectStore] forRelationship:@"cats"]; - } - @catch (NSException *exception) { - caughtException = exception; - } - @finally { - NSLog(@"In finally the exception is: %@", caughtException); - expect(caughtException).notTo.beNil(); - expect([caughtException reason]).to.equal(@"Cannot set entity identifier for relationship 'cats': the given relationship identifier is for the 'Human' entity, but the 'Cat' entity was expected."); - } + NSEntityDescription *entity = [NSEntityDescription entityForName:@"Parent" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; + RKEntityMapping *entityMapping = [[RKEntityMapping alloc] initWithEntity:entity]; + expect(entityMapping.identificationAttributes).notTo.beNil(); + assertThat([entityMapping.identificationAttributes valueForKey:@"name"], equalTo(@[ @"parentID" ])); } -- (void)testEntityIdentifierInferenceOnInit +- (void)testInitWithIdentifierInferenceDisabled { - [RKEntityMapping setEntityIdentifierInferenceEnabled:YES]; + [RKEntityMapping setEntityIdentificationInferenceEnabled:NO]; RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Parent" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; RKEntityMapping *entityMapping = [[RKEntityMapping alloc] initWithEntity:entity]; - expect(entityMapping.entityIdentifier).notTo.beNil(); - assertThat([entityMapping.entityIdentifier.attributes valueForKey:@"name"], equalTo(@[ @"parentID" ])); + expect(entityMapping.identificationAttributes).to.beNil(); } -- (void)testInitWithIdentifierInferenceEnabledInfersIdentifiersForRelationships +#pragma mark - Entity Identification + +- (void)testThatInitEntityIdentificationAttributesToNil { - [RKEntityMapping setEntityIdentifierInferenceEnabled:YES]; RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; - NSEntityDescription *entity = [NSEntityDescription entityForName:@"Parent" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; + NSEntityDescription *entity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; RKEntityMapping *entityMapping = [[RKEntityMapping alloc] initWithEntity:entity]; - - RKEntityIdentifier *childrenIdentifier = [entityMapping entityIdentifierForRelationship:@"children"]; - expect(childrenIdentifier).notTo.beNil(); - assertThat([childrenIdentifier.attributes valueForKey:@"name"], equalTo(@[ @"childID" ])); + NSException *expectedExcepetion = nil; + @try { + entityMapping.identificationAttributes = nil; + } + @catch (NSException *exception) { + expectedExcepetion = exception; + } + expect(expectedExcepetion).to.beNil(); } -- (void)testInitWithIdentifierInferenceDisabled +- (void)testThatInitEntityIdentifierWithEmptyAttributesRaisesException { - [RKEntityMapping setEntityIdentifierInferenceEnabled:NO]; RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; - NSEntityDescription *entity = [NSEntityDescription entityForName:@"Parent" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; + NSEntityDescription *entity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; + NSException *expectedExcepetion = nil; RKEntityMapping *entityMapping = [[RKEntityMapping alloc] initWithEntity:entity]; - expect(entityMapping.entityIdentifier).to.beNil(); + @try { + entityMapping.identificationAttributes = @[]; + } + @catch (NSException *exception) { + expectedExcepetion = exception; + } + expect(expectedExcepetion).notTo.beNil(); + expect([expectedExcepetion description]).to.equal(@"At least one attribute must be provided to identify managed objects"); +} + +#pragma mark - Entity Identifier Inference + +// TODO: The attributes to auto-detect: entityNameID, ID, identififer, url, URL + +- (void)testEntityIdentifierInferenceForEntityWithLlamaCasedIDAttribute +{ + NSEntityDescription *entity = [[NSEntityDescription alloc] init]; + [entity setName:@"Monkey"]; + NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; + [identifierAttribute setName:@"monkeyID"]; + [entity setProperties:@[ identifierAttribute ]]; + NSArray *identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + expect(identificationAttributes).notTo.beNil(); + NSArray *attributeNames = @[ @"monkeyID" ]; + expect([identificationAttributes valueForKey:@"name"]).to.equal(attributeNames); +} + +- (void)testEntityIdentifierInferenceForEntityWithIDAttribute +{ + NSEntityDescription *entity = [[NSEntityDescription alloc] init]; + [entity setName:@"Monkey"]; + NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; + [identifierAttribute setName:@"ID"]; + [entity setProperties:@[ identifierAttribute ]]; + NSArray *identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + expect(identificationAttributes).notTo.beNil(); + NSArray *attributeNames = @[ @"ID" ]; + expect([identificationAttributes valueForKey:@"name"]).to.equal(attributeNames); +} + +- (void)testEntityIdentifierInferenceForEntityWithIdentifierAttribute +{ + NSEntityDescription *entity = [[NSEntityDescription alloc] init]; + [entity setName:@"Monkey"]; + NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; + [identifierAttribute setName:@"identifier"]; + [entity setProperties:@[ identifierAttribute ]]; + NSArray *identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + expect(identificationAttributes).notTo.beNil(); + NSArray *attributeNames = @[ @"identifier" ]; + expect([identificationAttributes valueForKey:@"name"]).to.equal(attributeNames); +} + +- (void)testEntityIdentifierInferenceForEntityWithURLAttribute +{ + NSEntityDescription *entity = [[NSEntityDescription alloc] init]; + [entity setName:@"Monkey"]; + NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; + [identifierAttribute setName:@"URL"]; + [entity setProperties:@[ identifierAttribute ]]; + NSArray *identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + expect(identificationAttributes).notTo.beNil(); + NSArray *attributeNames = @[ @"URL" ]; + expect([identificationAttributes valueForKey:@"name"]).to.equal(attributeNames); +} + +- (void)testEntityIdentifierInferenceForEntityWithUrlAttribute +{ + NSEntityDescription *entity = [[NSEntityDescription alloc] init]; + [entity setName:@"Monkey"]; + NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; + [identifierAttribute setName:@"url"]; + [entity setProperties:@[ identifierAttribute ]]; + NSArray *identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + expect(identificationAttributes).notTo.beNil(); + NSArray *attributeNames = @[ @"url" ]; + expect([identificationAttributes valueForKey:@"name"]).to.equal(attributeNames); +} + +- (void)testEntityIdentifierInferenceFromUserInfoKeyForSingleValue +{ + NSEntityDescription *entity = [[NSEntityDescription alloc] init]; + [entity setName:@"Monkey"]; + NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; + [identifierAttribute setName:@"monkeyID"]; // We ignore this by specifying the userInfo key + NSAttributeDescription *nameAttribute = [NSAttributeDescription new]; + [nameAttribute setName:@"name"]; + [entity setProperties:@[ identifierAttribute, nameAttribute ]]; + [entity setUserInfo:@{ RKEntityIdentificationAttributesUserInfoKey: @"name" }]; + NSArray *identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + expect(identificationAttributes).notTo.beNil(); + NSArray *attributeNames = @[ @"name" ]; + expect([identificationAttributes valueForKey:@"name"]).to.equal(attributeNames); +} + +- (void)testEntityIdentifierInferenceFromUserInfoKeyForArrayOfValues +{ + NSEntityDescription *entity = [[NSEntityDescription alloc] init]; + [entity setName:@"Monkey"]; + NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; + [identifierAttribute setName:@"monkeyID"]; + NSAttributeDescription *nameAttribute = [NSAttributeDescription new]; + [nameAttribute setName:@"name"]; + [entity setProperties:@[ identifierAttribute, nameAttribute ]]; + [entity setUserInfo:@{ RKEntityIdentificationAttributesUserInfoKey: @[ @"name", @"monkeyID" ] }]; + NSArray *identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + expect(identificationAttributes).notTo.beNil(); + NSArray *attributeNames = @[ @"name", @"monkeyID" ]; + expect([identificationAttributes valueForKey:@"name"]).to.equal(attributeNames); +} + +- (void)testEntityIdentifierInferenceFromUserInfoKeyRaisesErrorForInvalidValue +{ + NSEntityDescription *entity = [[NSEntityDescription alloc] init]; + [entity setName:@"Monkey"]; + NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; + [identifierAttribute setName:@"monkeyID"]; + NSAttributeDescription *nameAttribute = [NSAttributeDescription new]; + [nameAttribute setName:@"name"]; + [entity setProperties:@[ identifierAttribute, nameAttribute ]]; + [entity setUserInfo:@{ RKEntityIdentificationAttributesUserInfoKey: @(12345) }]; + + NSException *caughtException = nil; + @try { + NSArray __unused *identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + } + @catch (NSException *exception) { + caughtException = exception; + } + @finally { + expect([caughtException name]).to.equal(NSInvalidArgumentException); + expect([caughtException reason]).to.equal(@"Invalid value given in user info key 'RKEntityIdentificationAttributes' of entity 'Monkey': expected an `NSString` or `NSArray` of strings, instead got '12345' (__NSCFNumber)"); + } +} + +- (void)testEntityIdentifierInferenceFromUserInfoKeyRaisesErrorForNonexistantAttributeName +{ + NSEntityDescription *entity = [[NSEntityDescription alloc] init]; + [entity setName:@"Monkey"]; + NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; + [identifierAttribute setName:@"monkeyID"]; + [entity setProperties:@[ identifierAttribute ]]; + [entity setUserInfo:@{ RKEntityIdentificationAttributesUserInfoKey: @"nonExistant" }]; + + NSException *caughtException = nil; + @try { + NSArray __unused *identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + } + @catch (NSException *exception) { + caughtException = exception; + } + @finally { + expect([caughtException name]).to.equal(NSInvalidArgumentException); + expect([caughtException reason]).to.equal(@"Invalid identifier attribute specified in user info key 'RKEntityIdentificationAttributes' of entity 'Monkey': no attribue was found with the name 'nonExistant'"); + } } @end diff --git a/Tests/Logic/CoreData/RKFetchRequestMappingCacheTest.m b/Tests/Logic/CoreData/RKFetchRequestMappingCacheTest.m index 3cc6ee84b5..7fa83b48e6 100644 --- a/Tests/Logic/CoreData/RKFetchRequestMappingCacheTest.m +++ b/Tests/Logic/CoreData/RKFetchRequestMappingCacheTest.m @@ -23,7 +23,7 @@ - (void)testFetchRequestMappingCacheReturnsObjectsWithNumericPrimaryKey RKFetchRequestManagedObjectCache *cache = [RKFetchRequestManagedObjectCache new]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Cat" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"railsID" ]; RKCat *reginald = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; reginald.name = @"Reginald"; @@ -44,7 +44,7 @@ - (void)testFetchRequestMappingCacheReturnsObjectsWithStringPrimaryKey RKFetchRequestManagedObjectCache *cache = [RKFetchRequestManagedObjectCache new]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Event" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Event" attributes:@[ @"eventID" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"eventID" ]; RKEvent *birthday = [NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; birthday.eventID = @"e-1234-a8-b12"; diff --git a/Tests/Logic/CoreData/RKManagedObjectLoaderTest.m b/Tests/Logic/CoreData/RKManagedObjectLoaderTest.m index d57b9e5d43..30be779024 100644 --- a/Tests/Logic/CoreData/RKManagedObjectLoaderTest.m +++ b/Tests/Logic/CoreData/RKManagedObjectLoaderTest.m @@ -96,7 +96,7 @@ - (void)testShouldDeleteObjectsMissingFromPayloadReturnedByObjectCache inManagedObjectStore:managedObjectStore]; [humanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"railsID"]]; [humanMapping addAttributeMappingsFromArray:@[@"name"]]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; humanMapping.rootKeyPath = @"human"; // Create 3 objects, we will expect 2 after the load @@ -167,7 +167,7 @@ - (void)testShouldSkipObjectMappingOnRequestCacheHitWhenObjectCachePresent RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; [humanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"railsID"]]; [humanMapping addAttributeMappingsFromArray:@[@"name"]]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; humanMapping.rootKeyPath = @"human"; NSError *error; diff --git a/Tests/Logic/CoreData/RKManagedObjectMappingOperationDataSourceTest.m b/Tests/Logic/CoreData/RKManagedObjectMappingOperationDataSourceTest.m index b2a4ab6d08..a8747b8efb 100644 --- a/Tests/Logic/CoreData/RKManagedObjectMappingOperationDataSourceTest.m +++ b/Tests/Logic/CoreData/RKManagedObjectMappingOperationDataSourceTest.m @@ -47,7 +47,7 @@ - (void)testShouldCreateNewManagedObjectInstancesWhenThereIsNoPrimaryKeyInTheDat RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext cache:managedObjectStore.managedObjectCache]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"railsID" ]; NSDictionary *data = [NSDictionary dictionary]; id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping]; @@ -74,7 +74,7 @@ - (void)testShouldCreateANewManagedObjectWhenThePrimaryKeyValueIsNSNull RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext cache:managedObjectStore.managedObjectCache]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"railsID" ]; [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"railsID"]]; NSDictionary *data = [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"id"]; @@ -90,7 +90,7 @@ - (void)testShouldFindExistingManagedObjectsByPrimaryKeyWithFetchedResultsCache RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"railsID" ]; [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"railsID"]]; RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; @@ -115,7 +115,7 @@ - (void)testShouldFindExistingManagedObjectsByPrimaryKeyPathWithFetchedResultsCa RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"railsID" ]; [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"monkey.id" toKeyPath:@"railsID"]]; RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; @@ -142,7 +142,7 @@ - (void)testUsingDateAsIdentifierAttributeWithFetchRequestCache RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"createdAt" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"createdAt" ]; [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"monkey.created_at" toKeyPath:@"createdAt"]]; NSString *createdAtString = @"2012-03-22T11:05:42Z"; @@ -171,7 +171,7 @@ - (void)testShouldFindExistingManagedObjectsByPrimaryKeyWithInMemoryCache RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"railsID" ]; [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"railsID"]]; RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; @@ -198,7 +198,7 @@ - (void)testShouldFindExistingManagedObjectsByPrimaryKeyPathWithInMemoryCache RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"railsID" ]; [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"monkey.id" toKeyPath:@"railsID"]]; RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; @@ -226,7 +226,7 @@ - (void)testUsingDateAsIdentifierAttributeWithInMemoryCache RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"createdAt" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"createdAt" ]; [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"monkey.created_at" toKeyPath:@"createdAt"]]; NSString *createdAtString = @"2012-03-22T11:05:42Z"; @@ -254,7 +254,7 @@ - (void)testThatCreationOfNewObjectWithIncorrectTypeValueForPrimaryKeyAddsToCach managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; RKEntityMapping *mapping = [[RKEntityMapping alloc] initWithEntity:entity]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"railsID" ]; [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"monkey.name" toKeyPath:@"name"]]; [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"monkey.railsID" toKeyPath:@"railsID"]]; @@ -306,7 +306,7 @@ - (void)testCompoundEntityIdentifierWithFetchRequestCache RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID", @"name", @"createdAt" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"railsID", @"name", @"createdAt" ]; [mapping addAttributeMappingsFromDictionary:@{ @"monkey.id": @"railsID", @"monkey.name": @"name", @"monkey.created_at": @"createdAt" }]; NSString *createdAtString = @"2012-03-22T11:05:42Z"; @@ -337,7 +337,7 @@ - (void)testCompoundEntityIdentifierWithInMemoryCache RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID", @"name", @"createdAt" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"railsID", @"name", @"createdAt" ]; [mapping addAttributeMappingsFromDictionary:@{ @"monkey.id": @"railsID", @"monkey.name": @"name", @"monkey.created_at": @"createdAt" }]; NSString *createdAtString = @"2012-03-22T11:05:42Z"; @@ -368,7 +368,7 @@ - (void)testRetrievalOfTargetObjectInWhichIdentifierAttributeIsDynamicNestingKey RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"name" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"name" ]; [mapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"name"]; [mapping addAttributeMappingsFromDictionary:@{ @"(name).id": @"railsID" }]; @@ -395,7 +395,7 @@ - (void)testRetrievalOfTargetObjectInWhichIdentifierAttributeIsCompoundAndOneAtt RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"name", @"railsID" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"name", @"railsID" ]; [mapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"name"]; [mapping addAttributeMappingsFromDictionary:@{ @"(name).id": @"railsID" }]; @@ -422,7 +422,7 @@ - (void)testRetrievalOfTargetObjectInWhichIdentifierAttributeIsCompoundAndOneAtt RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID", @"name" ] inManagedObjectStore:managedObjectStore]; + mapping.identificationAttributes = @[ @"railsID", @"name" ]; [mapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"name"]; [mapping addAttributeMappingsFromDictionary:@{ @"(name).id": @"railsID" }]; @@ -449,8 +449,8 @@ - (void)testEntityIdentifierWithPredicate RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new]; RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; - mapping.entityIdentifier.predicate = [NSPredicate predicateWithFormat:@"age < 30"]; + mapping.identificationAttributes = @[ @"railsID" ]; + mapping.identificationPredicate = [NSPredicate predicateWithFormat:@"age < 30"]; [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"railsID"]]; // Create two humans matching the identifier, but differ in matching the diff --git a/Tests/Logic/CoreData/RKManagedObjectMappingOperationTest.m b/Tests/Logic/CoreData/RKManagedObjectMappingOperationTest.m index e3328fec9e..c3be3f2264 100644 --- a/Tests/Logic/CoreData/RKManagedObjectMappingOperationTest.m +++ b/Tests/Logic/CoreData/RKManagedObjectMappingOperationTest.m @@ -57,7 +57,7 @@ - (void)testMappingInPrivateQueue NSDictionary *sourceObject = @{ @"name" : @"Blake Watters" }; [managedObjectContext performBlockAndWait:^{ RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectContext]; RKHuman *human = [[RKHuman alloc] initWithEntity:entity insertIntoManagedObjectContext:managedObjectContext]; @@ -76,11 +76,11 @@ - (void)testShouldConnectRelationshipsByPrimaryKey RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; [humanMapping connectRelationship:@"favoriteCat" fromKeyPath:@"favoriteCatID" toKeyPath:@"railsID" withMapping:catMapping]; @@ -110,11 +110,11 @@ - (void)testShouldConnectRelationshipsByPrimaryKeyReverse NSManagedObjectContext *managedObjectContext = managedObjectStore.persistentStoreManagedObjectContextContext; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name", @"railsID"]]; [catMapping connectRelationship:@"favoriteOfHumans" fromKeyPath:@"railsID" toKeyPath:@"favoriteCatID" withMapping:humanMapping]; @@ -158,11 +158,11 @@ - (void)testConnectRelationshipsDoesNotLeakMemory RKManagedObjectStore* managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; [humanMapping connectRelationship:@"favoriteCat" fromKeyPath:@"favoriteCatID" toKeyPath:@"railsID" withMapping:catMapping]; @@ -191,11 +191,11 @@ - (void)testConnectionOfHasManyRelationshipsByPrimaryKey RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; [humanMapping connectRelationship:@"favoriteCat" fromKeyPath:@"favoriteCatID" toKeyPath:@"railsID" withMapping:catMapping]; @@ -224,11 +224,11 @@ - (void)testShouldConnectRelationshipsByPrimaryKeyWithDifferentSourceAndDestinat RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"catIDs"]]; [humanMapping connectRelationship:@"cats" fromKeyPath:@"catIDs" toKeyPath:@"railsID" withMapping:catMapping]; @@ -265,11 +265,11 @@ - (void)testShouldConnectRelationshipsByPrimaryKeyWithDifferentSourceAndDestinat RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"railsID"]]; RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name", @"humanId"]]; [catMapping connectRelationship:@"human" fromKeyPath:@"humanId" toKeyPath:@"railsID" withMapping:humanMapping]; @@ -297,11 +297,11 @@ - (void)testShouldLoadNestedHasManyRelationship { RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; [humanMapping hasMany:@"cats" withMapping:catMapping]; @@ -322,11 +322,11 @@ - (void)testShouldLoadOrderedHasManyRelationship { RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; [humanMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"cats" toKeyPath:@"catsInOrderByAge" withMapping:catMapping]];; @@ -396,11 +396,11 @@ - (void)testShouldDynamicallyConnectRelationshipsByPrimaryKeyWhenMatchingSucceed RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; [humanMapping connectRelationship:@"favoriteCat" fromKeyPath:@"favoriteCatID" toKeyPath:@"railsID" withMapping:catMapping whenValueOfKeyPath:@"name" isEqualTo:@"Blake"]; @@ -429,11 +429,11 @@ - (void)testShouldNotDynamicallyConnectRelationshipsByPrimaryKeyWhenMatchingFail RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; [humanMapping connectRelationship:@"favoriteCat" fromKeyPath:@"favoriteCatID" toKeyPath:@"railsID" withMapping:catMapping whenValueOfKeyPath:@"name" isEqualTo:@"Jeff"]; @@ -460,11 +460,11 @@ - (void)testShouldConnectManyToManyRelationships { RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping *childMapping = [RKEntityMapping mappingForEntityForName:@"Child" inManagedObjectStore:managedObjectStore]; - childmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + childmapping.identificationAttributes = @[ @"railsID" ]; [childMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping *parentMapping = [RKEntityMapping mappingForEntityForName:@"Parent" inManagedObjectStore:managedObjectStore]; - parentmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + parentmapping.identificationAttributes = @[ @"railsID" ]; [parentMapping addAttributeMappingsFromArray:@[@"name", @"age"]]; [parentMapping hasMany:@"children" withMapping:childMapping]; @@ -698,11 +698,11 @@ - (void)testShouldConnectRelationshipsByPrimaryKeyDeprecated { RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping* catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping* humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; [humanMapping hasOne:@"favoriteCat" withMapping:catMapping]; [humanMapping connectRelationship:@"favoriteCat" withObjectForPrimaryKeyAttribute:@"favoriteCatID"]; @@ -731,11 +731,11 @@ - (void)testConnectRelationshipsDoesNotLeakMemoryDeprecated { RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping* catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping* humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; [humanMapping hasOne:@"favoriteCat" withMapping:catMapping]; [humanMapping connectRelationship:@"favoriteCat" withObjectForPrimaryKeyAttribute:@"favoriteCatID"]; @@ -764,11 +764,11 @@ - (void)testConnectionOfHasManyRelationshipsByPrimaryKeyDeprecated { RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping* catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping* humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; [humanMapping hasOne:@"favoriteCat" withMapping:catMapping]; [humanMapping connectRelationship:@"favoriteCat" withObjectForPrimaryKeyAttribute:@"favoriteCatID"]; @@ -797,11 +797,11 @@ - (void)testShouldConnectRelationshipsByPrimaryKeyWithDifferentSourceAndDestinat RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping* catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping* humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID", @"catIDs"]]; [humanMapping mapRelationship:@"cats" withMapping:catMapping]; [humanMapping connectRelationship:@"cats" withObjectForPrimaryKeyAttribute:@"catIDs"]; @@ -837,11 +837,11 @@ - (void)testShouldDynamicallyConnectRelationshipsByPrimaryKeyWhenMatchingSucceed RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping* catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping* humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; [humanMapping hasOne:@"favoriteCat" withMapping:catMapping]; [humanMapping connectRelationship:@"favoriteCat" withObjectForPrimaryKeyAttribute:@"favoriteCatID" whenValueOfKeyPath:@"name" isEqualTo:@"Blake"]; @@ -870,11 +870,11 @@ - (void)testShouldNotDynamicallyConnectRelationshipsByPrimaryKeyWhenMatchingFail RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping* catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; - catmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + catmapping.identificationAttributes = @[ @"railsID" ]; [catMapping addAttributeMappingsFromArray:@[@"name"]]; RKEntityMapping* humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; - humanmapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanmapping.identificationAttributes = @[ @"railsID" ]; [humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]]; [humanMapping hasOne:@"favoriteCat" withMapping:catMapping]; [humanMapping connectRelationship:@"favoriteCat" withObjectForPrimaryKeyAttribute:@"favoriteCatID" whenValueOfKeyPath:@"name" isEqualTo:@"Jeff"]; diff --git a/Tests/Logic/ObjectMapping/RKObjectMappingNextGenTest.m b/Tests/Logic/ObjectMapping/RKObjectMappingNextGenTest.m index 686c67755b..37664773ac 100644 --- a/Tests/Logic/ObjectMapping/RKObjectMappingNextGenTest.m +++ b/Tests/Logic/ObjectMapping/RKObjectMappingNextGenTest.m @@ -2037,7 +2037,7 @@ - (void)testUpdatingArrayOfExistingCats NSArray *array = [RKTestFixture parsedObjectWithContentsOfFixture:@"ArrayOfHumans.json"]; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; [humanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"railsID"]]; - humanMapping.entityIdentifier = [RKEntityIdentifier identifierWithEntityName:@"Human" attributes:@[ @"railsID" ] inManagedObjectStore:managedObjectStore]; + humanMapping.identificationAttributes = @[ @"railsID" ]; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:humanMapping forKey:@"human"]; From a5dc037ef9ed8dc7c04de6c7eed903eefe4b0de9 Mon Sep 17 00:00:00 2001 From: Blake Watters Date: Sun, 2 Dec 2012 14:34:03 -0500 Subject: [PATCH 10/11] Add support for inferring attributes that match the snake-case _id pattern. closes #1047 --- Code/CoreData/RKEntityMapping.h | 2 +- Code/CoreData/RKEntityMapping.m | 22 +++++++++--- Tests/Logic/CoreData/RKEntityMappingTest.m | 41 ++++++++++++++++++++-- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/Code/CoreData/RKEntityMapping.h b/Code/CoreData/RKEntityMapping.h index f896d1a8ff..e7a2f57529 100644 --- a/Code/CoreData/RKEntityMapping.h +++ b/Code/CoreData/RKEntityMapping.h @@ -38,7 +38,7 @@ When `RKIdentificationAttributesInferredFromEntity` is invoked, the entity is first checked for a user info key specifying the identifying attributes. If the user info of the given entity contains a value for the key 'RKEntityIdentificationAttributes', then that value is used to construct an array of attributes. The user info key must contain a string or an array of strings specifying the names of attributes that exist in the given entity. - If no attributes are specified in the user info, then the entity is searched for an attribute whose name matches the llama-cased name of the entity. For example, an entity named 'Article' would have an inferred identifier attribute of 'articleID' and an entity named 'ApprovedComment' would be inferred as 'approvedCommentID'. If such an attribute is found within the entity, an array is returned containing the attribute. If none is returned, the the attributes are searched for the following names: + If no attributes are specified in the user info, then the entity is searched for an attribute whose name matches the llama-cased or snake-cased name of the entity. For example, an entity named 'Article' would have an inferred identifying attributes of 'articleID' and 'article_id', and an entity named 'ApprovedComment' would be inferred as 'approvedCommentID' and 'approved_comment_id'. If such an attribute is found within the entity, an array is returned containing the attribute. If none is returned, the the attributes are searched for the following names: 1. 'identifier' 1. 'id' diff --git a/Code/CoreData/RKEntityMapping.m b/Code/CoreData/RKEntityMapping.m index 78d5e56bfb..c88b41a762 100644 --- a/Code/CoreData/RKEntityMapping.m +++ b/Code/CoreData/RKEntityMapping.m @@ -58,12 +58,26 @@ return nil; } -// Given 'Human', returns 'humanID'; Given 'AmenityReview' returns 'amenityReviewID' -static NSString *RKEntityIdentificationAttributeNameForEntity(NSEntityDescription *entity) +static NSString *RKUnderscoredStringFromCamelCasedString(NSString *camelCasedString) +{ + NSError *error = nil; + NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:@"((^[a-z]+)|([A-Z]{1}[a-z]+)|([A-Z]+(?=([A-Z][a-z])|($))))" options:0 error:&error]; + if (! regularExpression) return nil; + NSMutableArray *lowercasedComponents = [NSMutableArray array]; + [regularExpression enumerateMatchesInString:camelCasedString options:0 range:NSMakeRange(0, [camelCasedString length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { + [lowercasedComponents addObject:[[camelCasedString substringWithRange:[result range]] lowercaseString]]; + }]; + return [lowercasedComponents componentsJoinedByString:@"_"]; +} + +// Given 'Human', returns 'humanID' and 'human_id'; Given 'AmenityReview' returns 'amenityReviewID' and 'amenity_review_id' +static NSArray *RKEntityIdentificationAttributeNamesForEntity(NSEntityDescription *entity) { NSString *entityName = [entity name]; NSString *lowerCasedFirstCharacter = [[entityName substringToIndex:1] lowercaseString]; - return [NSString stringWithFormat:@"%@%@ID", lowerCasedFirstCharacter, [entityName substringFromIndex:1]]; + NSString *camelizedIDAttributeName = [NSString stringWithFormat:@"%@%@ID", lowerCasedFirstCharacter, [entityName substringFromIndex:1]]; + NSString *underscoredIDAttributeName = [NSString stringWithFormat:@"%@_id", RKUnderscoredStringFromCamelCasedString([entity name])]; + return @[ camelizedIDAttributeName, underscoredIDAttributeName ]; } static NSArray *RKEntityIdentificationAttributeNames() @@ -97,7 +111,7 @@ return RKArrayOfAttributesForEntityFromAttributesOrNames(entity, attributes); } - NSMutableArray *identifyingAttributes = [NSMutableArray arrayWithObject:RKEntityIdentificationAttributeNameForEntity(entity)]; + NSMutableArray *identifyingAttributes = [RKEntityIdentificationAttributeNamesForEntity(entity) mutableCopy]; [identifyingAttributes addObjectsFromArray:RKEntityIdentificationAttributeNames()]; for (NSString *attributeName in identifyingAttributes) { NSAttributeDescription *attribute = [entity attributesByName][attributeName]; diff --git a/Tests/Logic/CoreData/RKEntityMappingTest.m b/Tests/Logic/CoreData/RKEntityMappingTest.m index 2576bbd1df..3fc2b9bd0d 100644 --- a/Tests/Logic/CoreData/RKEntityMappingTest.m +++ b/Tests/Logic/CoreData/RKEntityMappingTest.m @@ -322,8 +322,6 @@ - (void)testThatInitEntityIdentifierWithEmptyAttributesRaisesException #pragma mark - Entity Identifier Inference -// TODO: The attributes to auto-detect: entityNameID, ID, identififer, url, URL - - (void)testEntityIdentifierInferenceForEntityWithLlamaCasedIDAttribute { NSEntityDescription *entity = [[NSEntityDescription alloc] init]; @@ -467,4 +465,43 @@ - (void)testEntityIdentifierInferenceFromUserInfoKeyRaisesErrorForNonexistantAtt } } +- (void)testInferenceOfSnakeCasedEntityName +{ + NSEntityDescription *entity = [[NSEntityDescription alloc] init]; + [entity setName:@"Monkey"]; + NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; + [identifierAttribute setName:@"monkey_id"]; + [entity setProperties:@[ identifierAttribute ]]; + NSArray *identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + expect(identificationAttributes).notTo.beNil(); + NSArray *attributeNames = @[ @"monkey_id" ]; + expect([identificationAttributes valueForKey:@"name"]).to.equal(attributeNames); +} + +- (void)testInferenceOfCompoundSnakeCasedEntityName +{ + NSEntityDescription *entity = [[NSEntityDescription alloc] init]; + [entity setName:@"ArcticMonkey"]; + NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; + [identifierAttribute setName:@"arctic_monkey_id"]; + [entity setProperties:@[ identifierAttribute ]]; + NSArray *identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + expect(identificationAttributes).notTo.beNil(); + NSArray *attributeNames = @[ @"arctic_monkey_id" ]; + expect([identificationAttributes valueForKey:@"name"]).to.equal(attributeNames); +} + +- (void)testInferenceOfSnakeCasedEntityNameWithAbbreviation +{ + NSEntityDescription *entity = [[NSEntityDescription alloc] init]; + [entity setName:@"ArcticMonkeyURL"]; + NSAttributeDescription *identifierAttribute = [NSAttributeDescription new]; + [identifierAttribute setName:@"arctic_monkey_url_id"]; + [entity setProperties:@[ identifierAttribute ]]; + NSArray *identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + expect(identificationAttributes).notTo.beNil(); + NSArray *attributeNames = @[ @"arctic_monkey_url_id" ]; + expect([identificationAttributes valueForKey:@"name"]).to.equal(attributeNames); +} + @end From 971083eacdc25fedc3b828f3f47180969aa50e03 Mon Sep 17 00:00:00 2001 From: Blake Watters Date: Sun, 2 Dec 2012 14:34:17 -0500 Subject: [PATCH 11/11] Bump ersion to pre2 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 96b451037e..e7ee464d27 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.20.0-pre1 \ No newline at end of file +0.20.0-pre2 \ No newline at end of file