WIP: allow migrations for CoreStoreObjects

This commit is contained in:
John Estropia
2017-04-11 19:13:35 +09:00
parent e5ef4992d3
commit 9f3db61ff7
27 changed files with 1146 additions and 691 deletions

View File

@@ -218,7 +218,7 @@ public extension DataStack {
try storage.eraseStorageAndWait(
metadata: metadata,
soureModelHint: self.model[metadata]
soureModelHint: self.schemaHistory.schema(for: metadata)?.rawModel()
)
_ = try self.addStorageAndWait(storage)
@@ -382,7 +382,9 @@ public extension DataStack {
at: cacheFileURL,
options: storeOptions
)
_ = try self.model[metadata].flatMap(storage.eraseStorageAndWait)
_ = try self.schemaHistory
.schema(for: metadata)
.flatMap({ try storage.eraseStorageAndWait(soureModel: $0.rawModel()) })
_ = try self.createPersistentStoreFromStorage(
storage,
finalURL: cacheFileURL,
@@ -497,7 +499,7 @@ public extension DataStack {
let error = CoreStoreError.mappingModelNotFound(
localStoreURL: fileURL,
targetModel: self.model,
targetModel: self.schemaHistory.rawModel,
targetModelVersion: self.modelVersion
)
CoreStore.log(
@@ -545,12 +547,12 @@ public extension DataStack {
let error = CoreStoreError.mappingModelNotFound(
localStoreURL: storage.fileURL,
targetModel: self.model,
targetModel: self.schemaHistory.rawModel,
targetModelVersion: self.modelVersion
)
CoreStore.log(
error,
"Failed to find migration steps from \(cs_typeName(storage)) at URL \"\(storage.fileURL)\" to version model \"\(self.model)\"."
"Failed to find migration steps from \(cs_typeName(storage)) at URL \"\(storage.fileURL)\" to version model \"\(self.schemaHistory.rawModel)\"."
)
DispatchQueue.main.async {
@@ -592,7 +594,7 @@ public extension DataStack {
let progress = Progress(parent: nil, userInfo: nil)
progress.totalUnitCount = numberOfMigrations
for (sourceModel, destinationModel, mappingModel, _) in migrationSteps {
for (sourceModel, destinationModel, mappingModel, migrationType) in migrationSteps {
progress.becomeCurrent(withPendingUnitCount: 1)
@@ -620,8 +622,13 @@ public extension DataStack {
)
}
catch {
migrationResult = MigrationResult(error)
let migrationError = CoreStoreError(error)
CoreStore.log(
migrationError,
"Failed to migrate version model \"\(migrationType.sourceVersion)\" to version \"\(migrationType.destinationVersion)\"."
)
migrationResult = MigrationResult(migrationError)
cancelled = true
}
}
@@ -658,28 +665,27 @@ public extension DataStack {
private func computeMigrationFromStorage<T: LocalStorage>(_ storage: T, metadata: [String: Any]) -> [(sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, mappingModel: NSMappingModel, migrationType: MigrationType)]? {
let model = self.model
if model.isConfiguration(withName: storage.configuration, compatibleWithStoreMetadata: metadata) {
let schemaHistory = self.schemaHistory
if schemaHistory.rawModel.isConfiguration(withName: storage.configuration, compatibleWithStoreMetadata: metadata) {
return []
}
guard let initialModel = model[metadata],
var currentVersion = initialModel.currentModelVersion else {
return nil
guard let initialSchema = schemaHistory.schema(for: metadata) else {
return nil
}
let migrationChain: MigrationChain = self.migrationChain.empty
? [currentVersion: model.currentModelVersion!]
: self.migrationChain
var currentVersion = initialSchema.modelVersion
let migrationChain: MigrationChain = schemaHistory.migrationChain.isEmpty
? [currentVersion: schemaHistory.currentModelVersion]
: schemaHistory.migrationChain
var migrationSteps = [(sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, mappingModel: NSMappingModel, migrationType: MigrationType)]()
while let nextVersion = migrationChain.nextVersionFrom(currentVersion),
let sourceModel = model[currentVersion],
sourceModel != model,
let destinationModel = model[nextVersion] {
let sourceModel = schemaHistory.rawModel(for: currentVersion),
sourceModel != schemaHistory.rawModel,
let destinationModel = schemaHistory.rawModel(for: nextVersion) {
if let mappingModel = NSMappingModel(
from: storage.mappingModelBundles,
@@ -727,7 +733,7 @@ public extension DataStack {
currentVersion = nextVersion
}
if migrationSteps.last?.destinationModel == model {
if migrationSteps.last?.destinationModel == schemaHistory.rawModel {
return migrationSteps
}
@@ -775,21 +781,8 @@ public extension DataStack {
}
catch {
do {
try fileManager.removeItem(at: temporaryFileURL)
}
catch _ { }
let sourceVersion = migrationManager.sourceModel.currentModelVersion ?? "???"
let destinationVersion = migrationManager.destinationModel.currentModelVersion ?? "???"
let migrationError = CoreStoreError(error)
CoreStore.log(
migrationError,
"Failed to migrate from version model \"\(sourceVersion)\" to version model \"\(destinationVersion)\"."
)
throw migrationError
_ = try? fileManager.removeItem(at: temporaryFileURL)
throw CoreStoreError(error)
}
do {
@@ -806,21 +799,8 @@ public extension DataStack {
}
catch {
do {
try fileManager.removeItem(at: temporaryFileURL)
}
catch _ { }
let sourceVersion = migrationManager.sourceModel.currentModelVersion ?? "???"
let destinationVersion = migrationManager.destinationModel.currentModelVersion ?? "???"
let fileError = CoreStoreError(error)
CoreStore.log(
fileError,
"Failed to save store after migrating from version model \"\(sourceVersion)\" to version model \"\(destinationVersion)\"."
)
throw fileError
_ = try? fileManager.removeItem(at: temporaryFileURL)
throw CoreStoreError(error)
}
}
}

View File

@@ -70,7 +70,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
self.versionTree = [:]
self.rootVersions = []
self.leafVersions = []
self.valid = true
self.isValid = true
}
/**
@@ -81,7 +81,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
self.versionTree = [:]
self.rootVersions = [value]
self.leafVersions = [value]
self.valid = true
self.isValid = true
}
/**
@@ -93,13 +93,13 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
var lastVersion: String?
var versionTree = [String: String]()
var valid = true
var isValid = true
for version in elements {
if let lastVersion = lastVersion,
let _ = versionTree.updateValue(version, forKey: lastVersion) {
valid = false
isValid = false
}
lastVersion = version
}
@@ -107,7 +107,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
self.versionTree = versionTree
self.rootVersions = Set(elements.prefix(1))
self.leafVersions = Set(elements.suffix(1))
self.valid = valid
self.isValid = isValid
}
/**
@@ -115,7 +115,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
*/
public init(_ elements: [(String, String)]) {
var valid = true
var isValid = true
var versionTree = [String: String]()
elements.forEach { (sourceVersion, destinationVersion) in
@@ -126,7 +126,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
CoreStore.assert(false, "\(cs_typeName(MigrationChain.self))'s migration chain could not be created due to ambiguous version paths.")
valid = false
isValid = false
}
let leafVersions = Set(
elements
@@ -156,7 +156,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
self.versionTree = versionTree
self.rootVersions = Set(versionTree.keys).subtracting(versionTree.values)
self.leafVersions = leafVersions
self.valid = valid && Set(versionTree.keys).union(versionTree.values).filter { isVersionAmbiguous($0) }.count <= 0
self.isValid = isValid && Set(versionTree.keys).union(versionTree.values).filter { isVersionAmbiguous($0) }.count <= 0
}
/**
@@ -223,7 +223,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
return lhs.versionTree == rhs.versionTree
&& lhs.rootVersions == rhs.rootVersions
&& lhs.leafVersions == rhs.leafVersions
&& lhs.valid == rhs.valid
&& lhs.isValid == rhs.isValid
}
@@ -231,9 +231,9 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
internal let rootVersions: Set<String>
internal let leafVersions: Set<String>
internal let valid: Bool
internal let isValid: Bool
internal var empty: Bool {
internal var isEmpty: Bool {
return self.versionTree.count <= 0
}