Mantle/Mantle — pull request #315 by kylef (2014-04-23 22:46:38+00:00)
Title: Include a test for not deleting an existing object on validation error

This is a test which will be skipped, it's for #223, I haven't managed to fix it just yet. The method we solution we discussed in #223 will not work because the implementation will break existing behaviour. Since you cannot make a child context with a confinement typed parent. (Unfortunately I wasted time in implementing this before I found out).

```diff
diff --git a/Mantle/MTLManagedObjectAdapter.m b/Mantle/MTLManagedObjectAdapter.m
index 4f27cc7..28813ba 100644
--- a/Mantle/MTLManagedObjectAdapter.m
+++ b/Mantle/MTLManagedObjectAdapter.m
@@ -309,36 +309,35 @@ static id performInContext(NSManagedObjectContext *context, id (^block)(void)) {
__block NSManagedObject *managedObject = nil;
NSPredicate *uniquingPredicate = [self uniquingPredicateForModel:model];

+	NSManagedObjectContext *childContext = [[[context class] alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
+	childContext.parentContext = context;
+
if (uniquingPredicate != nil) {
__block NSError *fetchRequestError = nil;
__block BOOL encountedError = NO;
-	managedObject = performInContext(context, ^ id {
-	NSFetchRequest *fetchRequest = [[fetchRequestClass alloc] init];
-	fetchRequest.entity = [entityDescriptionClass entityForName:entityName inManagedObjectContext:context];
-	fetchRequest.predicate = uniquingPredicate;
-	fetchRequest.returnsObjectsAsFaults = NO;
-	fetchRequest.fetchLimit = 1;
+	NSFetchRequest *fetchRequest = [[fetchRequestClass alloc] init];
+	fetchRequest.entity = [entityDescriptionClass entityForName:entityName inManagedObjectContext:childContext];
+	fetchRequest.predicate = uniquingPredicate;
+	fetchRequest.returnsObjectsAsFaults = NO;
+	fetchRequest.fetchLimit = 1;

-	NSArray *results = [context executeFetchRequest:fetchRequest error:&fetchRequestError];
+	NSArray *results = [childContext executeFetchRequest:fetchRequest error:&fetchRequestError];

-	if (results == nil) {
-	encountedError = YES;
-	if (error != NULL) {
-	NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"Failed to fetch a managed object for uniqing predicate \"%@\".", @""), uniquingPredicate];
-
-	NSDictionary *userInfo = @{
-	NSLocalizedDescriptionKey: NSLocalizedString(@"Could not serialize managed object", @""),
-	NSLocalizedFailureReasonErrorKey: failureReason,
-	};
-
-	fetchRequestError = [NSError errorWithDomain:MTLManagedObjectAdapterErrorDomain code:MTLManagedObjectAdapterErrorUniqueFetchRequestFailed userInfo:userInfo];
-	}
+	if (results == nil) {
+	encountedError = YES;
+	if (error != NULL) {
+	NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"Failed to fetch a managed object for uniqing predicate \"%@\".", @""), uniquingPredicate];

-	return nil;
+	NSDictionary *userInfo = @{
+	NSLocalizedDescriptionKey: NSLocalizedString(@"Could not serialize managed object", @""),
+	NSLocalizedFailureReasonErrorKey: failureReason,
+	};
+
+	fetchRequestError = [NSError errorWithDomain:MTLManagedObjectAdapterErrorDomain code:MTLManagedObjectAdapterErrorUniqueFetchRequestFailed userInfo:userInfo];
}
+	}

-	return results.mtl_firstObject;
-	});
+	managedObject = results.mtl_firstObject;

if (encountedError && error != NULL) {
*error = fetchRequestError;
@@ -347,7 +346,7 @@ static id performInContext(NSManagedObjectContext *context, id (^block)(void)) {
}

if (managedObject == nil) {
-	managedObject = [entityDescriptionClass insertNewObjectForEntityForName:entityName inManagedObjectContext:context];
+	managedObject = [entityDescriptionClass insertNewObjectForEntityForName:entityName inManagedObjectContext:childContext];
} else {
// Our CoreData store already has data for this model, we need to merge
[self mergeValuesOfModel:model forKeysFromManagedObject:managedObject];
@@ -414,7 +413,7 @@ static id performInContext(NSManagedObjectContext *context, id (^block)(void)) {
return nil;
}

-	return [self.class managedObjectFromModel:model insertingIntoContext:context processedObjects:processedObjects error:&tmpError];
+	return [self.class managedObjectFromModel:model insertingIntoContext:childContext processedObjects:processedObjects error:&tmpError];
};

BOOL (^serializeRelationship)(NSRelationshipDescription *) = ^(NSRelationshipDescription *relationshipDescription) {
@@ -494,21 +493,19 @@ static id performInContext(NSManagedObjectContext *context, id (^block)(void)) {
};

if (!serializeProperty(managedObjectProperties[managedObjectKey])) {
-	performInContext(context, ^ id {
-	[context deleteObject:managedObject];
-	return nil;
-	});
-
managedObject = nil;
*stop = YES;
}
}];

if (managedObject != nil && ![managedObject validateForInsert:&tmpError]) {
-	managedObject = performInContext(context, ^ id {
-	[context deleteObject:managedObject];
-	return nil;
-	});
+	managedObject = nil;
+	}
+
+	if (managedObject != nil) {
+	if ([childContext save:&tmpError] == NO) {
+	managedObject = nil;
+	}
}

if (error != NULL) {
```