Don't create unnecessary objects when mapping temporary managed objects POST'd without identification attributes. closes #1149

This commit is contained in:
Blake Watters
2013-01-15 22:45:43 -05:00
parent bf521310b2
commit 868d83be2c
8 changed files with 152 additions and 31 deletions

View File

@@ -210,7 +210,7 @@ extern NSString * const RKObjectMappingNestingAttributeKeyName;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRepresentation:(NSDictionary *)representation withMapping:(RKObjectMapping *)mapping
- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRepresentation:(NSDictionary *)representation withMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationship
{
NSAssert(representation, @"Mappable data cannot be nil");
NSAssert(self.managedObjectContext, @"%@ must be initialized with a managed object context.", [self class]);
@@ -219,16 +219,36 @@ extern NSString * const RKObjectMappingNestingAttributeKeyName;
return [mapping.objectClass new];
}
RKEntityMapping *entityMapping = (RKEntityMapping *)mapping;
RKEntityMapping *entityMapping = (RKEntityMapping *)mapping;
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 identification attributes. Duplicate objects may be created.");
}
// If we have found the entity identification attributes, try to find an existing instance to update
NSEntityDescription *entity = [entityMapping entity];
NSManagedObject *managedObject = nil;
// If we are mapping within a relationship, try to find an existing object without identifying attributes
if (relationship) {
id existingObjects = [mappingOperation.destinationObject valueForKeyPath:relationship.destinationKeyPath];
if (existingObjects && ![existingObjects respondsToSelector:@selector(count)]) existingObjects = @[ existingObjects ];
NSArray *identificationAttributes = [entityMapping.identificationAttributes valueForKey:@"name"];
for (NSManagedObject *existingObject in existingObjects) {
if (! identificationAttributes) {
managedObject = existingObject;
break;
}
NSDictionary *identificationAttributeValues = [existingObject dictionaryWithValuesForKeys:identificationAttributes];
if ([[NSSet setWithArray:[identificationAttributeValues allValues]] isEqualToSet:[NSSet setWithObject:[NSNull null]]]) {
managedObject = existingObject;
break;
}
}
}
// If we have found the entity identification attributes, try to find an existing instance to update
if ([entityIdentifierAttributes count]) {
NSSet *objects = [self.managedObjectCache managedObjectsWithEntity:entity
attributeValues:entityIdentifierAttributes

View File

@@ -271,7 +271,7 @@ static NSString *RKFailureReasonErrorStringForMappingNotFoundError(id representa
}
if (objectMapping) {
return [self.mappingOperationDataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:objectMapping];
return [self.mappingOperationDataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:objectMapping inRelationship:nil];
}
return nil;

View File

@@ -233,7 +233,7 @@ static BOOL RKObjectContainsValueForKeyPaths(id representation, NSArray *keyPath
return self;
}
- (id)destinationObjectForMappingRepresentation:(id)representation withMapping:(RKMapping *)mapping
- (id)destinationObjectForMappingRepresentation:(id)representation withMapping:(RKMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping
{
RKObjectMapping *concreteMapping = nil;
if ([mapping isKindOfClass:[RKDynamicMapping class]]) {
@@ -246,7 +246,7 @@ static BOOL RKObjectContainsValueForKeyPaths(id representation, NSArray *keyPath
concreteMapping = (RKObjectMapping *)mapping;
}
return [self.dataSource mappingOperation:self targetObjectForRepresentation:representation withMapping:concreteMapping];
return [self.dataSource mappingOperation:self targetObjectForRepresentation:representation withMapping:concreteMapping inRelationship:relationshipMapping];
}
- (NSDate *)parseDateFromString:(NSString *)string
@@ -498,7 +498,7 @@ static BOOL RKObjectContainsValueForKeyPaths(id representation, NSArray *keyPath
return NO;
}
id destinationObject = [self destinationObjectForMappingRepresentation:value withMapping:relationshipMapping.mapping];
id destinationObject = [self destinationObjectForMappingRepresentation:value withMapping:relationshipMapping.mapping inRelationship:relationshipMapping];
if (! destinationObject) {
RKLogDebug(@"Mapping %@ declined mapping for representation %@: returned `nil` destination object.", relationshipMapping.mapping, destinationObject);
return NO;
@@ -562,7 +562,7 @@ static BOOL RKObjectContainsValueForKeyPaths(id representation, NSArray *keyPath
}
for (id nestedObject in value) {
id mappableObject = [self destinationObjectForMappingRepresentation:nestedObject withMapping:relationshipMapping.mapping];
id mappableObject = [self destinationObjectForMappingRepresentation:nestedObject withMapping:relationshipMapping.mapping inRelationship:relationshipMapping];
if (! mappableObject) {
RKLogDebug(@"Mapping %@ declined mapping for representation %@: returned `nil` destination object.", relationshipMapping.mapping, nestedObject);
continue;
@@ -755,7 +755,7 @@ static BOOL RKObjectContainsValueForKeyPaths(id representation, NSArray *keyPath
RKLogTrace(@"Performing mapping operation: %@", self);
if (! self.destinationObject) {
self.destinationObject = [self destinationObjectForMappingRepresentation:self.sourceObject withMapping:self.mapping];
self.destinationObject = [self destinationObjectForMappingRepresentation:self.sourceObject withMapping:self.mapping inRelationship:nil];
if (! self.destinationObject) {
RKLogDebug(@"Mapping operation failed: Given nil destination object and unable to instantiate a destination object for mapping.");
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Cannot perform a mapping operation with a nil destination object." };

View File

@@ -43,7 +43,7 @@
@param mapping The object mapping to be used to perform a mapping from the representation to the target object.
@return A key-value coding compliant object to perform the mapping on to.
*/
- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRepresentation:(NSDictionary *)representation withMapping:(RKObjectMapping *)mapping;
- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRepresentation:(NSDictionary *)representation withMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping;
@optional

View File

@@ -23,7 +23,8 @@
@implementation RKObjectMappingOperationDataSource
- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRepresentation:(NSDictionary *)representation withMapping:(RKObjectMapping *)mapping
- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRepresentation:(NSDictionary *)representation
withMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping
{
return [mapping.objectClass new];
}

View File

@@ -359,7 +359,6 @@
254372D915F54CE3006E8424 /* RKManagedObjectRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372D515F54CE3006E8424 /* RKManagedObjectRequestOperation.m */; };
2543A25D1664FD3100821D5B /* RKResponseDescriptorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25CC5C58161DDADD0008BD21 /* RKResponseDescriptorTest.m */; };
2543A25E1664FD3200821D5B /* RKResponseDescriptorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25CC5C58161DDADD0008BD21 /* RKResponseDescriptorTest.m */; };
2546A95816628EDD0078E044 /* RKConnectionDescriptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2546A95716628EDD0078E044 /* RKConnectionDescriptionTest.m */; };
2546A95916628EDD0078E044 /* RKConnectionDescriptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2546A95716628EDD0078E044 /* RKConnectionDescriptionTest.m */; };
2548AC6E162F5E00009E79BF /* RKManagedObjectRequestOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2548AC6C162F5E00009E79BF /* RKManagedObjectRequestOperationTest.m */; };
2549D646162B376F003DD135 /* RKRequestDescriptorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2549D645162B376F003DD135 /* RKRequestDescriptorTest.m */; };
@@ -487,6 +486,7 @@
25A8C2351673BD480014D9A6 /* RKConnectionTestExpectation.h in Headers */ = {isa = PBXBuildFile; fileRef = 25A8C2321673BD480014D9A6 /* RKConnectionTestExpectation.h */; settings = {ATTRIBUTES = (Public, ); }; };
25A8C2361673BD480014D9A6 /* RKConnectionTestExpectation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25A8C2331673BD480014D9A6 /* RKConnectionTestExpectation.m */; };
25A8C2371673BD480014D9A6 /* RKConnectionTestExpectation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25A8C2331673BD480014D9A6 /* RKConnectionTestExpectation.m */; };
25A9827516A5FF4F0088A3CA /* RKConnectionDescriptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2546A95716628EDD0078E044 /* RKConnectionDescriptionTest.m */; };
25AA23D015AF2920006EF62D /* RKManagedObjectMappingOperationDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 25AA23CF15AF291F006EF62D /* RKManagedObjectMappingOperationDataSource.m */; };
25AA23D115AF2920006EF62D /* RKManagedObjectMappingOperationDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 25AA23CF15AF291F006EF62D /* RKManagedObjectMappingOperationDataSource.m */; };
25AA23D815AF5085006EF62D /* RKManagedObjectMappingOperationDataSourceTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25AA23D315AF4F25006EF62D /* RKManagedObjectMappingOperationDataSourceTest.m */; };
@@ -2318,13 +2318,13 @@
2549D646162B376F003DD135 /* RKRequestDescriptorTest.m in Sources */,
2506759F162DEA25003210B0 /* RKEntityMappingTest.m in Sources */,
255F87911656B22D00914D57 /* RKPaginatorTest.m in Sources */,
2546A95816628EDD0078E044 /* RKConnectionDescriptionTest.m in Sources */,
2543A25D1664FD3100821D5B /* RKResponseDescriptorTest.m in Sources */,
2536D1FD167270F100DF9BB0 /* RKRouterTest.m in Sources */,
2551338F167838590017E4B6 /* RKHTTPRequestOperationTest.m in Sources */,
255133CF167AC7600017E4B6 /* RKManagedObjectRequestOperationTest.m in Sources */,
25B639CC16961EFA0065EB7B /* RKMappingTestTest.m in Sources */,
25A73362169C8C230090A930 /* VersionedModel.xcdatamodeld in Sources */,
25A9827516A5FF4F0088A3CA /* RKConnectionDescriptionTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -41,7 +41,7 @@
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKMappableObject class]];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:[NSDictionary dictionary] withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:[NSDictionary dictionary] withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat([object class], is(equalTo([RKMappableObject class])));
}
@@ -55,7 +55,7 @@
mapping.identificationAttributes = @[ @"railsID" ];
NSDictionary *data = [NSDictionary dictionary];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(instanceOf([RKHuman class])));
}
@@ -68,7 +68,7 @@
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
NSDictionary *data = [NSDictionary dictionary];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(instanceOf([RKHuman class])));
}
@@ -83,7 +83,7 @@
[mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"railsID"]];
NSDictionary *data = [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"id"];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(instanceOf([RKHuman class])));
}
@@ -110,7 +110,7 @@
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
NSDictionary *data = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:123] forKey:@"id"];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
@@ -137,7 +137,7 @@
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:nestedDictionary withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:nestedDictionary withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
@@ -164,7 +164,7 @@
NSDictionary *representation = @{ @"monkey": @{ @"created_at": createdAtString } };
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
@@ -192,7 +192,7 @@
NSDictionary *data = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:123] forKey:@"id"];
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
NSManagedObject *object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping];
NSManagedObject *object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping inRelationship:nil];
expect([object managedObjectContext]).to.equal(managedObjectStore.persistentStoreManagedObjectContext);
expect(object).notTo.beNil();
expect(object).to.equal(human);
@@ -221,7 +221,7 @@
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:nestedDictionary withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:nestedDictionary withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(equalTo(human)));
}
@@ -248,7 +248,7 @@
NSDictionary *representation = @{ @"monkey": @{ @"created_at": createdAtString } };
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
@@ -279,7 +279,7 @@
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
RKHuman *object = [dataSource mappingOperation:nil targetObjectForRepresentation:nestedDictionary withMapping:mapping];
RKHuman *object = [dataSource mappingOperation:nil targetObjectForRepresentation:nestedDictionary withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(equalTo(human)));
assertThatInteger([object.railsID integerValue], is(equalToInteger(12345)));
@@ -333,7 +333,7 @@
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(equalTo(human)));
}
@@ -364,7 +364,7 @@
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(equalTo(human)));
}
@@ -391,7 +391,7 @@
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
NSDictionary *representation = @{ @"Blake": @{ @"id": @"12345" } };
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
@@ -418,7 +418,7 @@
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
NSDictionary *representation = @{ @"Blake": @{ @"id": @"12345" } };
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
@@ -445,7 +445,7 @@
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
NSDictionary *representation = @{ @"Blake": @{ @"id": @"12345" } };
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
@@ -479,7 +479,7 @@
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
NSDictionary *data = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:123] forKey:@"id"];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human1);
}

View File

@@ -1005,4 +1005,104 @@
expect(user.name).to.equal(@"Blake");
}
- (void)testPostingTemporaryObjectThatDoesNotExistInCacheDoesNotCreateDuplicatesWithFetchRequestCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
managedObjectStore.managedObjectCache = managedObjectCache;
NSEntityDescription *entity = [managedObjectStore.managedObjectModel entitiesByName][@"Human"];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
entityMapping.identificationAttributes = @[ @"railsID" ];
[entityMapping addAttributeMappingsFromDictionary:@{ @"id": @"railsID", @"name": @"name" }];
NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[childContext setParentContext:managedObjectStore.mainQueueManagedObjectContext];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:childContext];
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
objectManager.managedObjectStore = managedObjectStore;
[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:@"/humans" keyPath:@"human" statusCodes:[NSIndexSet indexSetWithIndex:201]]];
__block RKMappingResult *mappingResult = nil;
[objectManager postObject:human path:@"/humans" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *blockMappingResult) {
mappingResult = blockMappingResult;
} failure:nil];
expect(mappingResult).willNot.beNil();
expect([[human objectID] isTemporaryID]).to.beFalsy();
NSSet *managedObjects = [managedObjectCache managedObjectsWithEntity:entity attributeValues:@{ @"railsID": @(1) } inManagedObjectContext:childContext];
expect(managedObjects).to.haveCountOf(1);
[objectManager postObject:human path:@"/humans" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *blockMappingResult) {
mappingResult = blockMappingResult;
} failure:nil];
expect(mappingResult).willNot.beNil();
managedObjects = [managedObjectCache managedObjectsWithEntity:entity attributeValues:@{ @"railsID": @(1) } inManagedObjectContext:childContext];
expect(managedObjects).to.haveCountOf(1);
}
- (void)testPostingTemporaryObjectWithChildObjectsThatDoesNotExistInCacheDoesNotCreateDuplicatesWithFetchRequestCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
managedObjectStore.managedObjectCache = managedObjectCache;
NSManagedObject *developmentTag = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext];
[developmentTag setValue:@"development" forKey:@"name"];
NSManagedObject *restkitTag = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext];
[restkitTag setValue:@"restkit" forKey:@"name"];
NSManagedObject *post = [NSEntityDescription insertNewObjectForEntityForName:@"Post" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext];
[post setValue:@"Post Title" forKey:@"title"];
[post setValue:[NSSet setWithObjects:developmentTag, restkitTag, nil] forKey:@"tags"];
RKEntityMapping *postMapping = [RKEntityMapping mappingForEntityForName:@"Post" inManagedObjectStore:managedObjectStore];
postMapping.identificationAttributes = @[ @"title" ];
[postMapping addAttributeMappingsFromArray:@[ @"title", @"body" ]];
RKEntityMapping *tagMapping = [RKEntityMapping mappingForEntityForName:@"Tag" inManagedObjectStore:managedObjectStore];
[tagMapping addAttributeMappingsFromArray:@[ @"name" ]];
RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"tags" toKeyPath:@"tags" withMapping:tagMapping];
[postMapping addPropertyMapping:relationshipMapping];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:postMapping pathPattern:nil keyPath:@"post" statusCodes:[NSIndexSet indexSetWithIndex:200]];
RKObjectMapping *tagRequestMapping = [RKObjectMapping requestMapping];
[tagRequestMapping addAttributeMappingsFromArray:@[ @"name" ]];
RKObjectMapping *postRequestMapping = [RKObjectMapping requestMapping];
[postRequestMapping addAttributeMappingsFromArray:@[ @"title", @"body" ]];
[postRequestMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"tags" toKeyPath:@"tags" withMapping:tagRequestMapping]];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:postRequestMapping objectClass:[NSManagedObject class] rootKeyPath:nil];
RKObjectManager *objectManager = [RKTestFactory objectManager];
objectManager.managedObjectStore = managedObjectStore;
[objectManager addResponseDescriptor:responseDescriptor];
[objectManager addRequestDescriptor:requestDescriptor];
expect([post isNew]).to.equal(YES);
expect([post.objectID isTemporaryID]).to.equal(YES);
expect([developmentTag isNew]).to.equal(YES);
expect([developmentTag.objectID isTemporaryID]).to.equal(YES);
expect([restkitTag isNew]).to.equal(YES);
expect([restkitTag.objectID isTemporaryID]).to.equal(YES);
__block RKMappingResult *postMappingResult = nil;
RKManagedObjectRequestOperation *operation = [objectManager appropriateObjectRequestOperationWithObject:post method:RKRequestMethodPOST path:@"/posts.json" parameters:nil];
operation.savesToPersistentStore = NO;
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
postMappingResult = mappingResult;
} failure:nil];
[objectManager enqueueObjectRequestOperation:operation];
expect(postMappingResult).willNot.beNil();
expect([post.objectID isTemporaryID]).will.equal(NO);
expect([developmentTag.objectID isTemporaryID]).will.equal(NO);
expect([restkitTag.objectID isTemporaryID]).will.equal(NO);
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Tag"];
NSUInteger tagsCount = [objectManager.managedObjectStore.mainQueueManagedObjectContext countForFetchRequest:fetchRequest error:nil];
expect(tagsCount).to.equal(2);
}
@end