From 9da323b0b8086ffd40e4deeb857e50e8781643d3 Mon Sep 17 00:00:00 2001 From: John Rommel Estropia Date: Thu, 9 Jul 2015 08:08:11 +0900 Subject: [PATCH] assert migration chain when creating a data stack --- CoreStore/Migrating/MigrationChain.swift | 82 ++++++++++++++++++------ CoreStore/Setting Up/DataStack.swift | 7 +- 2 files changed, 66 insertions(+), 23 deletions(-) diff --git a/CoreStore/Migrating/MigrationChain.swift b/CoreStore/Migrating/MigrationChain.swift index 6cb899b..76ab413 100644 --- a/CoreStore/Migrating/MigrationChain.swift +++ b/CoreStore/Migrating/MigrationChain.swift @@ -31,25 +31,6 @@ import CoreData public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, DictionaryLiteralConvertible, ArrayLiteralConvertible { - // MARK: Public - - public func contains(version: String) -> Bool { - - return self.rootVersions.contains(version) - || self.leafVersions.contains(version) - || self.versionTree[version] != nil - } - - public func nextVersionFrom(version: String) -> String? { - - if let nextVersion = self.versionTree[version] where nextVersion != version { - - return nextVersion - } - return nil - } - - // MARK: NilLiteralConvertible public init(nilLiteral: ()) { @@ -57,6 +38,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D self.versionTree = [:] self.rootVersions = [] self.leafVersions = [] + self.valid = true } @@ -67,6 +49,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D self.versionTree = [:] self.rootVersions = [value] self.leafVersions = [value] + self.valid = true } @@ -77,6 +60,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D self.versionTree = [:] self.rootVersions = [value] self.leafVersions = [value] + self.valid = true } @@ -87,6 +71,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D self.versionTree = [:] self.rootVersions = [value] self.leafVersions = [value] + self.valid = true } @@ -94,9 +79,13 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D public init(dictionaryLiteral elements: (String, String)...) { + var valid = true let versionTree = elements.reduce([String: String]()) { (var versionTree, tuple: (String, String)) -> [String: String] in - versionTree[tuple.0] = tuple.1 + if let _ = versionTree.updateValue(tuple.1, forKey: tuple.0) { + + valid = false + } return versionTree } let leafVersions = Set( @@ -110,6 +99,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D self.versionTree = versionTree self.rootVersions = Set(versionTree.keys).subtract(versionTree.values) self.leafVersions = leafVersions + self.valid = valid } @@ -121,11 +111,15 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D var lastVersion: String? var versionTree = [String: String]() + var valid = true for version in elements { if let lastVersion = lastVersion { - versionTree[lastVersion] = version + if let _ = versionTree.updateValue(version, forKey: lastVersion) { + + valid = false + } } lastVersion = version } @@ -133,6 +127,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D self.versionTree = versionTree self.rootVersions = Set([elements.first].flatMap { $0 == nil ? [] : [$0!] }) self.leafVersions = Set([elements.last].flatMap { $0 == nil ? [] : [$0!] }) + self.valid = valid } @@ -140,9 +135,54 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D internal let rootVersions: Set internal let leafVersions: Set + internal let valid: Bool + + internal func contains(version: String) -> Bool { + + return self.rootVersions.contains(version) + || self.leafVersions.contains(version) + || self.versionTree[version] != nil + } + + internal func nextVersionFrom(version: String) -> String? { + + if let nextVersion = self.versionTree[version] where nextVersion != version { + + return nextVersion + } + return nil + } // MARK: Private private let versionTree: [String: String] } + + +// MARK: - MigrationChain: CustomDebugStringConvertible + +extension MigrationChain: CustomDebugStringConvertible { + + public var debugDescription: String { + + guard self.valid else { + + return "" + } + + var paths = [String]() + for var version in self.rootVersions { + + var steps = [version] + while let nextVersion = self.nextVersionFrom(version) { + + steps.append(nextVersion) + version = nextVersion + } + paths.append(" → ".join(steps)) + } + + return "[" + "], [".join(paths) + "]" + } +} diff --git a/CoreStore/Setting Up/DataStack.swift b/CoreStore/Setting Up/DataStack.swift index 13b8092..8703326 100644 --- a/CoreStore/Setting Up/DataStack.swift +++ b/CoreStore/Setting Up/DataStack.swift @@ -53,14 +53,17 @@ public final class DataStack { */ public required init(modelName: String = applicationName, bundle: NSBundle = NSBundle.mainBundle(), migrationChain: MigrationChain = nil) { + CoreStore.assert( + migrationChain.valid, + "Invalid migration chain passed to the \(typeName(DataStack)). Check that the model versions' order is correct and that no repetitions or ambiguities exist." + ) + let model = NSManagedObjectModel.fromBundle( bundle, modelName: modelName, modelVersion: migrationChain.leafVersions.first ) - // TODO: assert existence of all model versions in the migrationChain - self.coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) self.rootSavingContext = NSManagedObjectContext.rootSavingContextForCoordinator(self.coordinator) self.mainContext = NSManagedObjectContext.mainContextForRootContext(self.rootSavingContext)