From 8ff163af30f82144d3e8c44d5f4beb1f48cda80f Mon Sep 17 00:00:00 2001 From: John Rommel Estropia Date: Wed, 10 May 2017 02:00:47 +0900 Subject: [PATCH] WIP: documentation --- .../NSEntityDescription+DynamicModel.swift | 4 +- .../ObjectiveC/CSXcodeDataModelSchema.swift | 4 +- Sources/Setup/DataStack.swift | 35 +++++- .../Dynamic Schema/CoreStoreSchema.swift | 97 ++++------------ .../Dynamic Schema/DynamicSchema.swift | 2 +- .../LegacyXcodeDataModelSchema.swift | 13 +++ .../Dynamic Schema/XcodeDataModelSchema.swift | 50 ++++++++- .../Setup/Dynamic Models/DynamicObject.swift | 12 ++ Sources/Setup/Dynamic Models/Entity.swift | 106 ++++++++++++++---- .../Setup/Dynamic Models/SchemaHistory.swift | 19 +++- 10 files changed, 230 insertions(+), 112 deletions(-) diff --git a/Sources/Internal/NSEntityDescription+DynamicModel.swift b/Sources/Internal/NSEntityDescription+DynamicModel.swift index 46094c9..045e2af 100644 --- a/Sources/Internal/NSEntityDescription+DynamicModel.swift +++ b/Sources/Internal/NSEntityDescription+DynamicModel.swift @@ -32,7 +32,7 @@ import Foundation internal extension NSEntityDescription { @nonobjc - internal var coreStoreEntity: CoreStoreSchema.AnyEntity? { + internal var coreStoreEntity: DynamicEntity? { get { @@ -43,7 +43,7 @@ internal extension NSEntityDescription { return nil } - return CoreStoreSchema.AnyEntity( + return DynamicEntity( type: NSClassFromString(typeName) as! CoreStoreObject.Type, entityName: entityName, isAbstract: isAbstract, diff --git a/Sources/ObjectiveC/CSXcodeDataModelSchema.swift b/Sources/ObjectiveC/CSXcodeDataModelSchema.swift index 336480d..62c0a76 100644 --- a/Sources/ObjectiveC/CSXcodeDataModelSchema.swift +++ b/Sources/ObjectiveC/CSXcodeDataModelSchema.swift @@ -38,10 +38,10 @@ import Foundation public final class CSXcodeDataModelSchema: NSObject, CSDynamicSchema, CoreStoreObjectiveCType { @objc - public required init(modelVersion: ModelVersion, modelVersionFileURL: URL) { + public required init(modelName: ModelVersion, modelVersionFileURL: URL) { self.bridgeToSwift = XcodeDataModelSchema( - modelVersion: modelVersion, + modelName: modelName, modelVersionFileURL: modelVersionFileURL ) } diff --git a/Sources/Setup/DataStack.swift b/Sources/Setup/DataStack.swift index 6ed1cf9..070cda1 100644 --- a/Sources/Setup/DataStack.swift +++ b/Sources/Setup/DataStack.swift @@ -35,7 +35,7 @@ import CoreData public final class DataStack: Equatable { /** - Initializes a `DataStack` from the model with the specified `modelName` in the specified `bundle`. + Convenience initializer for `DataStack` that creates a `SchemaHistory` from the model with the specified `modelName` in the specified `bundle`. - parameter modelName: the name of the (.xcdatamodeld) model file. If not specified, the application name (CFBundleName) will be used if it exists, or "CoreData" if it the bundle name was not set (e.g. in Unit Tests). - parameter bundle: an optional bundle to load models from. If not specified, the main bundle will be used. @@ -53,8 +53,20 @@ public final class DataStack: Equatable { } /** - Initializes a `DataStack` from a `DynamicSchema` implementation. - + Convenience initializer for `DataStack` that creates a `SchemaHistory` from a list of `DynamicSchema` versions. + ``` + CoreStore.defaultStack = DataStack( + XcodeDataModelSchema(modelName: "MyModelV1"), + CoreStoreSchema( + modelVersion: "MyModelV2", + entities: [ + Entity("Animal"), + Entity("Person") + ] + ), + migrationChain: ["MyModelV1", "MyModelV2"] + ) + ``` - parameter schema: an instance of `DynamicSchema` - parameter otherSchema: a list of other `DynamicSchema` instances that represent present/previous/future model versions, in any order - parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. @@ -67,10 +79,25 @@ public final class DataStack: Equatable { migrationChain: migrationChain ) ) + } /** Initializes a `DataStack` from a `SchemaHistory` instance. - + ``` + CoreStore.defaultStack = DataStack( + schemaHistory: SchemaHistory( + XcodeDataModelSchema(modelName: "MyModelV1"), + CoreStoreSchema( + modelVersion: "MyModelV2", + entities: [ + Entity("Animal"), + Entity("Person") + ] + ), + migrationChain: ["MyModelV1", "MyModelV2"] + ) + ) + ``` - parameter schemaHistory: the `SchemaHistory` for the stack */ public required init(schemaHistory: SchemaHistory) { diff --git a/Sources/Setup/Dynamic Models/Dynamic Schema/CoreStoreSchema.swift b/Sources/Setup/Dynamic Models/Dynamic Schema/CoreStoreSchema.swift index 22a5f5d..e03bc89 100644 --- a/Sources/Setup/Dynamic Models/Dynamic Schema/CoreStoreSchema.swift +++ b/Sources/Setup/Dynamic Models/Dynamic Schema/CoreStoreSchema.swift @@ -94,9 +94,9 @@ public final class CoreStoreSchema: DynamicSchema { - parameter entities: an array of `Entity` pertaining to all `CoreStoreObject` subclasses to be added to the schema version. - parameter versionLock: an optional list of `VersionLock` hashes for each entity name in the `entities` array. If any `DynamicEntity` doesn't match its version lock hash, an assertion will be raised. */ - public convenience init(modelVersion: ModelVersion, entities: [DynamicEntity & Hashable], versionLock: VersionLock? = nil) { + public convenience init(modelVersion: ModelVersion, entities: [DynamicEntity], versionLock: VersionLock? = nil) { - var entityConfigurations: [DynamicEntity & Hashable: Set] = [:] + var entityConfigurations: [DynamicEntity: Set] = [:] for entity in entities { entityConfigurations[entity] = [] @@ -138,15 +138,15 @@ public final class CoreStoreSchema: DynamicSchema { - parameter entityConfigurations: a dictionary with `Entity` pertaining to all `CoreStoreObject` subclasses and the corresponding list of "Configurations" they should be added to. To add an entity only to the default configuration, assign an empty set to its configurations list. Note that regardless of the set configurations, all entities will be added to the default configuration. - parameter versionLock: an optional list of `VersionLock` hashes for each entity name in the `entities` array. If any `DynamicEntity` doesn't match its version lock hash, an assertion will be raised. */ - public required init(modelVersion: ModelVersion, entityConfigurations: [DynamicEntity & Hashable: Set], versionLock: VersionLock? = nil) { + public required init(modelVersion: ModelVersion, entityConfigurations: [DynamicEntity: Set], versionLock: VersionLock? = nil) { - var actualEntitiesByConfiguration: [String: Set] = [:] + var actualEntitiesByConfiguration: [String: Set] = [:] for (entity, configurations) in entityConfigurations { for configuration in configurations { - var entities: Set - if let existingEntities = actualEntitiesByConfiguration[configurations] { + var entities: Set + if let existingEntities = actualEntitiesByConfiguration[configuration] { entities = existingEntities } @@ -154,11 +154,11 @@ public final class CoreStoreSchema: DynamicSchema { entities = [] } - entities.insert(AnyEntity(entity)) - actualEntitiesByConfiguration[configurations] = entities + entities.insert(entity) + actualEntitiesByConfiguration[configuration] = entities } } - let allEntities = Set(actualEntitiesByConfiguration.values.joined()) + let allEntities = Set(entityConfigurations.keys) actualEntitiesByConfiguration[DataStack.defaultConfigurationName] = allEntities CoreStore.assert( @@ -205,7 +205,7 @@ public final class CoreStoreSchema: DynamicSchema { return cachedRawModel } let rawModel = NSManagedObjectModel() - var entityDescriptionsByEntity: [AnyEntity: NSEntityDescription] = [:] + var entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription] = [:] for entity in self.allEntities { let entityDescription = self.entityDescription( @@ -234,73 +234,19 @@ public final class CoreStoreSchema: DynamicSchema { // MARK: Internal - // MARK: - AnyEntity - - internal struct AnyEntity: DynamicEntity, Hashable { - - internal init(_ entity: DynamicEntity) { - - self.init( - type: entity.type, - entityName: entity.entityName, - isAbstract: entity.isAbstract, - versionHashModifier: entity.versionHashModifier - ) - } - - internal init(type: DynamicObject.Type, entityName: String, isAbstract: Bool, versionHashModifier: String?) { - - self.type = type - self.entityName = entityName - self.isAbstract = isAbstract - self.versionHashModifier = versionHashModifier - } - - - // MARK: Equatable - - static func == (lhs: AnyEntity, rhs: AnyEntity) -> Bool { - - return lhs.type == rhs.type - && lhs.entityName == rhs.entityName - && lhs.isAbstract == rhs.isAbstract - && lhs.versionHashModifier == rhs.versionHashModifier - } - - // MARK: Hashable - - var hashValue: Int { - - return ObjectIdentifier(self.type).hashValue - ^ self.entityName.hashValue - ^ self.isAbstract.hashValue - ^ (self.versionHashModifier ?? "").hashValue - } - - // MARK: DynamicEntity - - internal let type: DynamicObject.Type - internal let entityName: EntityName - internal let isAbstract: Bool - internal let versionHashModifier: String? - } - - - // MARK: - - - internal let entitiesByConfiguration: [String: Set] + internal let entitiesByConfiguration: [String: Set] // MARK: Private private static let barrierQueue = DispatchQueue.concurrent("com.coreStore.coreStoreDataModelBarrierQueue") - private let allEntities: Set + private let allEntities: Set - private var entityDescriptionsByEntity: [CoreStoreSchema.AnyEntity: NSEntityDescription] = [:] + private var entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription] = [:] private weak var cachedRawModel: NSManagedObjectModel? - private func entityDescription(for entity: CoreStoreSchema.AnyEntity, initializer: (CoreStoreSchema.AnyEntity) -> NSEntityDescription) -> NSEntityDescription { + private func entityDescription(for entity: DynamicEntity, initializer: (DynamicEntity) -> NSEntityDescription) -> NSEntityDescription { if let cachedEntityDescription = self.entityDescriptionsByEntity[entity] { @@ -311,12 +257,13 @@ public final class CoreStoreSchema: DynamicSchema { return entityDescription } - private static func firstPassCreateEntityDescription(from entity: AnyEntity) -> NSEntityDescription { + private static func firstPassCreateEntityDescription(from entity: DynamicEntity) -> NSEntityDescription { let entityDescription = NSEntityDescription() entityDescription.coreStoreEntity = entity entityDescription.name = entity.entityName entityDescription.isAbstract = entity.isAbstract + entityDescription.versionHashModifier = entity.versionHashModifier entityDescription.managedObjectClassName = NSStringFromClass(NSManagedObject.self) func createProperties(for type: CoreStoreObject.Type) -> [NSPropertyDescription] { @@ -360,16 +307,16 @@ public final class CoreStoreSchema: DynamicSchema { return entityDescription } - private static func secondPassConnectRelationshipAttributes(for entityDescriptionsByEntity: [AnyEntity: NSEntityDescription]) { + private static func secondPassConnectRelationshipAttributes(for entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription]) { - var relationshipsByNameByEntity: [AnyEntity: [String: NSRelationshipDescription]] = [:] + var relationshipsByNameByEntity: [DynamicEntity: [String: NSRelationshipDescription]] = [:] for (entity, entityDescription) in entityDescriptionsByEntity { relationshipsByNameByEntity[entity] = entityDescription.relationshipsByName } - func findEntity(for type: CoreStoreObject.Type) -> AnyEntity { + func findEntity(for type: CoreStoreObject.Type) -> DynamicEntity { - var matchedEntities: Set = [] + var matchedEntities: Set = [] for (entity, _) in entityDescriptionsByEntity where entity.type == type { matchedEntities.insert(entity) @@ -392,7 +339,7 @@ public final class CoreStoreSchema: DynamicSchema { } } - func findInverseRelationshipMatching(destinationEntity: AnyEntity, destinationKeyPath: String) -> NSRelationshipDescription { + func findInverseRelationshipMatching(destinationEntity: DynamicEntity, destinationKeyPath: String) -> NSRelationshipDescription { for case (destinationKeyPath, let relationshipDescription) in relationshipsByNameByEntity[destinationEntity]! { @@ -451,7 +398,7 @@ public final class CoreStoreSchema: DynamicSchema { } } - private static func thirdPassConnectInheritanceTree(for entityDescriptionsByEntity: [AnyEntity: NSEntityDescription]) { + private static func thirdPassConnectInheritanceTree(for entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription]) { func connectBaseEntity(mirror: Mirror, entityDescription: NSEntityDescription) { diff --git a/Sources/Setup/Dynamic Models/Dynamic Schema/DynamicSchema.swift b/Sources/Setup/Dynamic Models/Dynamic Schema/DynamicSchema.swift index 58e0ffc..e01b096 100644 --- a/Sources/Setup/Dynamic Models/Dynamic Schema/DynamicSchema.swift +++ b/Sources/Setup/Dynamic Models/Dynamic Schema/DynamicSchema.swift @@ -30,7 +30,7 @@ import Foundation // MARK: - DynamicSchema /** - `DynamicSchema` are types that provide `NSManagedObjectModel` instances for a particular model version. CoreStore currently supports the following concrete types: + `DynamicSchema` are types that provide `NSManagedObjectModel` instances for a single model version. CoreStore currently supports the following concrete types: - `XcodeDataModelSchema`: describes models loaded from a .xcdatamodeld file. - `LegacyXcodeDataModelSchema`: describes models loaded directly from an existing `NSManagedObjectModel`. It is not advisable to continue using this model as its metadata are not available to CoreStore. - `CoreStoreSchema`: describes models written for `CoreStoreObject` Swift class declarations. diff --git a/Sources/Setup/Dynamic Models/Dynamic Schema/LegacyXcodeDataModelSchema.swift b/Sources/Setup/Dynamic Models/Dynamic Schema/LegacyXcodeDataModelSchema.swift index d9db734..f079c17 100644 --- a/Sources/Setup/Dynamic Models/Dynamic Schema/LegacyXcodeDataModelSchema.swift +++ b/Sources/Setup/Dynamic Models/Dynamic Schema/LegacyXcodeDataModelSchema.swift @@ -29,8 +29,21 @@ import Foundation // MARK: - LegacyXcodeDataModelSchema +/** + The `LegacyXcodeDataModelSchema` describes models loaded directly from an existing `NSManagedObjectModel`. It is not advisable to continue using this model as its metadata are not available to CoreStore. + */ public final class LegacyXcodeDataModelSchema: DynamicSchema { + /** + Initializes a `LegacyXcodeDataModelSchema` from an `NSManagedObjectModel`. + ``` + CoreStore.defaultStack = DataStack( + LegacyXcodeDataModelSchema(modelName: "MyAppV1", model: model) + ) + ``` + - parameter modelName: the model version, typically the file name of an *.xcdatamodeld file (without the file extension) + - parameter model: the `NSManagedObjectModel` + */ public required init(modelName: ModelVersion, model: NSManagedObjectModel) { self.modelVersion = modelName diff --git a/Sources/Setup/Dynamic Models/Dynamic Schema/XcodeDataModelSchema.swift b/Sources/Setup/Dynamic Models/Dynamic Schema/XcodeDataModelSchema.swift index 8e25ebc..c0fe99c 100644 --- a/Sources/Setup/Dynamic Models/Dynamic Schema/XcodeDataModelSchema.swift +++ b/Sources/Setup/Dynamic Models/Dynamic Schema/XcodeDataModelSchema.swift @@ -29,16 +29,60 @@ import Foundation // MARK: - XcodeDataModelSchema +/** + The `XcodeDataModelSchema` describes a model version declared in a single *.xcdatamodeld file. + ``` + CoreStore.defaultStack = DataStack( + XcodeDataModelSchema(modelName: "MyAppV1", bundle: .main) + ) + ``` + */ public final class XcodeDataModelSchema: DynamicSchema { - public required init(modelVersion: ModelVersion, modelVersionFileURL: URL) { + /** + Initializes an `XcodeDataModelSchema` from an *.xcdatamodeld version name and its containing `Bundle`. + ``` + CoreStore.defaultStack = DataStack( + XcodeDataModelSchema(modelName: "MyAppV1", bundle: .main) + ) + ``` + - parameter modelName: the model version, typically the file name of an *.xcdatamodeld file (without the file extension) + - parameter bundle: the `Bundle` that contains the .xcdatamodeld's "momd" file. If not specified, the `Bundle.main` will be searched. + */ + public convenience init(modelName: ModelVersion, bundle: Bundle = Bundle.main) { + + guard let modelFilePath = bundle.path(forResource: modelName, ofType: "momd") else { + + // For users migrating from very old Xcode versions: Old xcdatamodel files are not contained inside xcdatamodeld (with a "d"), and will thus fail this check. If that was the case, create a new xcdatamodeld file and copy all contents into the new model. + let foundModels = bundle + .paths(forResourcesOfType: "momd", inDirectory: nil) + .map({ ($0 as NSString).lastPathComponent }) + CoreStore.abort("Could not find \"\(modelName).momd\" from the bundle \"\(bundle.bundleIdentifier ?? "")\". Other model files in bundle: \(foundModels.coreStoreDumpString)") + } + + let modelFileURL = URL(fileURLWithPath: modelFilePath) + let fileURL = modelFileURL.appendingPathComponent("\(modelName).mom", isDirectory: false) + self.init(modelName: modelName, modelVersionFileURL: fileURL) + } + + /** + Initializes an `XcodeDataModelSchema` from an *.xcdatamodeld file URL. + ``` + CoreStore.defaultStack = DataStack( + XcodeDataModelSchema(modelName: "MyAppV1", modelVersionFileURL: fileURL) + ) + ``` + - parameter modelName: the model version, typically the file name of an *.xcdatamodeld file (without the file extension) + - parameter modelVersionFileURL: the file URL that points to the .xcdatamodeld's "momd" file. + */ + public required init(modelName: ModelVersion, modelVersionFileURL: URL) { CoreStore.assert( NSManagedObjectModel(contentsOf: modelVersionFileURL) != nil, - "Could not find the \"\(modelVersion).mom\" version file for the model at URL \"\(modelVersionFileURL)\"." + "Could not find the \"\(modelName).mom\" version file for the model at URL \"\(modelVersionFileURL)\"." ) - self.modelVersion = modelVersion + self.modelVersion = modelName self.modelVersionFileURL = modelVersionFileURL } diff --git a/Sources/Setup/Dynamic Models/DynamicObject.swift b/Sources/Setup/Dynamic Models/DynamicObject.swift index 4544073..01a44e2 100644 --- a/Sources/Setup/Dynamic Models/DynamicObject.swift +++ b/Sources/Setup/Dynamic Models/DynamicObject.swift @@ -28,12 +28,24 @@ import Foundation // MARK: - DynamicObject +/** + All CoreStore's utilities are designed around `DynamicObject` instances. `NSManagedObject` and `CoreStoreObject` instances all conform to `DynamicObject`. + */ public protocol DynamicObject: class { + /** + Used internally by CoreStore. Do not call directly. + */ static func cs_forceCreate(entityDescription: NSEntityDescription, into context: NSManagedObjectContext, assignTo store: NSPersistentStore) -> Self + /** + Used internally by CoreStore. Do not call directly. + */ static func cs_fromRaw(object: NSManagedObject) -> Self + /** + Used internally by CoreStore. Do not call directly. + */ func cs_toRaw() -> NSManagedObject } diff --git a/Sources/Setup/Dynamic Models/Entity.swift b/Sources/Setup/Dynamic Models/Entity.swift index 03fe560..bb6fc26 100644 --- a/Sources/Setup/Dynamic Models/Entity.swift +++ b/Sources/Setup/Dynamic Models/Entity.swift @@ -28,46 +28,99 @@ import Foundation import ObjectiveC -// MARK: - DynamicEntity - -public protocol DynamicEntity { - - var type: DynamicObject.Type { get } - var entityName: EntityName { get } - var isAbstract: Bool { get } - var versionHashModifier: String? { get } -} - - // MARK: Entity -public struct Entity: DynamicEntity, Hashable { +/** + The `Entity` contains `NSEntityDescription` metadata for `CoreStoreObject` subclasses. Pass the `Entity` instances to `CoreStoreSchema` initializer. + ``` + class Animal: CoreStoreObject { + let species = Value.Required("species") + let nickname = Value.Optional("nickname") + let master = Relationship.ToOne("master") + } + + class Person: CoreStoreObject { + let name = Value.Required("name") + let pet = Relationship.ToOne("pet", inverse: { $0.master }) + } + + CoreStore.defaultStack = DataStack( + CoreStoreSchema( + modelVersion: "V1", + entities: [ + Entity("Animal"), + Entity("Person") + ] + ) + ) + ``` + - SeeAlso: CoreStoreSchema + - SeeAlso: CoreStoreObject + */ +public final class Entity: DynamicEntity { - public init(_ entityName: String, isAbstract: Bool = false, versionHashModifier: String? = nil) { + /** + Initializes an `Entity`. Always provide a concrete generic type to `Entity`. + ``` + Entity("Animal") + ``` + - parameter entityName: the `NSEntityDescription` name to use for the entity + - parameter isAbstract: set to `true` if the entity is meant to be an abstract class and can only be initialized with subclass types. + - parameter versionHashModifier: The version hash modifier for the entity. Used to mark or denote an entity as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where, for example, the structure of an entity is unchanged but the format or content of data has changed.) + */ + public convenience init(_ entityName: String, isAbstract: Bool = false, versionHashModifier: String? = nil) { self.init(O.self, entityName, isAbstract: isAbstract, versionHashModifier: versionHashModifier) } + /** + Initializes an `Entity`. + ``` + Entity(Animal.self, "Animal") + ``` + - parameter type: the `DynamicObject` type associated with the entity + - parameter entityName: the `NSEntityDescription` name to use for the entity + - parameter isAbstract: set to `true` if the entity is meant to be an abstract class and can only be initialized with subclass types. + - parameter versionHashModifier: The version hash modifier for the entity. Used to mark or denote an entity as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where, for example, the structure of an entity is unchanged but the format or content of data has changed.) + */ public init(_ type: O.Type, _ entityName: String, isAbstract: Bool = false, versionHashModifier: String? = nil) { - self.type = type - self.entityName = entityName - self.isAbstract = isAbstract - self.versionHashModifier = versionHashModifier + super.init(type: type, entityName: entityName, isAbstract: isAbstract, versionHashModifier: versionHashModifier) } +} + + +// MARK: - DynamicEntity + +/** + Use concrete instances of `Entity` in API that accept `DynamicEntity` arguments. + */ +public /*abstract*/ class DynamicEntity: Hashable { - - // MARK: DynamicEntity - + /** + Do not use directly. + */ public let type: DynamicObject.Type + + /** + Do not use directly. + */ public let entityName: EntityName + + /** + Do not use directly. + */ public let isAbstract: Bool + + /** + Do not use directly. + */ public let versionHashModifier: String? // MARK: Equatable - public static func == (lhs: Entity, rhs: Entity) -> Bool { + public static func == (lhs: DynamicEntity, rhs: DynamicEntity) -> Bool { return lhs.type == rhs.type && lhs.entityName == rhs.entityName @@ -84,4 +137,15 @@ public struct Entity: DynamicEntity, Hashable { ^ self.isAbstract.hashValue ^ (self.versionHashModifier ?? "").hashValue } + + + // MARK: Internal + + internal init(type: DynamicObject.Type, entityName: String, isAbstract: Bool = false, versionHashModifier: String?) { + + self.type = type + self.entityName = entityName + self.isAbstract = isAbstract + self.versionHashModifier = versionHashModifier + } } diff --git a/Sources/Setup/Dynamic Models/SchemaHistory.swift b/Sources/Setup/Dynamic Models/SchemaHistory.swift index 941401b..944f036 100644 --- a/Sources/Setup/Dynamic Models/SchemaHistory.swift +++ b/Sources/Setup/Dynamic Models/SchemaHistory.swift @@ -30,9 +30,7 @@ import Foundation // MARK: - SchemaHistory /** - The `SchemaHistory` encapsulates all model versions that is relevant to the data model, including past versions. - - SeeAlso: SchemaHistory.currentModelVersion - - SeeAlso: SchemaHistory.migrationChain + The `SchemaHistory` encapsulates multiple `DynamicSchema` across multiple model versions. It contains all model history and is used by the `DataStack` to */ public final class SchemaHistory: ExpressibleByArrayLiteral { @@ -108,7 +106,7 @@ public final class SchemaHistory: ExpressibleByArrayLiteral { for modelVersion in modelVersions { let fileURL = modelFileURL.appendingPathComponent("\(modelVersion).mom", isDirectory: false) - allSchema.append(XcodeDataModelSchema(modelVersion: modelVersion, modelVersionFileURL: fileURL)) + allSchema.append(XcodeDataModelSchema(modelName: modelVersion, modelVersionFileURL: fileURL)) } self.init( allSchema: allSchema, @@ -117,6 +115,13 @@ public final class SchemaHistory: ExpressibleByArrayLiteral { ) } + /** + Initializes a `SchemaHistory` with a list of `DynamicSchema` and a `MigrationChain` to describe the order of progressive migrations. + - parameter schema: a `DynamicSchema` that represents a model version + - parameter otherSchema: a list of `DynamicSchema` that represent other model versions + - parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. + - parameter exactCurrentModelVersion: an optional string to explicitly select the current model version string. This is useful if the `DataStack` should load a non-latest model version (usually to prepare data before migration). If not provided, the current model version will be computed from the `MigrationChain`. + */ public convenience init(_ schema: DynamicSchema, _ otherSchema: DynamicSchema..., migrationChain: MigrationChain = nil, exactCurrentModelVersion: String? = nil) { self.init( @@ -126,6 +131,12 @@ public final class SchemaHistory: ExpressibleByArrayLiteral { ) } + /** + Initializes a `SchemaHistory` with a list of `DynamicSchema` and a `MigrationChain` to describe the order of progressive migrations. + - parameter allSchema: a list of `DynamicSchema` that represent model versions + - parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. + - parameter exactCurrentModelVersion: an optional string to explicitly select the current model version string. This is useful if the `DataStack` should load a non-latest model version (usually to prepare data before migration). If not provided, the current model version will be computed from the `MigrationChain`. + */ public required init(allSchema: [DynamicSchema], migrationChain: MigrationChain = nil, exactCurrentModelVersion: String? = nil) { if allSchema.isEmpty {