mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-01-12 22:51:50 +08:00
Add new RKManagedObjectStore method for assisting in performing migrations when you have made dynamic modifications to the managed object model (such as when you leverage the Search indexing support)
This commit is contained in:
@@ -244,6 +244,54 @@
|
||||
*/
|
||||
- (NSManagedObjectContext *)newChildManagedObjectContextWithConcurrencyType:(NSManagedObjectContextConcurrencyType)concurrencyType;
|
||||
|
||||
///----------------------------
|
||||
/// @name Performing Migrations
|
||||
///----------------------------
|
||||
|
||||
/**
|
||||
Performs a migration on a persistent store at a given URL to the model at the specified URL.
|
||||
|
||||
This method provides support for migrating persistent stores in which the source and destination models have been mutated after being loaded from the model archive on disk, such as when the RestKit managed object searching support is used. In a situation where the persistent store has been created with a dynamically modified managed object model. Core Data is unable to infer the mapping model because the metadata of the persistent store does not agree with that of the managed object model due to the dynamic modifications. In order to perform a migration, one must load the appropriate source model, apply the dynamic changes appropriate for that model, then infer a mapping model from the modified model. This method assists in this process by accepting a source store and a destination model as arguments and searching through all models in the .momd package and yielding each model to the given configuration block for processing. After the block is invoked, the metadata of the store is checked for compatibility with the modified managed object model to identify the source store. Once the source store is found, a mapping model is inferred and the migration proceeds. The migration is done against a copy of the given persistent store and if successful, the migrated store is moved to replace the original store.
|
||||
|
||||
To understand how this is used, consider the following example: Given a managed object model containing two entities 'Article' and 'Tag', the user wishes to configure managed object search indexing on the models and wishes to be able to migrate existing persistent stores across versions. The migration configuration would look something like this:
|
||||
|
||||
NSURL *storeURL = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"MyStore.sqlite"];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"VersionedModel" withExtension:@"momd"];
|
||||
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:^(NSManagedObjectModel *model, NSURL *sourceURL) {
|
||||
// Examine each model and configure search indexing appropriately based on the versionIdentifiers configured in the model
|
||||
if ([[model versionIdentifiers] isEqualToSet:[NSSet setWithObject:@"1.0"]]) {
|
||||
NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"];
|
||||
NSEntityDescription *tagEntity = [[model entitiesByName] objectForKey:@"Tag"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title" ]];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]];
|
||||
} else if ([[model versionIdentifiers] isEqualToSet:[NSSet setWithObject:@"2.0"]]) {
|
||||
NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"];
|
||||
NSEntityDescription *tagEntity = [[model entitiesByName] objectForKey:@"Tag"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title", @"body" ]];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]];
|
||||
} else if ([[model versionIdentifiers] containsObject:@"3.0"] || [[model versionIdentifiers] containsObject:@"4.0"]) {
|
||||
// We index the same attributes on v3 and v4
|
||||
NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"];
|
||||
NSEntityDescription *tagEntity = [[model entitiesByName] objectForKey:@"Tag"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title", @"body", @"authorName" ]];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]];
|
||||
}
|
||||
}];
|
||||
|
||||
@param storeType The type of store that given URL. May be `nil`.
|
||||
@param storeURL A URL to the store that is to be migrated.
|
||||
@param destinationModelURL A URL to the managed object model that the persistent store is to be updated to. This URL may target a specific model version with a .momd package or point to the .momd package itself, in which case the migration is performed to the current version of the model as configured on the .xcdatamodeld file used to the build the .momd package.
|
||||
@param error A pointer to an error object that is set in the event that the migration is unsuccessful.
|
||||
@param block A block object used to configure
|
||||
|
||||
@warning This method is only usable with a versioned Managed Object Model stored as a .momd package containing .mom managed object model archives.
|
||||
*/
|
||||
+ (BOOL)migratePersistentStoreOfType:(NSString *)storeType
|
||||
atURL:(NSURL *)storeURL
|
||||
toModelAtURL:(NSURL *)destinationModelURL
|
||||
error:(NSError **)error
|
||||
configuringModelsWithBlock:(void (^)(NSManagedObjectModel *model, NSURL *sourceURL))block;
|
||||
|
||||
@end
|
||||
|
||||
// Option containing the path to the seed database a SQLite store was initialized with
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#undef RKLogComponent
|
||||
#define RKLogComponent RKlcl_cRestKitCoreData
|
||||
|
||||
extern NSString * const RKErrorDomain;
|
||||
|
||||
NSString * const RKSQLitePersistentStoreSeedDatabasePathOption = @"RKSQLitePersistentStoreSeedDatabasePathOption";
|
||||
NSString * const RKManagedObjectStoreDidFailSaveNotification = @"RKManagedObjectStoreDidFailSaveNotification";
|
||||
|
||||
@@ -288,4 +290,101 @@ static RKManagedObjectStore *defaultStore = nil;
|
||||
}];
|
||||
}
|
||||
|
||||
+ (BOOL)migratePersistentStoreOfType:(NSString *)storeType
|
||||
atURL:(NSURL *)storeURL
|
||||
toModelAtURL:(NSURL *)destinationModelURL
|
||||
error:(NSError **)error
|
||||
configuringModelsWithBlock:(void (^)(NSManagedObjectModel *, NSURL *))block
|
||||
{
|
||||
BOOL isMomd = [[destinationModelURL pathExtension] isEqualToString:@"momd"]; // Momd contains a directory of versioned models
|
||||
NSManagedObjectModel *destinationModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:destinationModelURL] mutableCopy];
|
||||
|
||||
// Yield the destination model for configuration (i.e. search indexing)
|
||||
if (block) block(destinationModel, destinationModelURL);
|
||||
|
||||
// Check if the store is compatible with our model
|
||||
NSDictionary *storeMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType
|
||||
URL:storeURL
|
||||
error:error];
|
||||
if (! storeMetadata) return NO;
|
||||
if ([destinationModel isConfiguration:nil compatibleWithStoreMetadata:storeMetadata]) {
|
||||
// Our store is compatible with the current model, no migration is necessary
|
||||
return YES;
|
||||
}
|
||||
|
||||
RKLogInfo(@"Determined that store at URL %@ has incompatible metadata for managed object model: performing migration...", storeURL);
|
||||
|
||||
NSURL *momdURL = isMomd ? destinationModelURL : [destinationModelURL URLByDeletingLastPathComponent];
|
||||
|
||||
// We can only do migrations within a versioned momd
|
||||
if (![[momdURL pathExtension] isEqualToString:@"momd"]) {
|
||||
NSString *errorDescription = [NSString stringWithFormat:@"Migration failed: Migrations can only be performed to versioned destination models contained in a .momd package. Incompatible destination model given at path '%@'", [momdURL path]];
|
||||
*error = [NSError errorWithDomain:RKErrorDomain code:NSMigrationError userInfo:@{ NSLocalizedDescriptionKey: errorDescription }];
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSArray *versionedModelURLs = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:momdURL
|
||||
includingPropertiesForKeys:@[] // We only want the URLs
|
||||
options:NSDirectoryEnumerationSkipsPackageDescendants|NSDirectoryEnumerationSkipsHiddenFiles
|
||||
error:error];
|
||||
if (! versionedModelURLs) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Iterate across each model version and try to find a compatible store
|
||||
NSManagedObjectModel *sourceModel = nil;
|
||||
for (NSURL *versionedModelURL in versionedModelURLs) {
|
||||
if (! [@[@"mom", @"momd"] containsObject:[versionedModelURL pathExtension]]) continue;
|
||||
NSManagedObjectModel *model = [[[NSManagedObjectModel alloc] initWithContentsOfURL:versionedModelURL] mutableCopy];
|
||||
if (! model) continue;
|
||||
if (block) block(model, versionedModelURL);
|
||||
|
||||
if ([model isConfiguration:nil compatibleWithStoreMetadata:storeMetadata]) {
|
||||
sourceModel = model;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot complete the migration as we can't find a source model
|
||||
if (! sourceModel) {
|
||||
NSString *errorDescription = [NSString stringWithFormat:@"Migration failed: Unable to find the source managed object model used to create the %@ store at path '%@'", storeType, [storeURL path]];
|
||||
*error = [NSError errorWithDomain:RKErrorDomain code:NSMigrationMissingSourceModelError userInfo:@{ NSLocalizedDescriptionKey: errorDescription }];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Infer a mapping model and complete the migration
|
||||
NSMappingModel *mappingModel = [NSMappingModel inferredMappingModelForSourceModel:sourceModel
|
||||
destinationModel:destinationModel
|
||||
error:error];
|
||||
if (!mappingModel) {
|
||||
RKLogError(@"Failed to obtain inferred mapping model for source and destination models: aborting migration...");
|
||||
RKLogError(@"%@", *error);
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *UUID = (__bridge_transfer NSString*)CFUUIDCreateString(kCFAllocatorDefault, CFUUIDCreate(NULL));
|
||||
NSString *migrationPath = [NSTemporaryDirectory() stringByAppendingFormat:@"Migration-%@.sqlite", UUID];
|
||||
NSURL *migrationURL = [NSURL fileURLWithPath:migrationPath];
|
||||
|
||||
// Create a migration manager to perform the migration.
|
||||
NSMigrationManager *manager = [[NSMigrationManager alloc] initWithSourceModel:sourceModel destinationModel:destinationModel];
|
||||
BOOL success = [manager migrateStoreFromURL:storeURL type:NSSQLiteStoreType
|
||||
options:nil withMappingModel:mappingModel toDestinationURL:migrationURL
|
||||
destinationType:NSSQLiteStoreType destinationOptions:nil error:error];
|
||||
|
||||
if (success) {
|
||||
success = [[NSFileManager defaultManager] removeItemAtURL:storeURL error:error];
|
||||
if (success) {
|
||||
success = [[NSFileManager defaultManager] moveItemAtURL:migrationURL toURL:storeURL error:error];
|
||||
if (success) RKLogInfo(@"Successfully migrated existing store to managed object model at path '%@'...", [destinationModelURL path]);
|
||||
} else {
|
||||
RKLogError(@"Failed to remove existing store at path '%@': unable to complete migration...", [storeURL path]);
|
||||
RKLogError(@"%@", *error);
|
||||
}
|
||||
} else {
|
||||
RKLogError(@"Failed migration with error: %@", *error);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -475,6 +475,8 @@
|
||||
25A226D81618A57500952D72 /* RKObjectUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 25A226D51618A57500952D72 /* RKObjectUtilities.m */; };
|
||||
25A226D91618A57500952D72 /* RKObjectUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 25A226D51618A57500952D72 /* RKObjectUtilities.m */; };
|
||||
25A34245147D8AAA0009758D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25A34244147D8AAA0009758D /* Security.framework */; };
|
||||
25A73362169C8C230090A930 /* VersionedModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 25A73360169C8C230090A930 /* VersionedModel.xcdatamodeld */; };
|
||||
25A73363169C8C230090A930 /* VersionedModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 25A73360169C8C230090A930 /* VersionedModel.xcdatamodeld */; };
|
||||
25A763DB15C7240200A9DF31 /* RKSearchTokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 25A763D915C7240100A9DF31 /* RKSearchTokenizer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
25A763DC15C7240200A9DF31 /* RKSearchTokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 25A763D915C7240100A9DF31 /* RKSearchTokenizer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
25A763DD15C7240200A9DF31 /* RKSearchTokenizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 25A763DA15C7240100A9DF31 /* RKSearchTokenizer.m */; };
|
||||
@@ -884,6 +886,10 @@
|
||||
25A226D41618A57500952D72 /* RKObjectUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKObjectUtilities.h; sourceTree = "<group>"; };
|
||||
25A226D51618A57500952D72 /* RKObjectUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectUtilities.m; sourceTree = "<group>"; };
|
||||
25A34244147D8AAA0009758D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
|
||||
25A73361169C8C230090A930 /* VersionedModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = VersionedModel.xcdatamodel; sourceTree = "<group>"; };
|
||||
25A73365169C8CD80090A930 /* VersionedModel 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "VersionedModel 2.xcdatamodel"; sourceTree = "<group>"; };
|
||||
25A73366169C8CF30090A930 /* VersionedModel 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "VersionedModel 3.xcdatamodel"; sourceTree = "<group>"; };
|
||||
25A73367169C8D500090A930 /* VersionedModel 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "VersionedModel 4.xcdatamodel"; sourceTree = "<group>"; };
|
||||
25A763D915C7240100A9DF31 /* RKSearchTokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKSearchTokenizer.h; sourceTree = "<group>"; };
|
||||
25A763DA15C7240100A9DF31 /* RKSearchTokenizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKSearchTokenizer.m; sourceTree = "<group>"; };
|
||||
25A763E015C72B9D00A9DF31 /* RKSearchTokenizerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKSearchTokenizerTest.m; sourceTree = "<group>"; };
|
||||
@@ -1447,6 +1453,7 @@
|
||||
251610081456F2330060A5C5 /* RKParent.m */,
|
||||
251610091456F2330060A5C5 /* RKResident.h */,
|
||||
2516100A1456F2330060A5C5 /* RKResident.m */,
|
||||
25A73360169C8C230090A930 /* VersionedModel.xcdatamodeld */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
@@ -2372,6 +2379,7 @@
|
||||
2551338F167838590017E4B6 /* RKHTTPRequestOperationTest.m in Sources */,
|
||||
255133CF167AC7600017E4B6 /* RKManagedObjectRequestOperationTest.m in Sources */,
|
||||
25B639CC16961EFA0065EB7B /* RKMappingTestTest.m in Sources */,
|
||||
25A73362169C8C230090A930 /* VersionedModel.xcdatamodeld in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -2523,6 +2531,7 @@
|
||||
2536D1FE167270F100DF9BB0 /* RKRouterTest.m in Sources */,
|
||||
25513390167838590017E4B6 /* RKHTTPRequestOperationTest.m in Sources */,
|
||||
25B639CD16961EFA0065EB7B /* RKMappingTestTest.m in Sources */,
|
||||
25A73363169C8C230090A930 /* VersionedModel.xcdatamodeld in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -2835,6 +2844,22 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCVersionGroup section */
|
||||
25A73360169C8C230090A930 /* VersionedModel.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
children = (
|
||||
25A73365169C8CD80090A930 /* VersionedModel 2.xcdatamodel */,
|
||||
25A73366169C8CF30090A930 /* VersionedModel 3.xcdatamodel */,
|
||||
25A73367169C8D500090A930 /* VersionedModel 4.xcdatamodel */,
|
||||
25A73361169C8C230090A930 /* VersionedModel.xcdatamodel */,
|
||||
);
|
||||
currentVersion = 25A73367169C8D500090A930 /* VersionedModel 4.xcdatamodel */;
|
||||
path = VersionedModel.xcdatamodeld;
|
||||
sourceTree = "<group>";
|
||||
versionGroupType = wrapper.xcdatamodel;
|
||||
};
|
||||
/* End XCVersionGroup section */
|
||||
};
|
||||
rootObject = 25160D0D14564E810060A5C5 /* Project object */;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,21 @@
|
||||
#import "RKTestEnvironment.h"
|
||||
#import "RKHuman.h"
|
||||
#import "RKPathUtilities.h"
|
||||
#import "RKSearchIndexer.h"
|
||||
|
||||
// TODO: Does this become `RKManagedObjectStore managedObjectModelWithName:version:inBundle:` ??? URLForManagedObjectModel
|
||||
static NSURL *RKURLForManagedObjectModelWithNameAtVersion(NSString *modelName, NSUInteger version)
|
||||
{
|
||||
NSString *modelNameAndVersion = (version == 1) ? modelName : [NSString stringWithFormat:@"%@ %ld", modelName, (unsigned long) version];
|
||||
return [[RKTestFixture fixtureBundle] URLForResource:[NSString stringWithFormat:@"%@.momd/%@", modelName, modelNameAndVersion] withExtension:@"mom"];
|
||||
}
|
||||
|
||||
static NSManagedObjectModel *RKManagedObjectModelWithNameAtVersion(NSString *modelName, NSUInteger version)
|
||||
{
|
||||
NSURL *URL = RKURLForManagedObjectModelWithNameAtVersion(modelName, version);
|
||||
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:URL];
|
||||
return model;
|
||||
}
|
||||
|
||||
@interface RKManagedObjectStoreTest : RKTestCase
|
||||
|
||||
@@ -52,7 +67,9 @@
|
||||
- (void)testAdditionOfSQLiteStoreRetainsPathOfSeedDatabase
|
||||
{
|
||||
// Create a store with a SQLite database to use as our store
|
||||
RKManagedObjectStore *seedStore = [[RKManagedObjectStore alloc] init];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||
RKManagedObjectStore *seedStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSString *seedPath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Seed.sqlite"];
|
||||
NSError *error;
|
||||
NSPersistentStore *persistentStore = [seedStore addSQLitePersistentStoreAtPath:seedPath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
||||
@@ -61,7 +78,7 @@
|
||||
expect(fileExists).to.beTruthy();
|
||||
|
||||
// Create a secondary store using the seed
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] init];
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Test.sqlite"];
|
||||
persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
|
||||
expect(persistentStore).notTo.beNil();
|
||||
@@ -77,7 +94,9 @@
|
||||
- (void)testAddingPersistentSQLiteStoreFromSeedDatabase
|
||||
{
|
||||
// Create a store with an object to serve as our seed database
|
||||
RKManagedObjectStore *seedStore = [[RKManagedObjectStore alloc] init];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||
RKManagedObjectStore *seedStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSError *error;
|
||||
NSString *seedPath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Seed.sqlite"];
|
||||
NSPersistentStore *seedPersistentStore = [seedStore addSQLitePersistentStoreAtPath:seedPath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
||||
@@ -91,7 +110,7 @@
|
||||
|
||||
// Create a secondary store using the first store as the seed
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"SeededStore.sqlite"];
|
||||
RKManagedObjectStore *seededStore = [[RKManagedObjectStore alloc] init];
|
||||
RKManagedObjectStore *seededStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSPersistentStore *persistentStore = [seededStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
|
||||
assertThat(persistentStore, is(notNilValue()));
|
||||
[seededStore createManagedObjectContexts];
|
||||
@@ -107,7 +126,9 @@
|
||||
|
||||
- (void)testResetPersistentStoresRecreatesInMemoryStoreThusDeletingAllManagedObjects
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] init];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSError *error;
|
||||
NSPersistentStore *persistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
|
||||
assertThat(persistentStore, is(notNilValue()));
|
||||
@@ -136,7 +157,9 @@
|
||||
|
||||
- (void)testResetPersistentStoresRecreatesSQLiteStoreThusDeletingAllManagedObjects
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] init];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSError *error;
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Test.sqlite"];
|
||||
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
||||
@@ -163,7 +186,9 @@
|
||||
|
||||
- (void)testResetPersistentStoreRecreatesSQLiteStoreThusRecreatingTheStoreFileOnDisk
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] init];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSError *error;
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Test.sqlite"];
|
||||
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
||||
@@ -192,7 +217,9 @@
|
||||
- (void)testResetPersistentStoreForSQLiteStoreSeededWithDatabaseReclonesTheSeedDatabaseToTheStoreLocation
|
||||
{
|
||||
// Create a store with an object to serve as our seed database
|
||||
RKManagedObjectStore *seedStore = [[RKManagedObjectStore alloc] init];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||
RKManagedObjectStore *seedStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSError *error;
|
||||
NSString *seedPath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Seed.sqlite"];
|
||||
NSPersistentStore *seedPersistentStore = [seedStore addSQLitePersistentStoreAtPath:seedPath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
||||
@@ -206,7 +233,7 @@
|
||||
|
||||
// Create a secondary store using the first store as the seed
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"SeededStore.sqlite"];
|
||||
RKManagedObjectStore *seededStore = [[RKManagedObjectStore alloc] init];
|
||||
RKManagedObjectStore *seededStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSPersistentStore *persistentStore = [seededStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
|
||||
assertThat(persistentStore, is(notNilValue()));
|
||||
[seededStore createManagedObjectContexts];
|
||||
@@ -239,7 +266,9 @@
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
- (void)testThatAddingASQLiteStoreExcludesThePathFromiCloudBackups
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] init];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSError *error;
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestBackupExclusion.sqlite"];
|
||||
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
||||
@@ -273,7 +302,9 @@
|
||||
|
||||
- (void)testCleanupOfExternalStorageDirectoryOnReset
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] init];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSEntityDescription *humanEntity = [managedObjectStore.managedObjectModel entitiesByName][@"Human"];
|
||||
NSAttributeDescription *photoAttribute = [[NSAttributeDescription alloc] init];
|
||||
[photoAttribute setName:@"photo"];
|
||||
@@ -310,7 +341,9 @@
|
||||
- (void)testThatPersistentStoreWithLongNameHasExternalStorageResetCorrectly
|
||||
{
|
||||
// Create a store with an object to serve as our seed database
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] init];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSError *error = nil;
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"This is the Store.sqlite"];
|
||||
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
||||
@@ -337,4 +370,197 @@
|
||||
expect([creationDate laterDate:newCreationDate]).to.equal(newCreationDate);
|
||||
}
|
||||
|
||||
#pragma mark - Versioning Tests
|
||||
|
||||
- (void)testThatAttemptToMigrateStoreAtNonExistantFileURLReturnsError
|
||||
{
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"NonExistantStore.sqlite"];
|
||||
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
||||
NSError *error = nil;
|
||||
NSURL *modelURL = RKURLForManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
||||
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:nil];
|
||||
expect(success).to.equal(NO);
|
||||
expect(error.code).to.equal(0);
|
||||
}
|
||||
|
||||
- (void)testThatAttemptingToMigrateToANonVersionedModelReturnsError
|
||||
{
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
NSManagedObjectModel *model_v1 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v1];
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
||||
NSError *error = nil;
|
||||
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
||||
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
||||
[managedObjectStore createManagedObjectContexts];
|
||||
managedObjectStore = nil;
|
||||
|
||||
// Attempting to update to `modelURL` will fail because this is an unversioned model
|
||||
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
||||
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:nil];
|
||||
expect(success).to.equal(NO);
|
||||
expect(error).notTo.beNil();
|
||||
expect(error.code).to.equal(NSMigrationError);
|
||||
assertThat([error localizedDescription], startsWith(@"Migration failed: Migrations can only be performed to versioned destination models contained in a .momd package. Incompatible destination model given at path"));
|
||||
}
|
||||
|
||||
- (void)testThatAttemptingToMigrateFromAnUnidentifiableSourceModelReturnsError
|
||||
{
|
||||
NSManagedObjectModel *model_v1 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
||||
NSEntityDescription *extraEntity = [NSEntityDescription new];
|
||||
[extraEntity setName:@"Extra"];
|
||||
[model_v1 setEntities:[[model_v1 entities] arrayByAddingObject:extraEntity]];
|
||||
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v1];
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
||||
NSError *error = nil;
|
||||
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
||||
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
||||
[managedObjectStore createManagedObjectContexts];
|
||||
managedObjectStore = nil;
|
||||
|
||||
// Attempting to upgrade to v2 returns NO, because it can't find the source model (due to the added entity)
|
||||
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
||||
NSURL *modelURL = RKURLForManagedObjectModelWithNameAtVersion(@"VersionedModel", 2);
|
||||
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:nil];
|
||||
expect(success).to.equal(NO);
|
||||
expect(error).notTo.beNil();
|
||||
expect(error.code).to.equal(NSMigrationMissingSourceModelError);
|
||||
assertThat([error localizedDescription], startsWith(@"Migration failed: Unable to find the source managed object model used to create the SQLite store at path"));
|
||||
}
|
||||
|
||||
- (void)testMigrationToCompatibleVersionReturnsYes
|
||||
{
|
||||
NSManagedObjectModel *model_v1 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v1];
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
||||
NSError *error = nil;
|
||||
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
||||
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
||||
[managedObjectStore createManagedObjectContexts];
|
||||
managedObjectStore = nil;
|
||||
|
||||
// Attempting to upgrade to v1 returns YES, because its already compatible
|
||||
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
||||
NSURL *modelURL = RKURLForManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
||||
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:nil];
|
||||
expect(success).to.equal(YES);
|
||||
expect(error).to.beNil();
|
||||
}
|
||||
|
||||
- (void)testUpgradingFromVersionedModelAt1_0to2_0
|
||||
{
|
||||
// Create a v1 Store
|
||||
NSManagedObjectModel *model_v1 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v1];
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
||||
NSError *error = nil;
|
||||
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
||||
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
||||
[managedObjectStore createManagedObjectContexts];
|
||||
managedObjectStore = nil;
|
||||
|
||||
// Now upgrade it to v2
|
||||
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
||||
NSURL *modelURL = RKURLForManagedObjectModelWithNameAtVersion(@"VersionedModel", 2);
|
||||
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:nil];
|
||||
expect(success).to.equal(YES);
|
||||
expect(error).to.beNil();
|
||||
}
|
||||
|
||||
- (void)testUpgradingFromVersionedModelAt1_0to_4_0
|
||||
{
|
||||
// Create a v1 Store
|
||||
NSManagedObjectModel *model_v1 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v1];
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
||||
NSError *error = nil;
|
||||
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
||||
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
||||
[managedObjectStore createManagedObjectContexts];
|
||||
managedObjectStore = nil;
|
||||
|
||||
// Now upgrade it to v4
|
||||
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
||||
NSURL *modelURL = RKURLForManagedObjectModelWithNameAtVersion(@"VersionedModel", 4);
|
||||
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:nil];
|
||||
expect(success).to.equal(YES);
|
||||
expect(error).to.beNil();
|
||||
}
|
||||
|
||||
- (void)testUpgradingFromVersionedModelWithSearchAttributesAt2_0to_3_0
|
||||
{
|
||||
// Create a v2 Store
|
||||
NSManagedObjectModel *model_v2 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 2);
|
||||
|
||||
// Add search indexing on the title attribute
|
||||
NSEntityDescription *articleEntity = [[model_v2 entitiesByName] objectForKey:@"Article"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title" ]];
|
||||
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v2];
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
||||
NSError *error = nil;
|
||||
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
||||
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
||||
[managedObjectStore createManagedObjectContexts];
|
||||
managedObjectStore = nil;
|
||||
|
||||
// Now upgrade it to v3
|
||||
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
||||
NSURL *modelURL = RKURLForManagedObjectModelWithNameAtVersion(@"VersionedModel", 4);
|
||||
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:^(NSManagedObjectModel *model, NSURL *sourceURL) {
|
||||
if ([[model versionIdentifiers] isEqualToSet:[NSSet setWithObject:@"2.0"]]) {
|
||||
NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title" ]];
|
||||
}
|
||||
}];
|
||||
expect(success).to.equal(YES);
|
||||
expect(error).to.beNil();
|
||||
}
|
||||
|
||||
- (void)testUpgradingFromVersionedModelWithSearchAttributesAt_1_0toLatest
|
||||
{
|
||||
// Create a v1 Store
|
||||
NSManagedObjectModel *model_v1 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
||||
|
||||
// Add search indexing on the title attribute
|
||||
NSEntityDescription *articleEntity = [[model_v1 entitiesByName] objectForKey:@"Article"];
|
||||
NSEntityDescription *tagEntity = [[model_v1 entitiesByName] objectForKey:@"Tag"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title" ]];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]];
|
||||
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v1];
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
||||
NSError *error = nil;
|
||||
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
||||
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
||||
[managedObjectStore createManagedObjectContexts];
|
||||
managedObjectStore = nil;
|
||||
|
||||
// Now upgrade it to the latest version
|
||||
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"VersionedModel" withExtension:@"momd"];
|
||||
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:^(NSManagedObjectModel *model, NSURL *sourceURL) {
|
||||
if ([[model versionIdentifiers] isEqualToSet:[NSSet setWithObject:@"1.0"]]) {
|
||||
NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"];
|
||||
NSEntityDescription *tagEntity = [[model entitiesByName] objectForKey:@"Tag"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title" ]];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]];
|
||||
} else if ([[model versionIdentifiers] isEqualToSet:[NSSet setWithObject:@"2.0"]]) {
|
||||
NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"];
|
||||
NSEntityDescription *tagEntity = [[model entitiesByName] objectForKey:@"Tag"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title", @"body" ]];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]];
|
||||
} else if ([[model versionIdentifiers] containsObject:@"3.0"] || [[model versionIdentifiers] containsObject:@"4.0"]) {
|
||||
// We index the same attributes on v3 and v4
|
||||
NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"];
|
||||
NSEntityDescription *tagEntity = [[model entitiesByName] objectForKey:@"Tag"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title", @"body", @"authorName" ]];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]];
|
||||
}
|
||||
}];
|
||||
expect(success).to.equal(YES);
|
||||
expect(error).to.beNil();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -14,6 +14,12 @@
|
||||
@property (nonatomic, strong) NSOperationQueue *operationQueue;
|
||||
@end
|
||||
|
||||
static NSManagedObjectModel *RKManagedObjectModel()
|
||||
{
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
return [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||
}
|
||||
|
||||
@interface RKSearchIndexerTest : RKTestCase
|
||||
|
||||
@end
|
||||
@@ -22,7 +28,7 @@
|
||||
|
||||
- (void)testAddingSearchIndexingToEntity
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
NSEntityDescription *searchWordEntity = [managedObjectModel.entitiesByName objectForKey:@"RKSearchWord"];
|
||||
assertThat(searchWordEntity, is(nilValue()));
|
||||
@@ -49,7 +55,7 @@
|
||||
|
||||
- (void)testAddingSearchIndexingToEntityWithMixtureOfNSAttributeDescriptionAndStringNames
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
NSEntityDescription *searchWordEntity = [managedObjectModel.entitiesByName objectForKey:@"RKSearchWord"];
|
||||
assertThat(searchWordEntity, is(nilValue()));
|
||||
@@ -77,7 +83,7 @@
|
||||
|
||||
- (void)testAddingSearchIndexingToNonStringAttributeTypeRaisesException
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
NSEntityDescription *searchWordEntity = [managedObjectModel.entitiesByName objectForKey:@"RKSearchWord"];
|
||||
assertThat(searchWordEntity, is(nilValue()));
|
||||
@@ -97,7 +103,7 @@
|
||||
|
||||
- (void)testAddingSearchIndexingToNonExistantAttributeRaisesException
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
NSEntityDescription *searchWordEntity = [managedObjectModel.entitiesByName objectForKey:@"RKSearchWord"];
|
||||
assertThat(searchWordEntity, is(nilValue()));
|
||||
@@ -117,7 +123,7 @@
|
||||
|
||||
- (void)testAddingSearchIndexingToTwoEntitiesManipulatesTheSameSearchWordEntity
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *humanEntity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
NSEntityDescription *catEntity = [[managedObjectModel entitiesByName] objectForKey:@"Cat"];
|
||||
|
||||
@@ -136,7 +142,7 @@
|
||||
|
||||
- (void)testIndexingManagedObject
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:entity onAttributes:@[ @"name", @"nickName" ]];
|
||||
|
||||
@@ -161,7 +167,7 @@
|
||||
|
||||
- (void)testIndexingManagedObjectUsingIndexingContext
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:entity onAttributes:@[ @"name", @"nickName" ]];
|
||||
|
||||
@@ -195,7 +201,7 @@
|
||||
|
||||
- (void)testIndexingOnManagedObjectContextSave
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:entity onAttributes:@[ @"name", @"nickName" ]];
|
||||
|
||||
@@ -223,7 +229,7 @@
|
||||
|
||||
- (void)testIndexingOnManagedObjectContextSaveUsingIndexingContext
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:entity onAttributes:@[ @"name", @"nickName" ]];
|
||||
|
||||
@@ -268,7 +274,7 @@
|
||||
|
||||
- (void)testIndexingChangesInManagedObjectContextWithoutSave
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:entity onAttributes:@[ @"name", @"nickName" ]];
|
||||
|
||||
@@ -294,7 +300,7 @@
|
||||
|
||||
- (void)testIndexingChangesInManagedObjectContextWithoutSaveUsingIndexingContext
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:entity onAttributes:@[ @"name", @"nickName" ]];
|
||||
|
||||
@@ -328,7 +334,7 @@
|
||||
|
||||
- (void)testCancellationOfIndexingInAnIndexingContext
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:entity onAttributes:@[ @"name", @"nickName" ]];
|
||||
|
||||
@@ -370,7 +376,7 @@
|
||||
|
||||
- (void)testThatDelegateCanDenyCreationOfSearchWordForWord
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:entity onAttributes:@[ @"name", @"nickName" ]];
|
||||
|
||||
@@ -403,7 +409,7 @@
|
||||
|
||||
- (void)testThatDelegateIsInformedWhenSearchWordIsCreated
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:entity onAttributes:@[ @"name", @"nickName" ]];
|
||||
|
||||
@@ -432,7 +438,7 @@
|
||||
|
||||
- (void)testThatDelegateCanBeUsedToFetchExistingSearchWords
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:entity onAttributes:@[ @"name", @"nickName" ]];
|
||||
|
||||
@@ -463,7 +469,7 @@
|
||||
|
||||
- (void)testThatTheDelegateCanDeclineIndexingOfAnObject
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:entity onAttributes:@[ @"name", @"nickName" ]];
|
||||
|
||||
@@ -490,7 +496,7 @@
|
||||
|
||||
- (void)testThatTheDelegateIsNotifiedAfterIndexingHasCompleted
|
||||
{
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSManagedObjectModel *managedObjectModel = RKManagedObjectModel();
|
||||
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:@"Human"];
|
||||
[RKSearchIndexer addSearchIndexingToEntity:entity onAttributes:@[ @"name", @"nickName" ]];
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
- (void)testSearchingForManagedObjects
|
||||
{
|
||||
__block NSError *error;
|
||||
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
NSManagedObjectModel *managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
|
||||
[managedObjectStore addSearchIndexingToEntityForName:@"Cat" onAttributes:@[ @"name" ]];
|
||||
[managedObjectStore addInMemoryPersistentStore:&error];
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>_XCCurrentVersionName</key>
|
||||
<string>VersionedModel 4.xcdatamodel</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model name="" userDefinedModelVersionIdentifier="2.0" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="12C60" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<entity name="Article" syncable="YES">
|
||||
<attribute name="authorName" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="body" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
|
||||
</entity>
|
||||
<entity name="Tag" syncable="YES">
|
||||
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Article" positionX="160" positionY="192" width="128" height="90"/>
|
||||
<element name="Tag" positionX="160" positionY="192" width="128" height="60"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model name="" userDefinedModelVersionIdentifier="3.0" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="12C60" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<entity name="Article" syncable="YES">
|
||||
<attribute name="authorName" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="body" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="createdAt" optional="YES" attributeType="Date" syncable="YES"/>
|
||||
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
|
||||
</entity>
|
||||
<entity name="Tag" syncable="YES">
|
||||
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Article" positionX="160" positionY="192" width="128" height="105"/>
|
||||
<element name="Tag" positionX="160" positionY="192" width="128" height="60"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model name="" userDefinedModelVersionIdentifier="4.0" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="12C60" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<entity name="Article" syncable="YES">
|
||||
<attribute name="authorName" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="body" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
|
||||
</entity>
|
||||
<entity name="Tag" syncable="YES">
|
||||
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Article" positionX="160" positionY="192" width="128" height="90"/>
|
||||
<element name="Tag" positionX="160" positionY="192" width="128" height="60"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model name="" userDefinedModelVersionIdentifier="1.0" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="12C60" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<entity name="Article" syncable="YES">
|
||||
<attribute name="body" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
|
||||
</entity>
|
||||
<entity name="Tag" syncable="YES">
|
||||
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Article" positionX="160" positionY="192" width="128" height="75"/>
|
||||
<element name="Tag" positionX="160" positionY="192" width="128" height="60"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -47,6 +47,24 @@
|
||||
|
||||
// Configure logging from the environment variable. See RKLog.h for details
|
||||
RKLogConfigureFromEnvironment();
|
||||
|
||||
// Configure the Test Factory to use a specific model file
|
||||
[RKTestFactory defineFactory:RKTestFactoryDefaultNamesManagedObjectStore withBlock:^id {
|
||||
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:RKTestFactoryDefaultStoreFilename];
|
||||
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
||||
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
||||
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
||||
NSError *error;
|
||||
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
||||
if (persistentStore) {
|
||||
BOOL success = [managedObjectStore resetPersistentStores:&error];
|
||||
if (! success) {
|
||||
RKLogError(@"Failed to reset persistent store: %@", error);
|
||||
}
|
||||
}
|
||||
|
||||
return managedObjectStore;
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user