WIP: custom migration

This commit is contained in:
John Rommel Estropia
2017-05-09 03:10:35 +09:00
parent 6d04806608
commit 9d65a27557
37 changed files with 1642 additions and 588 deletions

View File

@@ -81,22 +81,7 @@ public extension CoreStore {
@discardableResult
public static func addStorageAndWait() throws -> SQLiteStore {
return try self.defaultStack.addStorageAndWait(SQLiteStore.self)
}
/**
Creates a `StorageInterface` of the specified store type with default values and adds it to the `defaultStack`. This method blocks until completion.
```
try CoreStore.addStorageAndWait(InMemoryStore.self)
```
- parameter storeType: the `StorageInterface` type
- throws: a `CoreStoreError` value indicating the failure
- returns: the `StorageInterface` added to the `defaultStack`
*/
@discardableResult
public static func addStorageAndWait<T: StorageInterface>(_ storeType: T.Type) throws -> T where T: DefaultInitializableStore {
return try self.defaultStack.addStorageAndWait(storeType.init())
return try self.defaultStack.addStorageAndWait(SQLiteStore())
}
/**
@@ -114,21 +99,6 @@ public extension CoreStore {
return try self.defaultStack.addStorageAndWait(storage)
}
/**
Creates a `LocalStorageInterface` of the specified store type with default values and adds it to the `defaultStack`. This method blocks until completion.
```
try CoreStore.addStorageAndWait(SQLiteStore.self)
```
- parameter storeType: the `LocalStorageInterface` type
- throws: a `CoreStoreError` value indicating the failure
- returns: the local storage added to the `defaultStack`
*/
@discardableResult
public static func addStorageAndWait<T: LocalStorage>(_ storageType: T.Type) throws -> T where T: DefaultInitializableStore {
return try self.defaultStack.addStorageAndWait(storageType.init())
}
/**
Adds a `LocalStorage` to the `defaultStack` and blocks until completion.
```

View File

@@ -142,7 +142,7 @@ public final class DataStack: Equatable {
continue
case .coreStore:
guard let anyEntity = entityDescription.anyEntity else {
guard let anyEntity = entityDescription.coreStoreEntity else {
continue
}
@@ -191,22 +191,7 @@ public final class DataStack: Equatable {
@discardableResult
public func addStorageAndWait() throws -> SQLiteStore {
return try self.addStorageAndWait(SQLiteStore.self)
}
/**
Creates a `StorageInterface` of the specified store type with default values and adds it to the stack. This method blocks until completion.
```
try dataStack.addStorageAndWait(InMemoryStore.self)
```
- parameter storeType: the `StorageInterface` type
- throws: a `CoreStoreError` value indicating the failure
- returns: the `StorageInterface` added to the stack
*/
@discardableResult
public func addStorageAndWait<T: StorageInterface>(_ storeType: T.Type) throws -> T where T: DefaultInitializableStore {
return try self.addStorageAndWait(storeType.init())
return try self.addStorageAndWait(SQLiteStore())
}
/**
@@ -248,21 +233,6 @@ public final class DataStack: Equatable {
}
}
/**
Creates a `LocalStorageInterface` of the specified store type with default values and adds it to the stack. This method blocks until completion.
```
try dataStack.addStorageAndWait(SQLiteStore.self)
```
- parameter storeType: the `LocalStorageInterface` type
- throws: a `CoreStoreError` value indicating the failure
- returns: the local storage added to the stack
*/
@discardableResult
public func addStorageAndWait<T: LocalStorage>(_ storageType: T.Type) throws -> T where T: DefaultInitializableStore {
return try self.addStorageAndWait(storageType.init())
}
/**
Adds a `LocalStorage` to the stack and blocks until completion.
```

View File

@@ -203,7 +203,7 @@ public final class CoreStoreSchema: DynamicSchema {
private static func firstPassCreateEntityDescription(from entity: AnyEntity) -> NSEntityDescription {
let entityDescription = NSEntityDescription()
entityDescription.anyEntity = entity
entityDescription.coreStoreEntity = entity
entityDescription.name = entity.entityName
entityDescription.isAbstract = entity.isAbstract
entityDescription.managedObjectClassName = NSStringFromClass(NSManagedObject.self)

View File

@@ -223,6 +223,11 @@ public final class SchemaHistory: ExpressibleByArrayLiteral {
return self.schemaByVersion[modelVersion]?.rawModel()
}
internal func schema(for modelVersion: ModelVersion) -> DynamicSchema? {
return self.schemaByVersion[modelVersion]
}
internal func schema(for storeMetadata: [String: Any]) -> DynamicSchema? {
guard let modelHashes = storeMetadata[NSStoreModelVersionHashesKey] as! [String: Data]? else {

View File

@@ -31,7 +31,7 @@ import CoreData
/**
A storage interface that is backed only by memory.
*/
public final class InMemoryStore: StorageInterface, DefaultInitializableStore {
public final class InMemoryStore: StorageInterface {
/**
Initializes an `InMemoryStore` for the specified configuration
@@ -42,9 +42,6 @@ public final class InMemoryStore: StorageInterface, DefaultInitializableStore {
self.configuration = configuration
}
// MARK: DefaultInitializableStore
/**
Initializes an `InMemoryStore` with the "Default" configuration
*/

View File

@@ -34,7 +34,8 @@ import CoreData
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`.
*/
public final class LegacySQLiteStore: LocalStorage, DefaultInitializableStore {
@available(*, obsoleted: 3.1, message: "`LegacySQLiteStore` previous users should now use `SQLiteStore`'s new SQLiteStore.legacy(fileName:configuration:migrationMappingProviders:localStorageOptions:) or SQLiteStore.legacy() methods to create an `SQLiteStore` with legacy paths.")
public final class LegacySQLiteStore: LocalStorage {
/**
Initializes an SQLite store interface from the given SQLite file URL. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
@@ -44,12 +45,10 @@ public final class LegacySQLiteStore: LocalStorage, DefaultInitializableStore {
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models for migration.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/
@available(*, obsoleted: 3.1, message: "Use `SQLiteStore`'s new SQLiteStore.init(fileURL:configuration:migrationMappingProviders:localStorageOptions:) initializer")
public init(fileURL: URL, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) {
self.fileURL = fileURL
self.configuration = configuration
self.mappingModelBundles = mappingModelBundles
self.localStorageOptions = localStorageOptions
fatalError()
}
/**
@@ -61,31 +60,21 @@ public final class LegacySQLiteStore: LocalStorage, DefaultInitializableStore {
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models for migration.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/
@available(*, obsoleted: 3.1, message: "Use `SQLiteStore`'s new SQLiteStore.legacy(fileName:configuration:migrationMappingProviders:localStorageOptions:) method.")
public init(fileName: String, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) {
self.fileURL = LegacySQLiteStore.defaultRootDirectory.appendingPathComponent(
fileName,
isDirectory: false
)
self.configuration = configuration
self.mappingModelBundles = mappingModelBundles
self.localStorageOptions = localStorageOptions
fatalError()
}
// MARK: DefaultInitializableStore
/**
Initializes an `LegacySQLiteStore` with an all-default settings: a `fileURL` pointing to a "<Application name>.sqlite" file in the "Application Support" directory (or the "Caches" directory on tvOS), a `nil` `configuration` pertaining to the "Default" configuration, a `mappingModelBundles` set to search all `NSBundle`s, and `localStorageOptions` set to `.AllowProgresiveMigration`.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`.
*/
@available(*, obsoleted: 3.1, message: "Use `SQLiteStore`'s new SQLiteStore.legacy() method.")
public init() {
self.fileURL = LegacySQLiteStore.defaultFileURL
self.configuration = nil
self.mappingModelBundles = Bundle.allBundles
self.localStorageOptions = nil
fatalError()
}
@@ -153,9 +142,9 @@ public final class LegacySQLiteStore: LocalStorage, DefaultInitializableStore {
public let fileURL: URL
/**
The `NSBundle`s from which to search mapping models for migrations
An array of `SchemaMappingProviders` that provides the complete mapping models for custom migrations.
*/
public let mappingModelBundles: [Bundle]
public let migrationMappingProviders: [SchemaMappingProvider]
/**
Options that tell the `DataStack` how to setup the persistent store
@@ -231,26 +220,6 @@ public final class LegacySQLiteStore: LocalStorage, DefaultInitializableStore {
}
// MARK: Internal
internal static let defaultRootDirectory: URL = cs_lazy {
#if os(tvOS)
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
#else
let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
#endif
return FileManager.default.urls(
for: systemDirectorySearchPath,
in: .userDomainMask).first!
}
internal static let defaultFileURL = LegacySQLiteStore.defaultRootDirectory
.appendingPathComponent(DataStack.applicationName, isDirectory: false)
.appendingPathExtension("sqlite")
// MARK: Private
private weak var dataStack: DataStack?

View File

@@ -33,21 +33,21 @@ import CoreData
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`.
*/
public final class SQLiteStore: LocalStorage, DefaultInitializableStore {
public final class SQLiteStore: LocalStorage {
/**
Initializes an SQLite store interface from the given SQLite file URL. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
- parameter fileURL: the local file URL for the target SQLite persistent store. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models (*.xcmappingmodel) for migration.
- parameter migrationMappingProviders: An array of `SchemaMappingProviders` that provides the complete mapping models for custom migrations. All lightweight inferred mappings and/or migration mappings provided by *xcmappingmodel files are automatically used as fallback (as `InferredSchemaMappingProvider`) and may be omitted from the array.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/
public init(fileURL: URL, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) {
public init(fileURL: URL, configuration: ModelConfiguration = nil, migrationMappingProviders: [SchemaMappingProvider] = [], localStorageOptions: LocalStorageOptions = nil) {
self.fileURL = fileURL
self.configuration = configuration
self.mappingModelBundles = mappingModelBundles
self.migrationMappingProviders = migrationMappingProviders
self.localStorageOptions = localStorageOptions
}
@@ -57,21 +57,18 @@ public final class SQLiteStore: LocalStorage, DefaultInitializableStore {
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`.
- parameter fileName: the local filename for the SQLite persistent store in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models (*.xcmappingmodel) for migration
- parameter migrationMappingProviders: An array of `SchemaMappingProviders` that provides the complete mapping models for custom migrations. All lightweight inferred mappings and/or migration mappings provided by *xcmappingmodel files are automatically used as fallback (as `InferredSchemaMappingProvider`) and may be omitted from the array.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/
public init(fileName: String, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) {
public init(fileName: String, configuration: ModelConfiguration = nil, migrationMappingProviders: [SchemaMappingProvider] = [], localStorageOptions: LocalStorageOptions = nil) {
self.fileURL = SQLiteStore.defaultRootDirectory
.appendingPathComponent(fileName, isDirectory: false)
self.configuration = configuration
self.mappingModelBundles = mappingModelBundles
self.migrationMappingProviders = migrationMappingProviders
self.localStorageOptions = localStorageOptions
}
// MARK: DefaultInitializableStore
/**
Initializes an `SQLiteStore` with an all-default settings: a `fileURL` pointing to a "<Application name>.sqlite" file in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS), a `nil` `configuration` pertaining to the "Default" configuration, a `mappingModelBundles` set to search all `NSBundle`s, and `localStorageOptions` set to `.AllowProgresiveMigration`.
@@ -81,10 +78,45 @@ public final class SQLiteStore: LocalStorage, DefaultInitializableStore {
self.fileURL = SQLiteStore.defaultFileURL
self.configuration = nil
self.mappingModelBundles = Bundle.allBundles
self.migrationMappingProviders = []
self.localStorageOptions = nil
}
/**
Initializes an SQLite store interface from the given SQLite file name. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`.
- parameter legacyFileName: the local filename for the SQLite persistent store in the "Application Support" directory (or the "Caches" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter migrationMappingProviders: An array of `SchemaMappingProviders` that provides the complete mapping models for custom migrations. All lightweight inferred mappings and/or migration mappings provided by *xcmappingmodel files are automatically used as fallback (as `InferredSchemaMappingProvider`) and may be omitted from the array.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/
public static func legacy(fileName: String, configuration: ModelConfiguration = nil, migrationMappingProviders: [SchemaMappingProvider] = [], localStorageOptions: LocalStorageOptions = nil) -> SQLiteStore {
return SQLiteStore(
fileURL: SQLiteStore.legacyDefaultRootDirectory
.appendingPathComponent(fileName, isDirectory: false),
configuration: configuration,
migrationMappingProviders: migrationMappingProviders,
localStorageOptions: localStorageOptions
)
}
/**
Initializes an `LegacySQLiteStore` with an all-default settings: a `fileURL` pointing to a "<Application name>.sqlite" file in the "Application Support" directory (or the "Caches" directory on tvOS), a `nil` `configuration` pertaining to the "Default" configuration, a `mappingModelBundles` set to search all `NSBundle`s, and `localStorageOptions` set to `.AllowProgresiveMigration`.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`.
*/
public static func legacy() -> SQLiteStore {
return SQLiteStore(
fileURL: SQLiteStore.legacyDefaultFileURL,
configuration: nil,
migrationMappingProviders: [],
localStorageOptions: nil
)
}
// MARK: StorageInterface
@@ -131,9 +163,9 @@ public final class SQLiteStore: LocalStorage, DefaultInitializableStore {
public let fileURL: URL
/**
The `NSBundle`s from which to search mapping models for migrations
An array of `SchemaMappingProviders` that provides the complete mapping models for custom migrations.
*/
public let mappingModelBundles: [Bundle]
public let migrationMappingProviders: [SchemaMappingProvider]
/**
Options that tell the `DataStack` how to setup the persistent store
@@ -255,8 +287,60 @@ public final class SQLiteStore: LocalStorage, DefaultInitializableStore {
)
.appendingPathExtension("sqlite")
internal static let legacyDefaultRootDirectory: URL = cs_lazy {
#if os(tvOS)
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
#else
let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
#endif
return FileManager.default.urls(
for: systemDirectorySearchPath,
in: .userDomainMask).first!
}
internal static let legacyDefaultFileURL = cs_lazy {
return SQLiteStore.legacyDefaultRootDirectory
.appendingPathComponent(DataStack.applicationName, isDirectory: false)
.appendingPathExtension("sqlite")
}
// MARK: Private
private weak var dataStack: DataStack?
// MARK: Deprecated
/**
Initializes an SQLite store interface from the given SQLite file URL. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
- parameter fileURL: the local file URL for the target SQLite persistent store. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models (*.xcmappingmodel) for migration.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/
@available(*, deprecated: 3.1, message: "The `mappingModelBundles` argument of this method is ignored. Use the new SQLiteStore.init(fileURL:configuration:migrationMappingProviders:localStorageOptions:) initializer instead.")
public convenience init(fileURL: URL, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle], localStorageOptions: LocalStorageOptions = nil) {
self.init(fileURL: fileURL, configuration: configuration, migrationMappingProviders: [], localStorageOptions: localStorageOptions)
}
/**
Initializes an SQLite store interface from the given SQLite file name. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`.
- parameter fileName: the local filename for the SQLite persistent store in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models (*.xcmappingmodel) for migration.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/
@available(*, deprecated: 3.1, message: "The `mappingModelBundles` argument of this method is ignored. Use the new SQLiteStore.init(fileName:configuration:migrationMappingProviders:localStorageOptions:) initializer instead.")
public convenience init(fileName: String, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle], localStorageOptions: LocalStorageOptions = nil) {
self.init(fileName: fileName, configuration: configuration, migrationMappingProviders: [], localStorageOptions: localStorageOptions)
}
}

View File

@@ -63,20 +63,6 @@ public protocol StorageInterface: class {
}
// MARK: - DefaultInitializableStore
/**
The `DefaultInitializableStore` represents `StorageInterface`s that can be initialized with default values
*/
public protocol DefaultInitializableStore: StorageInterface {
/**
Initializes the `StorageInterface` with the default configurations
*/
init()
}
// MARK: - LocalStorageOptions
/**
@@ -141,9 +127,9 @@ public protocol LocalStorage: StorageInterface {
var fileURL: URL { get }
/**
The `NSBundle`s from which to search mapping models (*.xcmappingmodel) for migrations
An array of `SchemaMappingProvider`s that provides the complete mapping models for custom migrations.
*/
var mappingModelBundles: [Bundle] { get }
var migrationMappingProviders: [SchemaMappingProvider] { get }
/**
Options that tell the `DataStack` how to setup the persistent store