mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-01-12 22:51:50 +08:00
Improve relationship connection behaviors when all connection attributes resolve to nil. Add logic for skipping the connection entirely. refs #1099
This commit is contained in:
@@ -38,6 +38,11 @@ static id RKMutableSetValueForRelationship(NSRelationshipDescription *relationsh
|
||||
return [relationship isOrdered] ? [NSMutableOrderedSet orderedSet] : [NSMutableSet set];
|
||||
}
|
||||
|
||||
static BOOL RKConnectionAttributeValuesIsNotConnectable(NSDictionary *attributeValues)
|
||||
{
|
||||
return [[NSSet setWithArray:[attributeValues allValues]] isEqualToSet:[NSSet setWithObject:[NSNull null]]];
|
||||
}
|
||||
|
||||
static NSDictionary *RKConnectionAttributeValuesWithObject(RKConnectionDescription *connection, NSManagedObject *managedObject)
|
||||
{
|
||||
NSCAssert([connection isForeignKeyConnection], @"Only valid for a foreign key connection");
|
||||
@@ -47,7 +52,7 @@ static NSDictionary *RKConnectionAttributeValuesWithObject(RKConnectionDescripti
|
||||
id sourceValue = [managedObject valueForKey:sourceAttribute];
|
||||
[destinationEntityAttributeValues setValue:sourceValue ?: [NSNull null] forKey:destinationAttribute];
|
||||
}
|
||||
return [[destinationEntityAttributeValues allValues] isEqualToArray:@[ [NSNull null] ]] ? nil : destinationEntityAttributeValues;
|
||||
return RKConnectionAttributeValuesIsNotConnectable(destinationEntityAttributeValues) ? nil : destinationEntityAttributeValues;
|
||||
}
|
||||
|
||||
@interface RKRelationshipConnectionOperation ()
|
||||
@@ -136,14 +141,19 @@ static NSDictionary *RKConnectionAttributeValuesWithObject(RKConnectionDescripti
|
||||
return result;
|
||||
}
|
||||
|
||||
- (id)findConnected
|
||||
- (id)findConnected:(BOOL *)shouldConnectRelationship
|
||||
{
|
||||
*shouldConnectRelationship = YES;
|
||||
id connectionResult = nil;
|
||||
if (self.connection.sourcePredicate && ![self.connection.sourcePredicate evaluateWithObject:self.managedObject]) return nil;
|
||||
|
||||
if ([self.connection isForeignKeyConnection]) {
|
||||
NSDictionary *attributeValues = RKConnectionAttributeValuesWithObject(self.connection, self.managedObject);
|
||||
if ([attributeValues count] == 0) return nil;
|
||||
// If there are no attribute values available for connecting, skip the connection entirely
|
||||
if (! attributeValues) {
|
||||
*shouldConnectRelationship = NO;
|
||||
return nil;
|
||||
}
|
||||
NSSet *managedObjects = [self.managedObjectCache managedObjectsWithEntity:[self.connection.relationship destinationEntity]
|
||||
attributeValues:attributeValues
|
||||
inManagedObjectContext:self.managedObjectContext];
|
||||
@@ -174,10 +184,13 @@ static NSDictionary *RKConnectionAttributeValuesWithObject(RKConnectionDescripti
|
||||
NSString *relationshipName = self.connection.relationship.name;
|
||||
RKLogTrace(@"Connecting relationship '%@' with mapping: %@", relationshipName, self.connection);
|
||||
[self.managedObjectContext performBlockAndWait:^{
|
||||
self.connectedValue = [self findConnected];
|
||||
[self.managedObject setValue:self.connectedValue forKeyPath:relationshipName];
|
||||
RKLogDebug(@"Connected relationship '%@' to object '%@'", relationshipName, self.connectedValue);
|
||||
if (self.connectionBlock) self.connectionBlock(self, self.connectedValue);
|
||||
BOOL shouldConnect = YES;
|
||||
self.connectedValue = [self findConnected:&shouldConnect];
|
||||
if (shouldConnect) {
|
||||
[self.managedObject setValue:self.connectedValue forKeyPath:relationshipName];
|
||||
RKLogDebug(@"Connected relationship '%@' to object '%@'", relationshipName, self.connectedValue);
|
||||
if (self.connectionBlock) self.connectionBlock(self, self.connectedValue);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -340,4 +340,30 @@
|
||||
assertThat(human.cats, hasItems(lola, nil));
|
||||
}
|
||||
|
||||
- (void)testConnectionOfOptionalRelationshipIsSkippedWhenAllAttributesEvaluateToNil
|
||||
{
|
||||
RKHuman *human = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:nil withProperties:nil];
|
||||
|
||||
RKCat *asia = [RKTestFactory insertManagedObjectForEntityForName:@"Cat" inManagedObjectContext:nil withProperties:@{@"birthYear": @2011}];
|
||||
asia.sex = @"female";
|
||||
asia.name = @"Asia";
|
||||
RKCat *lola = [RKTestFactory insertManagedObjectForEntityForName:@"Cat" inManagedObjectContext:nil withProperties:@{@"birthYear": @2012}];
|
||||
lola.sex = @"female";
|
||||
lola.name = nil;
|
||||
|
||||
human.cats = [NSSet setWithObject:asia];
|
||||
|
||||
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:[RKTestFactory managedObjectStore]];
|
||||
[mapping addConnectionForRelationship:@"cats" connectedBy:@[ @"sex", @"name" ]];
|
||||
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
|
||||
RKConnectionDescription *connection = [mapping connectionForRelationship:@"cats"];
|
||||
|
||||
RKRelationshipConnectionOperation *operation = [[RKRelationshipConnectionOperation alloc] initWithManagedObject:human connection:connection managedObjectCache:managedObjectCache];
|
||||
[operation start];
|
||||
|
||||
// Operation should be skipped due to lack of connectable attributes
|
||||
assertThat(human.cats, hasCountOf(1));
|
||||
assertThat(human.cats, hasItems(asia, nil));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user