Files
RestKit/Tests/Logic/CoreData/RKManagedObjectMappingOperationDataSourceTest.m

1398 lines
93 KiB
Objective-C

//
// RKManagedObjectMappingOperationDataSourceTest.m
// RestKit
//
// Created by Blake Watters on 7/12/12.
// Copyright (c) 2012 RestKit. All rights reserved.
//
#import "RKTestEnvironment.h"
#import "RKEntityCache.h"
#import "RKEntityByAttributeCache.h"
#import "RKHuman.h"
#import "RKManagedObjectMappingOperationDataSource.h"
#import "RKMappableObject.h"
#import "RKMappingErrors.h"
#import "RKCat.h"
#import "RKHuman.h"
#import "RKChild.h"
#import "RKParent.h"
#import "RKBenchmark.h"
@interface RKManagedObjectMappingOperationDataSourceTest : RKTestCase
@end
/**
NOTE: You need to take care that you allow the operationQueue to finish before the next test begins execution, else the Core Data tear down can result in intermittent test crashes.
*/
@implementation RKManagedObjectMappingOperationDataSourceTest
- (void)setUp
{
[RKTestFactory setUp];
}
- (void)tearDown
{
[RKTestFactory tearDown];
}
- (void)testShouldCreateNewInstancesOfUnmanagedObjects
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
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 inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat([object class], is(equalTo([RKMappableObject class])));
}
- (void)testShouldCreateNewManagedObjectInstancesWhenThereIsNoPrimaryKeyInTheData
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"railsID" ];
NSDictionary *data = [NSDictionary dictionary];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(instanceOf([RKHuman class])));
}
- (void)testShouldCreateNewManagedObjectInstancesWhenThereIsNoPrimaryKeyAttribute
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
NSDictionary *data = [NSDictionary dictionary];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(instanceOf([RKHuman class])));
}
- (void)testShouldCreateANewManagedObjectWhenThePrimaryKeyValueIsNSNull
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"railsID" ];
[mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"railsID"]];
NSDictionary *data = [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"id"];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:data withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(instanceOf([RKHuman class])));
}
#pragma mark - Fetched Results Cache
- (void)testShouldFindExistingManagedObjectsByPrimaryKeyWithFetchedResultsCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"railsID" ];
[mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"railsID"]];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.railsID = [NSNumber numberWithInt:123];
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
expect(count).to.beGreaterThan(0);
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 inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
- (void)testShouldFindExistingManagedObjectsByPrimaryKeyPathWithFetchedResultsCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"railsID" ];
[mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"monkey.id" toKeyPath:@"railsID"]];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.railsID = [NSNumber numberWithInt:123];
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
expect(count).to.beGreaterThan(0);
NSDictionary *data = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:123] forKey:@"id"];
NSDictionary *nestedDictionary = [NSDictionary dictionaryWithObject:data forKey:@"monkey"];
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:nestedDictionary withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
- (void)testUsingDateAsIdentifierAttributeWithFetchRequestCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"createdAt" ];
[mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"monkey.created_at" toKeyPath:@"createdAt"]];
NSString *createdAtString = @"2012-03-22T11:05:42Z";
NSDate *createdAtDate = RKDateFromString(createdAtString);
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.createdAt = createdAtDate;
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
expect(count).to.beGreaterThan(0);
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 inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
#pragma mark - In Memory Cache
- (void)testShouldFindExistingManagedObjectsByPrimaryKeyWithInMemoryCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"railsID" ];
[mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"railsID"]];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.railsID = [NSNumber numberWithInt:123];
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
// Check the count
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
expect(count).to.beGreaterThan(0);
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 inRelationship:nil];
expect([object managedObjectContext]).to.equal(managedObjectStore.persistentStoreManagedObjectContext);
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
- (void)testShouldFindExistingManagedObjectsByPrimaryKeyPathWithInMemoryCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"railsID" ];
[mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"monkey.id" toKeyPath:@"railsID"]];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.railsID = [NSNumber numberWithInt:123];
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
// Check the count
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
assertThat([NSNumber numberWithInteger:count], is(greaterThan([NSNumber numberWithInteger:0])));
NSDictionary *data = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:123] forKey:@"id"];
NSDictionary *nestedDictionary = [NSDictionary dictionaryWithObject:data forKey:@"monkey"];
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:nestedDictionary withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(equalTo(human)));
}
- (void)testUsingDateAsIdentifierAttributeWithInMemoryCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"createdAt" ];
[mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"monkey.created_at" toKeyPath:@"createdAt"]];
NSString *createdAtString = @"2012-03-22T11:05:42Z";
NSDate *createdAtDate = RKDateFromString(createdAtString);
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.createdAt = createdAtDate;
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
expect(count).to.beGreaterThan(0);
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 inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
- (void)testThatCreationOfNewObjectWithIncorrectTypeValueForPrimaryKeyAddsToCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKEntityMapping *mapping = [[RKEntityMapping alloc] initWithEntity:entity];
mapping.identificationAttributes = @[ @"railsID" ];
[mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"monkey.name" toKeyPath:@"name"]];
[mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"monkey.railsID" toKeyPath:@"railsID"]];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.name = @"Testing";
human.railsID = [NSNumber numberWithInteger:12345];
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
// Check the count
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
assertThatInteger(count, is(greaterThan([NSNumber numberWithInteger:0])));
NSDictionary *data = [NSDictionary dictionaryWithObject:@"12345" forKey:@"railsID"];
NSDictionary *nestedDictionary = [NSDictionary dictionaryWithObject:data forKey:@"monkey"];
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
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)));
}
- (void)testThatMappingAnEntityMappingContainingAConnectionMappingWithANilManagedObjectCacheTriggersError
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKEntityMapping *mapping = [[RKEntityMapping alloc] initWithEntity:entity];
RKConnectionDescription *connection = [[RKConnectionDescription alloc] initWithRelationship:entity.relationshipsByName[@"favoriteCat"] attributes:@{ @"railsID": @"railsID" }];
[mapping addConnection:connection];
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:nil];
id mockOperation = [OCMockObject mockForClass:[RKMappingOperation class]];
[[mockOperation stub] destinationObject];
[[[mockOperation stub] andReturn:mapping] objectMapping];
NSError *error = nil;
BOOL success = [dataSource commitChangesForMappingOperation:mockOperation error:&error];
expect(success).to.beFalsy();
expect([error code]).to.equal(RKMappingErrorNilManagedObjectCache);
expect([error localizedDescription]).to.equal(@"Cannot map an entity mapping that contains connection mappings with a data source whose managed object cache is nil.");
}
#pragma mark - Rearrange Me
- (void)testCompoundEntityIdentifierWithFetchRequestCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" 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";
NSDate *createdAtDate = RKDateFromString(createdAtString);
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.railsID = @(12345);
human.createdAt = createdAtDate;
human.name = @"Reginald";
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
// Check the count
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
assertThat([NSNumber numberWithInteger:count], is(greaterThan([NSNumber numberWithInteger:0])));
NSDictionary *representation = @{ @"monkey": @{ @"id": @"12345", @"name": @"Reginald", @"created_at": createdAtString } };
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(equalTo(human)));
}
- (void)testCompoundEntityIdentifierWithInMemoryCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" 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";
NSDate *createdAtDate = RKDateFromString(createdAtString);
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.railsID = @(12345);
human.createdAt = createdAtDate;
human.name = @"Reginald";
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
// Check the count
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
assertThat([NSNumber numberWithInteger:count], is(greaterThan([NSNumber numberWithInteger:0])));
NSDictionary *representation = @{ @"monkey": @{ @"id": @"12345", @"name": @"Reginald", @"created_at": createdAtString } };
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
assertThat(object, isNot(nilValue()));
assertThat(object, is(equalTo(human)));
}
- (void)testRetrievalOfTargetObjectInWhichIdentifierAttributeIsDynamicNestingKey
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"name" ];
[mapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"name"];
[mapping addAttributeMappingsFromDictionary:@{ @"(name).id": @"railsID" }];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.name = @"Blake";
human.railsID = @(12345);
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
expect(count).to.beGreaterThan(0);
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
NSDictionary *representation = @{ @"Blake": @{ @"id": @"12345" } };
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
- (void)testRetrievalOfTargetObjectWithDynamicNestingKeyMappingInWhichIdentifierAttributeIsNotTheDynamicNestingKey
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"railsID" ];
[mapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"name"];
[mapping addAttributeMappingsFromDictionary:@{ @"(name).id": @"railsID" }];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.name = @"Blake";
human.railsID = @(12345);
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
expect(count).to.beGreaterThan(0);
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
NSDictionary *representation = @{ @"Blake": @{ @"id": @"12345" } };
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
- (void)testRetrievalOfTargetObjectInWhichIdentifierAttributeIsCompoundAndOneAttributeIsTheDynamicNestingKey
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"name", @"railsID" ];
[mapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"name"];
[mapping addAttributeMappingsFromDictionary:@{ @"(name).id": @"railsID" }];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.name = @"Blake";
human.railsID = @(12345);
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
expect(count).to.beGreaterThan(0);
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
NSDictionary *representation = @{ @"Blake": @{ @"id": @"12345" } };
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
- (void)testRetrievalOfTargetObjectInWhichIdentifierAttributeIsCompoundAndOneAttributeIsTheDynamicNestingKeyAndItIsNotTheFirstIdentifierAttribute
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"railsID", @"name" ];
[mapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"name"];
[mapping addAttributeMappingsFromDictionary:@{ @"(name).id": @"railsID" }];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.name = @"Blake";
human.railsID = @(12345);
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
expect(count).to.beGreaterThan(0);
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectStore.managedObjectCache];
NSDictionary *representation = @{ @"Blake": @{ @"id": @"12345" } };
id object = [dataSource mappingOperation:nil targetObjectForRepresentation:representation withMapping:mapping inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human);
}
- (void)testEntityIdentifierWithPredicate
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
managedObjectStore.managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
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
RKHuman *human1 = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human1.name = @"Colin";
human1.railsID = [NSNumber numberWithInt:123];
human1.age = @28;
RKHuman *human2 = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human2.name = @"Blake";
human2.railsID = [NSNumber numberWithInt:123];
human2.age = @30;
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
NSUInteger count = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
expect(count).to.beGreaterThan(0);
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 inRelationship:nil];
expect(object).notTo.beNil();
expect(object).to.equal(human1);
}
- (void)testMappingInPrivateQueue
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
managedObjectContext.parentContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectContext
cache:managedObjectCache];
__block BOOL success;
__block NSError *error;
NSDictionary *sourceObject = @{ @"name" : @"Blake Watters" };
[managedObjectContext performBlockAndWait:^{
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
humanMapping.identificationAttributes = @[ @"railsID" ];
[humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectContext];
RKHuman *human = [[RKHuman alloc] initWithEntity:entity insertIntoManagedObjectContext:managedObjectContext];
RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:sourceObject destinationObject:human mapping:humanMapping];
mappingOperation.dataSource = mappingOperationDataSource;
success = [mappingOperation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
assertThat(human.name, is(equalTo(@"Blake Watters")));
}];
}
- (void)testShouldConnectRelationshipsByPrimaryKey
{
/* Connect a new human to a cat */
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore];
catMapping.identificationAttributes = @[ @"railsID" ];
[catMapping addAttributeMappingsFromArray:@[@"name"]];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
humanMapping.identificationAttributes = @[ @"railsID" ];
[humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]];
[humanMapping addConnectionForRelationship:@"favoriteCat" connectedBy:@{ @"favoriteCatID": @"railsID" }];
// Create a cat to connect
RKCat *cat = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
cat.name = @"Asia";
cat.railsID = @31337;
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSDictionary *mappableData = @{ @"name": @"Blake", @"favoriteCatID": @31337 };
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
mappingOperationDataSource.operationQueue = [NSOperationQueue new];
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
operation.dataSource = mappingOperationDataSource;
NSError *error = nil;
BOOL success = [operation performMapping:&error];
[mappingOperationDataSource.operationQueue waitUntilAllOperationsAreFinished];
assertThatBool(success, is(equalToBool(YES)));
assertThat(human.favoriteCat, isNot(nilValue()));
assertThat(human.favoriteCat.name, is(equalTo(@"Asia")));
[mappingOperationDataSource.operationQueue waitUntilAllOperationsAreFinished];
}
- (void)testShouldConnectRelationshipsByPrimaryKeyReverse
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
NSManagedObjectContext *managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
humanMapping.identificationAttributes = @[ @"railsID" ];
[humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]];
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore];
catMapping.identificationAttributes = @[ @"railsID" ];
[catMapping addAttributeMappingsFromArray:@[@"name", @"railsID"]];
[catMapping addConnectionForRelationship:@"favoriteOfHumans" connectedBy:@{ @"railsID": @"favoriteCatID" }];
// Create some humans to connect
RKHuman *blake = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
blake.name = @"Blake";
blake.favoriteCatID = [NSNumber numberWithInt:31340];
RKHuman *jeremy = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
jeremy.name = @"Jeremy";
jeremy.favoriteCatID = [NSNumber numberWithInt:31340];
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSDictionary *mappableData = @{ @"name": @"Asia", @"railsID": @31340 };
RKCat *cat = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
NSOperationQueue *operationQueue = [NSOperationQueue new];
[operationQueue setSuspended:YES];
mappingOperationDataSource.operationQueue = operationQueue;
__block BOOL success;
[managedObjectContext performBlockAndWait:^{
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:mappableData destinationObject:cat mapping:catMapping];
operation.dataSource = mappingOperationDataSource;
NSError *error = nil;
success = [operation performMapping:&error];
}];
[operationQueue setSuspended:NO];
[operationQueue waitUntilAllOperationsAreFinished];
assertThatBool(success, is(equalToBool(YES)));
assertThat(cat.favoriteOfHumans, isNot(nilValue()));
assertThat([cat.favoriteOfHumans valueForKeyPath:@"name"], containsInAnyOrder(blake.name, jeremy.name, nil));
}
- (void)testConnectionOfHasManyRelationshipsByPrimaryKey
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore];
catMapping.identificationAttributes = @[ @"railsID" ];
[catMapping addAttributeMappingsFromArray:@[@"name"]];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
humanMapping.identificationAttributes = @[ @"railsID" ];
[humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]];
[humanMapping addConnectionForRelationship:@"favoriteCat" connectedBy:@{ @"favoriteCatID": @"railsID" }];
// Create a cat to connect
RKCat *cat = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
cat.name = @"Asia";
cat.railsID = @31337;
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSDictionary *mappableData = @{ @"name": @"Blake", @"favoriteCatID": @31337 };
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
mappingOperationDataSource.operationQueue = [NSOperationQueue new];
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
operation.dataSource = mappingOperationDataSource;
NSError *error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
[mappingOperationDataSource.operationQueue waitUntilAllOperationsAreFinished];
assertThat(human.favoriteCat, isNot(nilValue()));
assertThat(human.favoriteCat.name, is(equalTo(@"Asia")));
}
- (void)testConnectingARelationshipFromASourceAttributeWhoseValueIsACollectionWithFetchRequestCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore];
catMapping.identificationAttributes = @[ @"railsID" ];
[catMapping addAttributeMappingsFromArray:@[@"name"]];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
humanMapping.identificationAttributes = @[ @"railsID" ];
[humanMapping addAttributeMappingsFromArray:@[@"name", @"catIDs"]];
[humanMapping addConnectionForRelationship:@"cats" connectedBy:@{ @"catIDs": @"railsID" }];
// Create a couple of cats to connect
RKCat *asia = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
asia.name = @"Asia";
asia.railsID = @31337;
RKCat *roy = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
roy.name = @"Reginald Royford Williams III";
roy.railsID = [NSNumber numberWithInt:31338];
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSArray *catIDs = [NSArray arrayWithObjects:@31337, [NSNumber numberWithInt:31338], nil];
NSDictionary *mappableData = @{ @"name": @"Blake", @"catIDs": catIDs };
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
mappingOperationDataSource.operationQueue = [NSOperationQueue new];
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
operation.dataSource = mappingOperationDataSource;
NSError *error = nil;
BOOL success = [operation performMapping:&error];
[mappingOperationDataSource.operationQueue waitUntilAllOperationsAreFinished];
assertThatBool(success, is(equalToBool(YES)));
assertThat(human.cats, isNot(nilValue()));
assertThat([human.cats valueForKeyPath:@"name"], containsInAnyOrder(@"Asia", @"Reginald Royford Williams III", nil));
}
- (void)testConnectingARelationshipFromASourceAttributeWhoseValueIsACollectionWithInMemoryCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore];
catMapping.identificationAttributes = @[ @"railsID" ];
[catMapping addAttributeMappingsFromArray:@[@"name"]];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
humanMapping.identificationAttributes = @[ @"railsID" ];
[humanMapping addAttributeMappingsFromArray:@[@"name", @"catIDs"]];
[humanMapping addConnectionForRelationship:@"cats" connectedBy:@{ @"catIDs": @"railsID" }];
// Create a couple of cats to connect
RKCat *asia = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
asia.name = @"Asia";
asia.railsID = @31337;
RKCat *roy = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
roy.name = @"Reginald Royford Williams III";
roy.railsID = [NSNumber numberWithInt:31338];
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSArray *catIDs = [NSArray arrayWithObjects:@31337, [NSNumber numberWithInt:31338], nil];
NSDictionary *mappableData = @{ @"name": @"Blake", @"catIDs": catIDs };
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKInMemoryManagedObjectCache *managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
mappingOperationDataSource.operationQueue = [NSOperationQueue new];
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
operation.dataSource = mappingOperationDataSource;
NSError *error = nil;
BOOL success = [operation performMapping:&error];
[mappingOperationDataSource.operationQueue waitUntilAllOperationsAreFinished];
assertThatBool(success, is(equalToBool(YES)));
assertThat(human.cats, isNot(nilValue()));
assertThat([human.cats valueForKeyPath:@"name"], containsInAnyOrder(@"Asia", @"Reginald Royford Williams III", nil));
}
- (void)testShouldConnectRelationshipsByPrimaryKeyWithDifferentSourceAndDestinationKeyPathsReverse
{
/* Connect a new cat to a human */
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
humanMapping.identificationAttributes = @[ @"railsID" ];
[humanMapping addAttributeMappingsFromArray:@[@"name", @"railsID"]];
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore];
catMapping.identificationAttributes = @[ @"railsID" ];
[catMapping addAttributeMappingsFromArray:@[@"name", @"humanId"]];
[catMapping addConnectionForRelationship:@"human" connectedBy:@{ @"humanId": @"railsID" }];
// Create a human to connect
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.name = @"Blake";
human.railsID = @31337;
[managedObjectStore.persistentStoreManagedObjectContext save:nil];
NSDictionary *mappableData = @{ @"name": @"Asia", @"humanId": @31337 };
RKCat *cat = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
mappingOperationDataSource.operationQueue = [NSOperationQueue new];
RKMappingOperation* operation = [[RKMappingOperation alloc] initWithSourceObject:mappableData destinationObject:cat mapping:catMapping];
operation.dataSource = mappingOperationDataSource;
NSError *error = nil;
BOOL success = [operation performMapping:&error];
[mappingOperationDataSource.operationQueue waitUntilAllOperationsAreFinished];
assertThatBool(success, is(equalToBool(YES)));
assertThat(cat.human, isNot(nilValue()));
assertThat(cat.human.name, is(equalTo(@"Blake")));
}
- (void)testShouldLoadNestedHasManyRelationship
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore];
catMapping.identificationAttributes = @[ @"railsID" ];
[catMapping addAttributeMappingsFromArray:@[@"name"]];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
humanMapping.identificationAttributes = @[ @"railsID" ];
[humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]];
[humanMapping addRelationshipMappingWithSourceKeyPath:@"cats" mapping:catMapping];
NSArray *catsData = [NSArray arrayWithObject:[NSDictionary dictionaryWithObject:@"Asia" forKey:@"name"]];
NSDictionary *mappableData = @{ @"name": @"Blake", @"favoriteCatID": @31337, @"cats": catsData };
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
operation.dataSource = mappingOperationDataSource;
NSError *error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
}
- (void)testShouldLoadOrderedHasManyRelationship
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore];
catMapping.identificationAttributes = @[ @"railsID" ];
[catMapping addAttributeMappingsFromArray:@[@"name"]];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
humanMapping.identificationAttributes = @[ @"railsID" ];
[humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]];
[humanMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"cats" toKeyPath:@"catsInOrderByAge" withMapping:catMapping]];;
NSArray *catsData = [NSArray arrayWithObject:[NSDictionary dictionaryWithObject:@"Asia" forKey:@"name"]];
NSDictionary *mappableData = @{ @"name": @"Blake", @"favoriteCatID": @31337, @"cats": catsData };
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
operation.dataSource = mappingOperationDataSource;
NSError *error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
assertThat([human catsInOrderByAge], isNot(empty()));
}
- (void)testShouldMapNullToAHasManyRelationship
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore];
[catMapping addAttributeMappingsFromArray:@[@"name"]];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[humanMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]];
[humanMapping addRelationshipMappingWithSourceKeyPath:@"cats" mapping:catMapping];
NSDictionary *mappableData = @{ @"name": @"Blake", @"cats": [NSNull null] };
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
operation.dataSource = mappingOperationDataSource;
NSError *error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
assertThat(human.cats, is(empty()));
}
- (void)testShouldLoadNestedHasManyRelationshipWithoutABackingClass
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *cloudMapping = [RKEntityMapping mappingForEntityForName:@"Cloud" inManagedObjectStore:managedObjectStore];
[cloudMapping addAttributeMappingsFromArray:@[@"name"]];
RKEntityMapping *stormMapping = [RKEntityMapping mappingForEntityForName:@"Storm" inManagedObjectStore:managedObjectStore];
[stormMapping addAttributeMappingsFromArray:@[@"name", @"favoriteCatID"]];
[stormMapping addRelationshipMappingWithSourceKeyPath:@"clouds" mapping:cloudMapping];
NSArray *cloudsData = [NSArray arrayWithObject:[NSDictionary dictionaryWithObject:@"Nimbus" forKey:@"name"]];
NSDictionary *mappableData = @{ @"name": @"Hurricane", @"clouds": cloudsData };
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Storm" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
NSManagedObject *storm = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:mappableData destinationObject:storm mapping:stormMapping];
operation.dataSource = mappingOperationDataSource;
NSError *error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
}
- (void)testShouldConnectManyToManyRelationships
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *childMapping = [RKEntityMapping mappingForEntityForName:@"Child" inManagedObjectStore:managedObjectStore];
childMapping.identificationAttributes = @[ @"name" ];
[childMapping addAttributeMappingsFromArray:@[@"name"]];
RKEntityMapping *parentMapping = [RKEntityMapping mappingForEntityForName:@"Parent" inManagedObjectStore:managedObjectStore];
parentMapping.identificationAttributes = @[ @"railsID" ];
[parentMapping addAttributeMappingsFromArray:@[@"name", @"age"]];
[parentMapping addRelationshipMappingWithSourceKeyPath:@"children" mapping:childMapping];
NSArray *childMappableData = @[ @{ @"name": @"Maya" }, @{ @"name": @"Brady" } ];
NSDictionary *parentMappableData = @{ @"name": @"Win", @"age": @34, @"children": childMappableData };
RKParent *parent = [NSEntityDescription insertNewObjectForEntityForName:@"Parent" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
mappingOperationDataSource.operationQueue = [NSOperationQueue new];
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:parentMappableData destinationObject:parent mapping:parentMapping];
operation.dataSource = mappingOperationDataSource;
NSError *error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
assertThat(parent.children, isNot(nilValue()));
assertThatUnsignedInteger([parent.children count], is(equalToInt(2)));
assertThat([[parent.children anyObject] parents], isNot(nilValue()));
assertThatBool([[[parent.children anyObject] parents] containsObject:parent], is(equalToBool(YES)));
assertThatUnsignedInteger([[[parent.children anyObject] parents] count], is(equalToInt(1)));
[mappingOperationDataSource.operationQueue waitUntilAllOperationsAreFinished];
}
- (void)testShouldConnectRelationshipsByPrimaryKeyRegardlessOfOrder
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
NSManagedObjectContext *managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
RKEntityMapping *parentMapping = [RKEntityMapping mappingForEntityForName:@"Parent" inManagedObjectStore:managedObjectStore];
[parentMapping addAttributeMappingsFromArray:@[@"parentID"]];
parentMapping.identificationAttributes = @[ @"parentID" ];
RKEntityMapping *childMapping = [RKEntityMapping mappingForEntityForName:@"Child" inManagedObjectStore:managedObjectStore];
[childMapping addAttributeMappingsFromArray:@[@"fatherID"]];
[childMapping addConnectionForRelationship:@"father" connectedBy:@{ @"fatherID": @"parentID" }];
NSDictionary *mappingsDictionary = @{ @"parents": parentMapping, @"children": childMapping };
NSDictionary *JSON = [RKTestFixture parsedObjectWithContentsOfFixture:@"ConnectingParents.json"];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectContext
cache:managedObjectCache];
NSOperationQueue *operationQueue = [NSOperationQueue new];
[operationQueue setSuspended:YES];
mappingOperationDataSource.operationQueue = operationQueue;
[managedObjectContext performBlockAndWait:^{
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:JSON mappingsDictionary:mappingsDictionary];
mapper.mappingOperationDataSource = mappingOperationDataSource;
[mapper start];
}];
[operationQueue setSuspended:NO];
[operationQueue waitUntilAllOperationsAreFinished];
[managedObjectContext performBlockAndWait:^{
NSError *error;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Parent"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"parentID = %@", @1];
fetchRequest.fetchLimit = 1;
NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
RKParent *parent = [results lastObject];
assertThat(parent, is(notNilValue()));
NSSet *children = [parent fatheredChildren];
assertThat(children, hasCountOf(1));
RKChild *child = [children anyObject];
assertThat(child.father, is(notNilValue()));
}];
}
- (void)testMappingAPayloadContainingRepeatedObjectsDoesNotYieldDuplicatesWithFetchRequestMappingCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
managedObjectStore.managedObjectCache = managedObjectCache;
RKEntityMapping *childMapping = [RKEntityMapping mappingForEntityForName:@"Child" inManagedObjectStore:managedObjectStore];
childMapping.identificationAttributes = @[ @"childID" ];
[childMapping addAttributeMappingsFromArray:@[@"name", @"childID"]];
RKEntityMapping *parentMapping = [RKEntityMapping mappingForEntityForName:@"Parent" inManagedObjectStore:managedObjectStore];
[parentMapping addAttributeMappingsFromArray:@[@"parentID", @"name"]];
parentMapping.identificationAttributes = @[ @"parentID" ];
[parentMapping addRelationshipMappingWithSourceKeyPath:@"children" mapping:childMapping];
NSDictionary *mappingsDictionary = @{ @"parents": parentMapping };
NSDictionary *JSON = [RKTestFixture parsedObjectWithContentsOfFixture:@"parents_and_children.json"];
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:JSON mappingsDictionary:mappingsDictionary];
mapper.mappingOperationDataSource = mappingOperationDataSource;
[mapper start];
NSUInteger parentCount = [managedObjectStore.persistentStoreManagedObjectContext countForEntityForName:@"Parent" predicate:nil error:nil];
NSUInteger childrenCount = [managedObjectStore.persistentStoreManagedObjectContext countForEntityForName:@"Child" predicate:nil error:nil];
assertThatInteger(parentCount, is(equalToInteger(2)));
assertThatInteger(childrenCount, is(equalToInteger(4)));
}
- (void)testMappingAPayloadContainingRepeatedObjectsDoesNotYieldDuplicatesWithInMemoryMappingCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKInMemoryManagedObjectCache *managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
managedObjectStore.managedObjectCache = managedObjectCache;
RKEntityMapping *childMapping = [RKEntityMapping mappingForEntityForName:@"Child" inManagedObjectStore:managedObjectStore];
childMapping.identificationAttributes = @[ @"childID" ];
[childMapping addAttributeMappingsFromArray:@[@"name", @"childID"]];
RKEntityMapping *parentMapping = [RKEntityMapping mappingForEntityForName:@"Parent" inManagedObjectStore:managedObjectStore];
[parentMapping addAttributeMappingsFromArray:@[@"parentID", @"name"]];
parentMapping.identificationAttributes = @[ @"parentID" ];
[parentMapping addRelationshipMappingWithSourceKeyPath:@"children" mapping:childMapping];
// NOTE: This may be fragile. Reverse order seems to trigger them to be mapped parent first. NSDictionary
// keys are not guaranteed to return in any particular order
NSDictionary *mappingsDictionary = @{ @"parents": parentMapping };
NSDictionary *JSON = [RKTestFixture parsedObjectWithContentsOfFixture:@"parents_and_children.json"];
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:JSON mappingsDictionary:mappingsDictionary];
mapper.mappingOperationDataSource = mappingOperationDataSource;
[mapper start];
NSError *error = nil;
BOOL success = [managedObjectStore.persistentStoreManagedObjectContext save:&error];
assertThatBool(success, is(equalToBool(YES)));
NSLog(@"Failed to save MOC: %@", error);
assertThat(error, is(nilValue()));
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Parent"];
NSUInteger parentCount = [managedObjectStore.persistentStoreManagedObjectContext countForFetchRequest:fetchRequest error:&error];
NSUInteger childrenCount = [managedObjectStore.persistentStoreManagedObjectContext countForEntityForName:@"Child" predicate:nil error:nil];
assertThatInteger(parentCount, is(equalToInteger(2)));
assertThatInteger(childrenCount, is(equalToInteger(4)));
}
- (void)testThatMappingObjectsWithTheSameIdentificationAttributesAcrossTwoContextsDoesNotCreateDuplicateObjects
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKInMemoryManagedObjectCache *inMemoryCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
managedObjectStore.managedObjectCache = inMemoryCache;
NSEntityDescription *humanEntity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"railsID" ];
[mapping addAttributeMappingsFromArray:@[ @"name", @"railsID" ]];
// Create two contexts with common parent
NSManagedObjectContext *firstContext = [managedObjectStore newChildManagedObjectContextWithConcurrencyType:NSPrivateQueueConcurrencyType];
NSManagedObjectContext *secondContext = [managedObjectStore newChildManagedObjectContextWithConcurrencyType:NSPrivateQueueConcurrencyType];
// Map into the first context
NSDictionary *objectRepresentation = @{ @"name": @"Blake", @"railsID": @(31337) };
// Check that the cache contains a value for our identification attributes
__block BOOL success;
__block NSError *error;
[firstContext performBlockAndWait:^{
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:firstContext
cache:inMemoryCache];
RKMapperOperation *mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:objectRepresentation mappingsDictionary:@{ [NSNull null]: mapping }];
mapperOperation.mappingOperationDataSource = dataSource;
success = [mapperOperation execute:&error];
expect(success).to.equal(YES);
expect([mapperOperation.mappingResult count]).to.equal(1);
[firstContext save:nil];
}];
// Check that there is an entry in the cache
NSSet *objects = [inMemoryCache managedObjectsWithEntity:humanEntity attributeValues:@{ @"railsID": @(31337) } inManagedObjectContext:firstContext];
expect(objects).to.haveCountOf(1);
// Map into the second context
[secondContext performBlockAndWait:^{
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:secondContext
cache:inMemoryCache];
RKMapperOperation *mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:objectRepresentation mappingsDictionary:@{ [NSNull null]: mapping }];
mapperOperation.mappingOperationDataSource = dataSource;
success = [mapperOperation execute:&error];
expect(success).to.equal(YES);
expect([mapperOperation.mappingResult count]).to.equal(1);
[secondContext save:nil];
}];
// Now check the count
objects = [inMemoryCache managedObjectsWithEntity:humanEntity attributeValues:@{ @"railsID": @(31337) } inManagedObjectContext:secondContext];
expect(objects).to.haveCountOf(1);
// Now pull the count back from the parent context
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"railsID == 31337"];
NSArray *fetchedObjects = [managedObjectStore.persistentStoreManagedObjectContext executeFetchRequest:fetchRequest error:nil];
expect(fetchedObjects).to.haveCountOf(1);
}
- (void)testConnectingToSubentitiesByFetchRequestCache
{
}
- (void)testConnectingToSubentitiesByInMemoryCache
{
}
- (void)testDeletionOfTombstoneRecords
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKEntityMapping *mapping = [[RKEntityMapping alloc] initWithEntity:entity];
[mapping addAttributeMappingsFromArray:@[ @"name" ]];
mapping.deletionPredicate = [NSPredicate predicateWithFormat:@"sex = %@", @"female"];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.sex = @"female";
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:nil];
NSDictionary *representation = @{ @"name": @"Whatever" };
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:representation destinationObject:human mapping:mapping];
operation.dataSource = dataSource;
NSError *error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
expect([human isDeleted]).to.equal(YES);
}
- (void)testDeletionOfTombstoneRecordsInMapperOperation
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKEntityMapping *mapping = [[RKEntityMapping alloc] initWithEntity:entity];
[mapping addAttributeMappingsFromArray:@[ @"name" ]];
mapping.deletionPredicate = [NSPredicate predicateWithFormat:@"sex = %@", @"female"];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
human.sex = @"female";
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:nil];
NSDictionary *representation = @{ @"name": @"Whatever" };
NSError *error = nil;
RKMapperOperation *mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:representation mappingsDictionary:@{ [NSNull null]: mapping }];
mapperOperation.mappingOperationDataSource = dataSource;
BOOL success = [mapperOperation execute:&error];
assertThatBool(success, is(equalToBool(YES)));
expect([human isDeleted]).to.equal(YES);
}
- (void)testMappingAPayloadContainingRepeatedObjectsPerformsAcceptablyWithFetchRequestMappingCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
managedObjectStore.managedObjectCache = managedObjectCache;
RKEntityMapping *childMapping = [RKEntityMapping mappingForEntityForName:@"Child" inManagedObjectStore:managedObjectStore];
childMapping.identificationAttributes = @[ @"childID" ];
[childMapping addAttributeMappingsFromArray:@[@"name", @"childID"]];
RKEntityMapping *parentMapping = [RKEntityMapping mappingForEntityForName:@"Parent" inManagedObjectStore:managedObjectStore];
[parentMapping addAttributeMappingsFromArray:@[@"parentID", @"name"]];
parentMapping.identificationAttributes = @[ @"parentID" ];
[parentMapping addRelationshipMappingWithSourceKeyPath:@"children" mapping:childMapping];
NSDictionary *mappingsDictionary = @{ @"parents": parentMapping };
NSDictionary *JSON = [RKTestFixture parsedObjectWithContentsOfFixture:@"benchmark_parents_and_children.json"];
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:JSON mappingsDictionary:mappingsDictionary];
mapper.mappingOperationDataSource = mappingOperationDataSource;
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelOff);
RKLogConfigureByName("RestKit/CoreData", RKLogLevelOff);
[RKBenchmark report:@"Mapping with Fetch Request Cache" executionBlock:^{
for (NSUInteger i = 0; i < 50; i++) {
[mapper start];
}
}];
NSUInteger parentCount = [managedObjectStore.persistentStoreManagedObjectContext countForEntityForName:@"Parent" predicate:nil error:nil];
NSUInteger childrenCount = [managedObjectStore.persistentStoreManagedObjectContext countForEntityForName:@"Child" predicate:nil error:nil];
assertThatInteger(parentCount, is(equalToInteger(25)));
assertThatInteger(childrenCount, is(equalToInteger(51)));
}
- (void)testMappingAPayloadContainingRepeatedObjectsPerformsAcceptablyWithInMemoryMappingCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKInMemoryManagedObjectCache *managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
managedObjectStore.managedObjectCache = managedObjectCache;
RKEntityMapping *childMapping = [RKEntityMapping mappingForEntityForName:@"Child" inManagedObjectStore:managedObjectStore];
childMapping.identificationAttributes = @[ @"childID" ];
[childMapping addAttributeMappingsFromArray:@[@"name", @"childID"]];
RKEntityMapping *parentMapping = [RKEntityMapping mappingForEntityForName:@"Parent" inManagedObjectStore:managedObjectStore];
[parentMapping addAttributeMappingsFromArray:@[@"parentID", @"name"]];
parentMapping.identificationAttributes = @[ @"parentID" ];
[parentMapping addRelationshipMappingWithSourceKeyPath:@"children" mapping:childMapping];
NSDictionary *mappingsDictionary = @{ @"parents": parentMapping };
NSDictionary *JSON = [RKTestFixture parsedObjectWithContentsOfFixture:@"benchmark_parents_and_children.json"];
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:JSON mappingsDictionary:mappingsDictionary];
mapper.mappingOperationDataSource = mappingOperationDataSource;
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelOff);
RKLogConfigureByName("RestKit/CoreData", RKLogLevelOff);
[RKBenchmark report:@"Mapping with In Memory Cache" executionBlock:^{
for (NSUInteger i = 0; i < 50; i++) {
[mapper start];
}
}];
NSUInteger parentCount = [managedObjectStore.persistentStoreManagedObjectContext countForEntityForName:@"Parent" predicate:nil error:nil];
NSUInteger childrenCount = [managedObjectStore.persistentStoreManagedObjectContext countForEntityForName:@"Child" predicate:nil error:nil];
assertThatInteger(parentCount, is(equalToInteger(25)));
assertThatInteger(childrenCount, is(equalToInteger(51)));
}
- (void)testMappingIdentificationAttributesFromElementsOnAnArray
{
NSDictionary *representation = @{
@"userSessions": @{
@"name": @"Mr. User",
@"identification": @54321,
@"catIDs": @[ @"418", @"419", @"431",@"441", @"457", @"486", @"504" ]
}
};
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore];
catMapping.identificationAttributes = @[ @"railsID" ];
[catMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"railsID"]];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[humanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"identification" toKeyPath:@"railsID"]];
[humanMapping setIdentificationAttributes:@[ @"railsID" ]];
[humanMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"catIDs" toKeyPath:@"cats" withMapping:catMapping]];
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:representation mappingsDictionary:@{ @"userSessions": humanMapping }];
mapper.mappingOperationDataSource = mappingOperationDataSource;
[mapper start];
RKHuman *human = [mapper.mappingResult firstObject];
expect(human).notTo.beNil();
expect(human.railsID).to.equal(@54321);
expect(human.cats).to.haveCountOf(7);
NSSet *expectedIDs = [NSSet setWithArray:@[ @418, @419, @431, @441, @457, @486, @504 ]];
expect([human.cats valueForKey:@"railsID"]).to.equal(expectedIDs);
}
- (void)testMappingIdentificationAttributesFromElementsOnAnArrayDoesNotDuplicateManagedObjects
{
NSDictionary *representation = @{ @"userSessions": @{ @"name": @"Mr. User",
@"identification": @54321,
@"catIDs": @[ @"418", @"419", @"431",@"441", @"457", @"486", @"504" ] } };
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
NSManagedObject *cat1 = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[cat1 setValue:@(418) forKey:@"railsID"];
NSManagedObject *cat2 = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[cat2 setValue:@(419) forKey:@"railsID"];
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore];
catMapping.identificationAttributes = @[ @"railsID" ];
[catMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"railsID"]];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[humanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"identification" toKeyPath:@"railsID"]];
[humanMapping setIdentificationAttributes:@[ @"railsID" ]];
[humanMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"catIDs" toKeyPath:@"cats" withMapping:catMapping]];
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:representation mappingsDictionary:@{ @"userSessions": humanMapping }];
mapper.mappingOperationDataSource = mappingOperationDataSource;
[mapper start];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Cat"];
[fetchRequest setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"railsID" ascending:YES]]];
NSPredicate *catOnePredicate = [NSPredicate predicateWithFormat:@"railsID == 418"];
[fetchRequest setPredicate:catOnePredicate];
NSArray *catsWithID418 = [managedObjectStore.persistentStoreManagedObjectContext executeFetchRequest:fetchRequest error:NULL];
NSPredicate *catTwoPredicate = [NSPredicate predicateWithFormat:@"railsID == 419"];
[fetchRequest setPredicate:catTwoPredicate];
NSArray *catsWithID419 = [managedObjectStore.persistentStoreManagedObjectContext executeFetchRequest:fetchRequest error:NULL];
expect(catsWithID418).to.haveCountOf(1);
expect(catsWithID419).to.haveCountOf(1);
}
- (void)testManagedObjectsMappedWithRequiredRelationshipsThatAreSetByConnectionsAreNotPrematurelyDeleted
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
mappingOperationDataSource.operationQueue = [NSOperationQueue new];
NSManagedObject *cat = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[cat setValue:@(12345) forKey:@"railsID"];
NSDictionary *representation = @{ @"name": @"Blake Watters", @"requiredCatID": @(12345) };
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore];
catMapping.identificationAttributes = @[ @"railsID" ];
RKEntityMapping *strictHumanMapping = [RKEntityMapping mappingForEntityForName:@"StrictHuman" inManagedObjectStore:managedObjectStore];
[strictHumanMapping addAttributeMappingsFromDictionary:@{ @"name": @"name" }];
[strictHumanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"requiredCatID" toKeyPath:@"favoriteCatID"]];
[strictHumanMapping addConnectionForRelationship:@"requiredCat" connectedBy:@{ @"favoriteCatID": @"railsID" }];
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:representation mappingsDictionary:@{ [NSNull null]: strictHumanMapping }];
mapper.mappingOperationDataSource = mappingOperationDataSource;
[mapper start];
[mappingOperationDataSource.operationQueue waitUntilAllOperationsAreFinished];
RKHuman *blake = [mapper.mappingResult firstObject];
expect(blake.name).to.equal(@"Blake Watters");
expect(blake.managedObjectContext).notTo.beNil();
expect([blake isDeleted]).to.beFalsy();
expect([blake valueForKey:@"requiredCat"]).to.equal(cat);
}
- (void)testManagedObjectsMappedWithRelationshipsThatAreSetByConnectionsWithInMemoryCache
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKInMemoryManagedObjectCache *managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKManagedObjectMappingOperationDataSource *mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext
cache:managedObjectCache];
mappingOperationDataSource.operationQueue = [NSOperationQueue new];
NSDictionary *representation = @{ @"human": @{ @"name": @"Blake Watters", @"favoriteCatID": @(12345) }, @"cat": @{ @"railsID": @(12345) } };
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat"
inManagedObjectStore:managedObjectStore];
catMapping.identificationAttributes = @[ @"railsID" ];
[catMapping addAttributeMappingsFromDictionary:@{ @"railsID": @"railsID" }];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human"
inManagedObjectStore:managedObjectStore];
[humanMapping addAttributeMappingsFromDictionary:@{ @"name": @"name" }];
[humanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"favoriteCatID" toKeyPath:@"favoriteCatID"]];
[humanMapping addConnectionForRelationship:@"favoriteCat" connectedBy:@{ @"favoriteCatID": @"railsID" }];
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:representation
mappingsDictionary:@{ @"human": humanMapping , @"cat": catMapping }];
mapper.mappingOperationDataSource = mappingOperationDataSource;
mappingOperationDataSource.parentOperation = mapper;
[mapper start];
[mappingOperationDataSource.operationQueue waitUntilAllOperationsAreFinished];
RKCat *cat = [mapper.mappingResult.dictionary objectForKey:@"cat"];
expect(cat.railsID).to.equal(12345);
expect(cat.managedObjectContext).notTo.beNil();
RKHuman *blake = [mapper.mappingResult.dictionary objectForKey:@"human"];
expect(blake.name).to.equal(@"Blake Watters");
expect(blake.managedObjectContext).notTo.beNil();
expect([blake isDeleted]).to.beFalsy();
expect([blake valueForKey:@"favoriteCat"]).notTo.beNil();
expect([blake valueForKey:@"favoriteCat"]).to.equal([mapper.mappingResult.dictionary objectForKey:@"cat"]);
}
- (void)testDeletionOperationAfterManagedObjectContextIsDeallocated
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
NSManagedObjectContext *managedObjectContext = [managedObjectStore newChildManagedObjectContextWithConcurrencyType:NSPrivateQueueConcurrencyType];
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectContext cache:nil];
NSDictionary *representation = @{ @"human": @{ @"name": @"Blake Watters", @"favoriteCatID": @(12345) }, @"cat": @{ @"railsID": @(12345) } };
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat"
inManagedObjectStore:managedObjectStore];
RKCat *cat = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectContext];
RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:representation destinationObject:cat mapping:catMapping];
NSOperationQueue *operationQueue = [NSOperationQueue new];
[operationQueue setSuspended:YES];
dataSource.operationQueue = operationQueue;
id mockOperation = [OCMockObject partialMockForObject:mappingOperation];
[[[mockOperation stub] andReturn:catMapping] objectMapping];
[dataSource commitChangesForMappingOperation:mockOperation error:nil];
expect([operationQueue operationCount]).to.equal(1);
dataSource = nil;
managedObjectContext = nil;
[operationQueue setSuspended:NO];
[operationQueue waitUntilAllOperationsAreFinished];
// Create a operation queue
// Create data source
}
@end