Skip to content

Commit

Permalink
Merge pull request #645 from couchbase/feature/issue_637_cblis_ordere…
Browse files Browse the repository at this point in the history
…d_relationship

Add ordered relationship warning message to CBLIS
  • Loading branch information
snej committed Apr 5, 2015
2 parents 38dd697 + ae6022a commit b4850d3
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 37 deletions.
38 changes: 9 additions & 29 deletions Source/API/Extras/CBLIncrementalStore.m
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ @implementation CBLIncrementalStore
NSMutableArray* _coalescedChanges;
NSCache* _queryBuilderCache;
NSMutableDictionary* _fetchRequestResultCache;
NSMutableDictionary* _entityAndPropertyToFetchViewName;
CBLLiveQuery* _conflictsQuery;
NSString * _documentTypeKey;
}
Expand Down Expand Up @@ -242,7 +241,6 @@ - (id) initWithPersistentStoreCoordinator: (NSPersistentStoreCoordinator*)root
_coalescedChanges = [[NSMutableArray alloc] init];
_fetchRequestResultCache = [[NSMutableDictionary alloc] init];
_queryBuilderCache = [[NSCache alloc] init];
_entityAndPropertyToFetchViewName = [[NSMutableDictionary alloc] init];

self.conflictHandler = [self defaultConflictHandler];

Expand Down Expand Up @@ -270,11 +268,15 @@ -(BOOL) loadMetadata: (NSError**)outError {
// Check if the entity contains to-many relationship without an inverse relation and warn:
NSDictionary* relationship = [entity relationshipsByName];
for (NSRelationshipDescription *rel in [relationship allValues]) {
if (rel.isToMany && !rel.inverseRelationship) {
WARN(@"'%@' entity has a to-many relationship '%@' that has no inverse relationship "
"defined. The inverse relationship is requried by the CBLIncrementalStore for "
"fetching to-many relationship entities.", entity.name, rel.name);
break;
if (rel.isToMany) {
if (!rel.inverseRelationship)
WARN(@"'%@' entity has a to-many relationship '%@' that has no inverse relationship "
"defined. The inverse relationship is requried by the CBLIncrementalStore for "
"fetching to-many relationship entities.", entity.name, rel.name);

if (rel.ordered)
WARN(@"'%@' entity has an ordered to-many relationship '%@', which is not supported "
"by the CBLIncrementalStore.", entity.name, rel.name);
}
}
}
Expand Down Expand Up @@ -633,8 +635,6 @@ - (NSString *)documentTypeKey {

/** Initializes the views needed for querying objects by type and for to-many relationships.*/
- (void) initializeViews {
NSMutableDictionary* subentitiesToSuperentities = [NSMutableDictionary dictionary];

// Create a view for each to-many relationship
NSArray* entites = self.persistentStoreCoordinator.managedObjectModel.entities;
for (NSEntityDescription* entity in entites) {
Expand All @@ -661,22 +661,9 @@ - (void) initializeViews {
emit([doc objectForKey: invertRelPropName], nil);
}
} version: @"1.0"];

// Remember view for mapping super-entity and all sub-entities:
for (NSString* entityName in entityNames) {
[self setViewName: viewName
forFetchingProperty: invertRelPropName
fromEntity: entityName];
}
}
}
}

if (entity.subentities.count > 0) {
for (NSEntityDescription* subentity in entity.subentities) {
[subentitiesToSuperentities setObject: entity.name forKey: subentity.name];
}
}
}
}

Expand Down Expand Up @@ -1790,13 +1777,6 @@ - (void) purgeCachedObjectsForEntityName: (NSString*)entity {
}
}

#pragma mark - Views

- (void) setViewName: (NSString*)viewName forFetchingProperty: (NSString*)propertyName fromEntity: (NSString*)entity {
[_entityAndPropertyToFetchViewName setObject: viewName
forKey: [NSString stringWithFormat:@"%@_%@", entity, propertyName]];
}

#pragma mark - Attachments

- (NSData*) loadDataForAttachmentWithName: (NSString*)name ofDocumentWithID: (NSString*)documentID {
Expand Down
88 changes: 80 additions & 8 deletions Unit-Tests/IncrementalStore_Tests.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ @interface IncrementalStore_Tests : CBLTestCaseWithDB

@class Entry;
@class Subentry;
@class AnotherSubentry;
@class File;
@class Article;
@class User;
Expand All @@ -53,23 +54,41 @@ @interface Entry : NSManagedObject
// To-Many relationship without an inverse relationship.
@property (nonatomic, retain) NSSet *articles;

// To-Many with ordered relationship (not supported by CBLIS)
@property (nonatomic, retain) NSOrderedSet *anotherSubentries;

@end

@interface Entry (CoreDataGeneratedAccessors)
// subEntries:
- (void)addSubEntriesObject:(Subentry *)value;
- (void)removeSubEntriesObject:(Subentry *)value;
- (void)addSubEntries:(NSSet *)values;
- (void)removeSubEntries:(NSSet *)values;

// files:
- (void)addFilesObject:(File *)value;
- (void)removeFilesObject:(File *)value;
- (void)addFiles:(NSSet *)values;
- (void)removeFiles:(NSSet *)values;

// articles:
- (void)addArticlesObject:(Article *)value;
- (void)removeArticlesObject:(Article *)value;
- (void)addArticles:(NSSet *)values;
- (void)removeArticles:(NSSet *)values;

// anotherSubentries:
- (void)insertObject:(NSManagedObject *)value inAnotherSubentriesAtIndex:(NSUInteger)idx;
- (void)removeObjectFromAnotherSubentriesAtIndex:(NSUInteger)idx;
- (void)insertAnotherSubentries:(NSArray *)value atIndexes:(NSIndexSet *)indexes;
- (void)removeAnotherSubentriesAtIndexes:(NSIndexSet *)indexes;
- (void)replaceObjectInAnotherSubentriesAtIndex:(NSUInteger)idx withObject:(NSManagedObject *)value;
- (void)replaceAnotherSubentriesAtIndexes:(NSIndexSet *)indexes withAnotherSubentries:(NSArray *)values;
- (void)addAnotherSubentriesObject:(NSManagedObject *)value;
- (void)removeAnotherSubentriesObject:(NSManagedObject *)value;
- (void)addAnotherSubentries:(NSOrderedSet *)values;
- (void)removeAnotherSubentries:(NSOrderedSet *)values;
@end

@interface Subentry : NSManagedObject
Expand All @@ -78,6 +97,12 @@ @interface Subentry : NSManagedObject
@property (nonatomic, retain) Entry *entry;
@end

@interface AnotherSubentry : NSManagedObject
@property (nonatomic, retain) NSString * text;
@property (nonatomic, retain) NSNumber * number;
@property (nonatomic, retain) Entry *entry;
@end

@interface File : NSManagedObject
@property (nonatomic, retain) NSString * filename;
@property (nonatomic, retain) NSData * data;
Expand Down Expand Up @@ -346,7 +371,7 @@ - (void) test_ToManyRelationship {
RequireTestCase(CBLIncrementalStoreCRUD);
NSError *error;

// To-Many with inverse relationship
// To-Many with inverse relationship:
Entry *entry = [NSEntityDescription insertNewObjectForEntityForName:@"Entry"
inManagedObjectContext:context];
entry.created_at = [NSDate new];
Expand All @@ -365,7 +390,7 @@ - (void) test_ToManyRelationship {
success = [context save:&error];
Assert(success, @"Could not save context: %@", error);

// To-Many without inverse relationship
// To-Many without inverse relationship:
for (NSUInteger i = 0; i < 3; i++) {
Article *article = [NSEntityDescription insertNewObjectForEntityForName:@"Article"
inManagedObjectContext:context];
Expand All @@ -376,19 +401,30 @@ - (void) test_ToManyRelationship {
success = [context save:&error];
Assert(success, @"Could not save context: %@", error);

// Ordered To-Many relationship:
for (NSUInteger i = 0; i < 3; i++) {
AnotherSubentry *sub = [NSEntityDescription insertNewObjectForEntityForName:@"AnotherSubentry"
inManagedObjectContext:context];
sub.text = [NSString stringWithFormat:@"AnotherSub%lu", (unsigned long)i];
[entry addAnotherSubentriesObject:sub];
}

success = [context save:&error];
Assert(success, @"Could not save context: %@", error);

NSManagedObjectID *objectID = entry.objectID;

// tear down and re-init for checking that data got saved
// tear down and re-init for checking that data got saved:
context = [CBLIncrementalStore createManagedObjectContextWithModel:model
databaseName:db.name error:&error];

entry = (Entry*)[context existingObjectWithID:objectID error:&error];
Assert(entry, @"Entry could not be loaded: %@", error);
AssertEq(entry.subEntries.count, 3u);
// Current we do not support to-many-non-inverse-relationship.
// We do not support to-many-non-inverse-relationship.
AssertEq(entry.articles.count, 0u);

// Tear down and re-init and test with fetch request
// Tear down and re-init and test with fetch request:
context = [CBLIncrementalStore createManagedObjectContextWithModel:model
databaseName:db.name error:&error];

Expand All @@ -397,7 +433,11 @@ - (void) test_ToManyRelationship {
AssertEq(result.count, 1u);
entry = result.firstObject;
AssertEq(entry.subEntries.count, 3u);
// NOTE: Current we do not support to-many-non-inverse-relationship.

// Not support the order feature but should return the data.
AssertEq(entry.anotherSubentries.count, 3u);

// We do not support to-many-non-inverse-relationship.
AssertEq(entry.articles.count, 0u);
}

Expand Down Expand Up @@ -1183,6 +1223,10 @@ - (void)assertFetchResult:(NSArray *)result key:(NSString *)key
[subentry setName:@"Subentry"];
[subentry setManagedObjectClassName:@"Subentry"];

NSEntityDescription *anotherSubentry = [NSEntityDescription new];
[anotherSubentry setName:@"AnotherSubentry"];
[anotherSubentry setManagedObjectClassName:@"AnotherSubentry"];

NSEntityDescription *article = [NSEntityDescription new];
[article setName:@"Article"];
[article setManagedObjectClassName:@"Article"];
Expand All @@ -1202,17 +1246,24 @@ - (void)assertFetchResult:(NSArray *)result key:(NSString *)key

NSRelationshipDescription *entryFiles = CBLISRelationshipDescription(@"files", YES, YES, NSCascadeDeleteRule, file);
NSRelationshipDescription *entrySubentries = CBLISRelationshipDescription(@"subEntries", YES, YES, NSCascadeDeleteRule, subentry);
NSRelationshipDescription *entryAnotherSubentries = CBLISRelationshipDescription(@"anotherSubentries", YES, YES, NSCascadeDeleteRule, anotherSubentry);
NSRelationshipDescription *fileEntry = CBLISRelationshipDescription(@"entry", YES, NO, NSNullifyDeleteRule, entry);
NSRelationshipDescription *subentryEntry = CBLISRelationshipDescription(@"entry", YES, NO, NSNullifyDeleteRule, entry);
NSRelationshipDescription *anotherSubentryEntry = CBLISRelationshipDescription(@"entry", YES, NO, NSNullifyDeleteRule, entry);
NSRelationshipDescription *entryArticles = CBLISRelationshipDescription(@"articles", YES, YES, NSCascadeDeleteRule, article);
NSRelationshipDescription *entryUser = CBLISRelationshipDescription(@"user", YES, NO, NSNullifyDeleteRule, user);
NSRelationshipDescription *userEntry = CBLISRelationshipDescription(@"entry", YES, NO, NSNullifyDeleteRule, entry);

[entryFiles setInverseRelationship:fileEntry];
[entrySubentries setInverseRelationship:subentryEntry];
[entryAnotherSubentries setInverseRelationship:anotherSubentryEntry];
[fileEntry setInverseRelationship:entryFiles];
[subentryEntry setInverseRelationship:entrySubentries];
[anotherSubentryEntry setInverseRelationship:entryAnotherSubentries];
[userEntry setInverseRelationship:entryUser];

[entryAnotherSubentries setOrdered:YES];
[anotherSubentryEntry setOrdered:YES];

[entry setProperties:@[
CBLISAttributeDescription(@"check", YES, NSBooleanAttributeType, nil),
Expand All @@ -1224,6 +1275,7 @@ - (void)assertFetchResult:(NSArray *)result key:(NSString *)key
CBLISAttributeDescription(@"text2", YES, NSStringAttributeType, nil),
entryFiles,
entrySubentries,
entryAnotherSubentries,
entryArticles,
entryUser
]];
Expand All @@ -1240,6 +1292,12 @@ - (void)assertFetchResult:(NSArray *)result key:(NSString *)key
subentryEntry
]];

[anotherSubentry setProperties:@[
CBLISAttributeDescription(@"number", YES, NSInteger32AttributeType, @(0)),
CBLISAttributeDescription(@"text", YES, NSStringAttributeType, nil),
anotherSubentryEntry
]];

[article setProperties:@[
CBLISAttributeDescription(@"name", YES, NSStringAttributeType, nil)
]];
Expand All @@ -1257,19 +1315,33 @@ - (void)assertFetchResult:(NSArray *)result key:(NSString *)key
CBLISAttributeDescription(@"anotherName", YES, NSStringAttributeType, nil)
]];

[model setEntities:@[entry, file, subentry, article, user, parent, child]];
[model setEntities:@[entry, file, subentry, anotherSubentry, article, user, parent, child]];

return model;
}

@implementation Entry
@dynamic check, created_at, text, text2, number, decimalNumber, doubleNumber, subEntries, files, articles, user;
@dynamic check, created_at, text, text2, number, decimalNumber, doubleNumber;
@dynamic subEntries, files, articles, anotherSubentries;
@dynamic user;

// Known Core Data Bug:
// Error: [nsset intersectsset:]: set argument is not an nsset.
// Workaround: Override and reimplement the method.
- (void)addAnotherSubentriesObject: (NSManagedObject *)value; {
NSMutableOrderedSet* tempSet = [self mutableOrderedSetValueForKey :@"anotherSubentries"];
[tempSet addObject:value];
}
@end

@implementation Subentry
@dynamic text, number, entry;
@end

@implementation AnotherSubentry
@dynamic text, number, entry;
@end

@implementation File
@dynamic filename, data, entry;
@end
Expand Down

0 comments on commit b4850d3

Please sign in to comment.