From 54c81d23f5ba8eb83c3acdcb792a1f9271dd1429 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 25 Apr 2017 18:08:43 +0900 Subject: [PATCH] WIP: dynamic migrations --- .../DynamicSchema+Convenience.swift | 10 +- .../MigrationMappingProvider.swift | 101 +++++++++++------- Sources/Setup/DataStack.swift | 2 +- .../Dynamic Schema/CoreStoreSchema.swift | 16 +-- Sources/Setup/Dynamic Models/Entity.swift | 6 +- .../Setup/Dynamic Models/Relationship.swift | 68 +++++++----- Sources/Setup/Dynamic Models/Value.swift | 26 ++++- 7 files changed, 147 insertions(+), 82 deletions(-) diff --git a/Sources/Convenience/DynamicSchema+Convenience.swift b/Sources/Convenience/DynamicSchema+Convenience.swift index fdcc6d6..e7f4b30 100644 --- a/Sources/Convenience/DynamicSchema+Convenience.swift +++ b/Sources/Convenience/DynamicSchema+Convenience.swift @@ -187,7 +187,11 @@ public extension DynamicSchema { } let indexedString = attribute.isIndexed ? ", isIndexed: true" : "" let transientString = attribute.isTransient ? ", isTransient: true" : "" - output.append(" let \(attributeName) = \(containerType)<\(String(describing: valueType))>(\"\(attributeName)\"\(indexedString)\(defaultString)\(transientString))\n") + // TODO: escape strings + let versionHashModifierString = attribute.versionHashModifier.flatMap({ ", versionHashModifier: \"\($0)\"" }) ?? "" + // TODO: escape strings + let renamingIdentifierString = attribute.renamingIdentifier.flatMap({ ", renamingIdentifier: \"\($0)\"" }) ?? "" + output.append(" let \(attributeName) = \(containerType)<\(String(describing: valueType))>(\"\(attributeName)\"\(indexedString)\(defaultString)\(transientString)\(versionHashModifierString)\(renamingIdentifierString))\n") } } @@ -251,7 +255,9 @@ public extension DynamicSchema { fatalError("Unsupported delete rule \((relationship.deleteRule)) for relationship \"\(relationshipQualifier)\"") } } - output.append(" let \(relationshipName) = \(containerType)<\(relationship.destinationEntity!.name!)>(\"\(relationshipName)\"\(inverseString)\(deleteRuleString)\(minCountString)\(maxCountString))\n") + let versionHashModifierString = relationship.versionHashModifier.flatMap({ ", versionHashModifier: \"\($0)\"" }) ?? "" + let renamingIdentifierString = relationship.renamingIdentifier.flatMap({ ", renamingIdentifier: \"\($0)\"" }) ?? "" + output.append(" let \(relationshipName) = \(containerType)<\(relationship.destinationEntity!.name!)>(\"\(relationshipName)\"\(inverseString)\(deleteRuleString)\(minCountString)\(maxCountString)\(versionHashModifierString)\(renamingIdentifierString))\n") } } } diff --git a/Sources/Migrating/Migration Mapping Providers/MigrationMappingProvider.swift b/Sources/Migrating/Migration Mapping Providers/MigrationMappingProvider.swift index 3f5f38a..fd6b271 100644 --- a/Sources/Migrating/Migration Mapping Providers/MigrationMappingProvider.swift +++ b/Sources/Migrating/Migration Mapping Providers/MigrationMappingProvider.swift @@ -27,53 +27,78 @@ import CoreData import Foundation -// MARK: - MigrationMappingProvider +// MARK: - SchemaMappingProvider -public protocol MigrationMappingProvider { +public protocol SchemaMappingProvider { - associatedtype SourceSchema: DynamicSchema - associatedtype DestinationSchema: DynamicSchema + var sourceSchema: DynamicSchema { get } + var destinationSchema: DynamicSchema { get } - var sourceSchema: SourceSchema { get } - var destinationSchema: DestinationSchema { get } - - init(source: SourceSchema, destination: DestinationSchema) - -// func migrate( -// from oldObject: SourceType, -// to newObject: DestinationType, -// transaction: UnsafeDataTransaction -// ) -// -// func forEachPropertyMapping( -// from oldObject: SourceType, -// to newObject: DestinationType, -// removed: (_ keyPath: KeyPath) -> Void, -// added: (_ keyPath: KeyPath) -> Void, -// transformed: (_ keyPath: KeyPath) -> Void, -// copied: (_ keyPath: KeyPath) -> Void -// ) + func createMappingModel() throws -> (mappingModel: NSMappingModel, migrationType: MigrationType) } -public extension MigrationMappingProvider { +public protocol EntityMappingProvider { -// func migrate(from oldObject: SourceType, to newObject: DestinationType, transaction: UnsafeDataTransaction) { -// -// -// } -// -// func forEachPropertyMapping(from oldObject: SourceType, to newObject: DestinationType, removed: (_ keyPath: KeyPath) -> Void, added: (_ keyPath: KeyPath) -> Void, transformed: (_ keyPath: KeyPath) -> Void) { -// -// let oldAttributes = oldObject.cs_toRaw().entity.attributesByName -// let newAttributes = newObject.cs_toRaw().entity.attributesByName -// let oldAttributeKeys = Set(oldAttributes.keys) -// let newAttributeKeys = Set(newAttributes.keys) -// for keyPath in -// } + var source: (schema: DynamicSchema, entity: DynamicEntity) { get } + var destination: (schema: DynamicSchema, entity: DynamicEntity) { get } + + func createEntityMapping() -> NSEntityMapping } -public extension MigrationMappingProvider { + +// MARK: - XcodeMappingModelProvider + +open class XcodeMappingModelProvider: SchemaMappingProvider { + private let mappingModelBundles: [Bundle] + + public required init(source: SourceSchema, destination: DestinationSchema, mappingModelBundles: [Bundle] = Bundle.allBundles) { + + self.sourceSchema = source + self.destinationSchema = destination + self.mappingModelBundles = mappingModelBundles + } + + + // MARK: SchemaMappingProvider + + public typealias SourceSchema = S + public typealias DestinationSchema = D + + public let sourceSchema: SourceSchema + public let destinationSchema: DestinationSchema + + public func createMappingModel() throws -> (mappingModel: NSMappingModel, migrationType: MigrationType) { + + let sourceModel = self.sourceSchema.rawModel() + let destinationModel = self.destinationSchema.rawModel() + + if let mappingModel = NSMappingModel( + from: self.mappingModelBundles, + forSourceModel: sourceModel, + destinationModel: destinationModel) { + + return ( + mappingModel, + .heavyweight( + sourceVersion: self.sourceSchema.modelVersion, + destinationVersion: self.destinationSchema.modelVersion + ) + ) + } + + let mappingModel = try NSMappingModel.inferredMappingModel( + forSourceModel: sourceModel, + destinationModel: destinationModel + ) + return ( + mappingModel, + .lightweight( + sourceVersion: self.sourceSchema.modelVersion, + destinationVersion: self.destinationSchema.modelVersion + ) + ) + } } diff --git a/Sources/Setup/DataStack.swift b/Sources/Setup/DataStack.swift index 30d07b6..7c926ed 100644 --- a/Sources/Setup/DataStack.swift +++ b/Sources/Setup/DataStack.swift @@ -149,7 +149,7 @@ public final class DataStack: Equatable { let actualType = anyEntity.type if (actualType as AnyClass).isSubclass(of: type) { - entityTypesByName[entityDescription.name!] = actualType + entityTypesByName[entityDescription.name!] = (actualType as! CoreStoreObject.Type) } } } diff --git a/Sources/Setup/Dynamic Models/Dynamic Schema/CoreStoreSchema.swift b/Sources/Setup/Dynamic Models/Dynamic Schema/CoreStoreSchema.swift index 64cfc63..869c52e 100644 --- a/Sources/Setup/Dynamic Models/Dynamic Schema/CoreStoreSchema.swift +++ b/Sources/Setup/Dynamic Models/Dynamic Schema/CoreStoreSchema.swift @@ -137,7 +137,7 @@ public final class CoreStoreSchema: DynamicSchema { ) } - internal init(type: CoreStoreObject.Type, entityName: String, isAbstract: Bool, versionHashModifier: String?) { + internal init(type: DynamicObject.Type, entityName: String, isAbstract: Bool, versionHashModifier: String?) { self.type = type self.entityName = entityName @@ -168,7 +168,7 @@ public final class CoreStoreSchema: DynamicSchema { // MARK: DynamicEntity - internal let type: CoreStoreObject.Type + internal let type: DynamicObject.Type internal let entityName: EntityName internal let isAbstract: Bool internal let versionHashModifier: String? @@ -223,7 +223,8 @@ public final class CoreStoreSchema: DynamicSchema { description.isIndexed = attribute.isIndexed description.defaultValue = attribute.defaultValue description.isTransient = attribute.isTransient - // TODO: versionHash, renamingIdentifier, etc + description.versionHashModifier = attribute.versionHashModifier + description.renamingIdentifier = attribute.renamingIdentifier propertyDescriptions.append(description) case let relationship as RelationshipProtocol: @@ -233,7 +234,8 @@ public final class CoreStoreSchema: DynamicSchema { description.maxCount = relationship.maxCount description.isOrdered = relationship.isOrdered description.deleteRule = relationship.deleteRule - // TODO: versionHash, renamingIdentifier, etc + description.versionHashModifier = relationship.versionHashModifier + description.renamingIdentifier = relationship.renamingIdentifier propertyDescriptions.append(description) default: @@ -243,7 +245,7 @@ public final class CoreStoreSchema: DynamicSchema { return propertyDescriptions } - entityDescription.properties = createProperties(for: entity.type) + entityDescription.properties = createProperties(for: entity.type as! CoreStoreObject.Type) return entityDescription } @@ -293,7 +295,7 @@ public final class CoreStoreSchema: DynamicSchema { for (entity, entityDescription) in entityDescriptionsByEntity { let relationshipsByName = relationshipsByNameByEntity[entity]! - for child in Mirror(reflecting: entity.type.meta).children { + for child in Mirror(reflecting: (entity.type as! CoreStoreObject.Type).meta).children { switch child.value { @@ -360,7 +362,7 @@ public final class CoreStoreSchema: DynamicSchema { for (entity, entityDescription) in entityDescriptionsByEntity { connectBaseEntity( - mirror: Mirror(reflecting: entity.type.meta), + mirror: Mirror(reflecting: (entity.type as! CoreStoreObject.Type).meta), entityDescription: entityDescription ) } diff --git a/Sources/Setup/Dynamic Models/Entity.swift b/Sources/Setup/Dynamic Models/Entity.swift index 1dce650..03fe560 100644 --- a/Sources/Setup/Dynamic Models/Entity.swift +++ b/Sources/Setup/Dynamic Models/Entity.swift @@ -32,7 +32,7 @@ import ObjectiveC public protocol DynamicEntity { - var type: CoreStoreObject.Type { get } + var type: DynamicObject.Type { get } var entityName: EntityName { get } var isAbstract: Bool { get } var versionHashModifier: String? { get } @@ -41,7 +41,7 @@ public protocol DynamicEntity { // MARK: Entity -public struct Entity: DynamicEntity, Hashable { +public struct Entity: DynamicEntity, Hashable { public init(_ entityName: String, isAbstract: Bool = false, versionHashModifier: String? = nil) { @@ -59,7 +59,7 @@ public struct Entity: DynamicEntity, Hashable { // MARK: DynamicEntity - public let type: CoreStoreObject.Type + public let type: DynamicObject.Type public let entityName: EntityName public let isAbstract: Bool public let versionHashModifier: String? diff --git a/Sources/Setup/Dynamic Models/Relationship.swift b/Sources/Setup/Dynamic Models/Relationship.swift index 9f1b5b3..5071194 100644 --- a/Sources/Setup/Dynamic Models/Relationship.swift +++ b/Sources/Setup/Dynamic Models/Relationship.swift @@ -60,24 +60,24 @@ public enum RelationshipContainer { relationship.value = relationship2.value } - public convenience init(_ keyPath: KeyPath, deleteRule: DeleteRule = .nullify) { + public convenience init(_ keyPath: KeyPath, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { - self.init(keyPath: keyPath, inverseKeyPath: { nil }, deleteRule: deleteRule) + self.init(keyPath: keyPath, inverseKeyPath: { nil }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) } - public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToOne, deleteRule: DeleteRule = .nullify) { + public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToOne, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { - self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule) + self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) } - public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToManyOrdered, deleteRule: DeleteRule = .nullify) { + public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToManyOrdered, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { - self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule) + self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) } - public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToManyUnordered, deleteRule: DeleteRule = .nullify) { + public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToManyUnordered, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { - self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule) + self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) } public var value: D? { @@ -124,6 +124,8 @@ public enum RelationshipContainer { internal let minCount: Int = 0 internal let maxCount: Int = 1 internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?) + internal let versionHashModifier: String? + internal let renamingIdentifier: String? internal var parentObject: () -> CoreStoreObject = { @@ -133,11 +135,13 @@ public enum RelationshipContainer { // MARK: Private - private init(keyPath: KeyPath, inverseKeyPath: @escaping () -> KeyPath?, deleteRule: DeleteRule) { + private init(keyPath: KeyPath, inverseKeyPath: @escaping () -> KeyPath?, deleteRule: DeleteRule, versionHashModifier: String?, renamingIdentifier: String?) { self.keyPath = keyPath self.deleteRule = deleteRule.nativeValue self.inverse = (D.self, inverseKeyPath) + self.versionHashModifier = versionHashModifier + self.renamingIdentifier = renamingIdentifier } } @@ -163,24 +167,24 @@ public enum RelationshipContainer { relationship.value = relationship2.value } - public convenience init(_ keyPath: KeyPath, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) { + public convenience init(_ keyPath: KeyPath, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { - self.init(keyPath: keyPath, inverseKeyPath: { nil }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount) + self.init(keyPath: keyPath, inverseKeyPath: { nil }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) } - public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToOne, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) { + public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToOne, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { - self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount) + self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) } - public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToManyOrdered, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) { + public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToManyOrdered, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { - self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount) + self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) } - public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToManyUnordered, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) { + public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToManyUnordered, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { - self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount) + self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) } // TODO: add subscripts, indexed operations for more performant single updates @@ -237,6 +241,8 @@ public enum RelationshipContainer { internal let minCount: Int internal let maxCount: Int internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?) + internal let versionHashModifier: String? + internal let renamingIdentifier: String? internal var parentObject: () -> CoreStoreObject = { @@ -246,11 +252,13 @@ public enum RelationshipContainer { // MARK: Private - private init(keyPath: String, inverseKeyPath: @escaping () -> String?, deleteRule: DeleteRule, minCount: Int, maxCount: Int) { + private init(keyPath: String, inverseKeyPath: @escaping () -> String?, deleteRule: DeleteRule, minCount: Int, maxCount: Int, versionHashModifier: String?, renamingIdentifier: String?) { self.keyPath = keyPath self.deleteRule = deleteRule.nativeValue self.inverse = (D.self, inverseKeyPath) + self.versionHashModifier = versionHashModifier + self.renamingIdentifier = renamingIdentifier let range = (max(0, minCount) ... maxCount) self.minCount = range.lowerBound @@ -285,24 +293,24 @@ public enum RelationshipContainer { relationship.value = Set(relationship2.value) } - public convenience init(_ keyPath: KeyPath, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) { + public convenience init(_ keyPath: KeyPath, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { - self.init(keyPath: keyPath, inverseKeyPath: { nil }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount) + self.init(keyPath: keyPath, inverseKeyPath: { nil }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) } - public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToOne, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) { + public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToOne, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { - self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount) + self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) } - public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToManyOrdered, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) { + public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToManyOrdered, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { - self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount) + self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) } - public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToManyUnordered, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) { + public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer.ToManyUnordered, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { - self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount) + self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) } // TODO: add subscripts, indexed operations for more performant single updates @@ -359,6 +367,8 @@ public enum RelationshipContainer { internal let minCount: Int internal let maxCount: Int internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?) + internal let versionHashModifier: String? + internal let renamingIdentifier: String? internal var parentObject: () -> CoreStoreObject = { @@ -368,11 +378,13 @@ public enum RelationshipContainer { // MARK: Private - private init(keyPath: KeyPath, inverseKeyPath: @escaping () -> KeyPath?, deleteRule: DeleteRule, minCount: Int, maxCount: Int) { + private init(keyPath: KeyPath, inverseKeyPath: @escaping () -> KeyPath?, deleteRule: DeleteRule, minCount: Int, maxCount: Int, versionHashModifier: String?, renamingIdentifier: String?) { self.keyPath = keyPath self.deleteRule = deleteRule.nativeValue self.inverse = (D.self, inverseKeyPath) + self.versionHashModifier = versionHashModifier + self.renamingIdentifier = renamingIdentifier let range = (max(0, minCount) ... maxCount) self.minCount = range.lowerBound @@ -412,6 +424,8 @@ internal protocol RelationshipProtocol: class { var deleteRule: NSDeleteRule { get } var inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?) { get } var parentObject: () -> CoreStoreObject { get set } + var versionHashModifier: String? { get } + var renamingIdentifier: String? { get } var minCount: Int { get } var maxCount: Int { get } } diff --git a/Sources/Setup/Dynamic Models/Value.swift b/Sources/Setup/Dynamic Models/Value.swift index 5394560..d8cd2da 100644 --- a/Sources/Setup/Dynamic Models/Value.swift +++ b/Sources/Setup/Dynamic Models/Value.swift @@ -59,12 +59,14 @@ public enum ValueContainer { attribute.value = attribute2.value } - public init(_ keyPath: KeyPath, `default`: V = V.cs_emptyValue(), isIndexed: Bool = false, isTransient: Bool = false, customGetter: @escaping (_ `self`: O, _ getValue: () -> V) -> V = { $1() }, customSetter: @escaping (_ `self`: O, _ setValue: (V) -> Void, _ newValue: V) -> Void = { $1($2) }) { + public init(_ keyPath: KeyPath, `default`: V = V.cs_emptyValue(), isIndexed: Bool = false, isTransient: Bool = false, versionHashModifier: String? = nil, renamingIdentifier: String? = nil, customGetter: @escaping (_ `self`: O, _ getValue: () -> V) -> V = { $1() }, customSetter: @escaping (_ `self`: O, _ setValue: (V) -> Void, _ newValue: V) -> Void = { $1($2) }) { self.keyPath = keyPath self.isIndexed = isIndexed self.isTransient = isTransient self.defaultValue = `default`.cs_toImportableNativeType() + self.versionHashModifier = versionHashModifier + self.renamingIdentifier = renamingIdentifier self.customGetter = customGetter self.customSetter = customSetter } @@ -129,6 +131,8 @@ public enum ValueContainer { internal let isIndexed: Bool internal let isTransient: Bool internal let defaultValue: Any? + internal let versionHashModifier: String? + internal let renamingIdentifier: String? internal var parentObject: () -> CoreStoreObject = { @@ -162,11 +166,13 @@ public enum ValueContainer { attribute.value = attribute2.value } - public init(_ keyPath: KeyPath, `default`: V? = nil, isTransient: Bool = false, customGetter: @escaping (_ `self`: O, _ getValue: () -> V?) -> V? = { $1() }, customSetter: @escaping (_ `self`: O, _ setValue: (V?) -> Void, _ newValue: V?) -> Void = { $1($2) }) { + public init(_ keyPath: KeyPath, `default`: V? = nil, isTransient: Bool = false, versionHashModifier: String? = nil, renamingIdentifier: String? = nil, customGetter: @escaping (_ `self`: O, _ getValue: () -> V?) -> V? = { $1() }, customSetter: @escaping (_ `self`: O, _ setValue: (V?) -> Void, _ newValue: V?) -> Void = { $1($2) }) { self.keyPath = keyPath self.isTransient = isTransient self.defaultValue = `default`?.cs_toImportableNativeType() + self.versionHashModifier = versionHashModifier + self.renamingIdentifier = renamingIdentifier self.customGetter = customGetter self.customSetter = customSetter } @@ -230,6 +236,8 @@ public enum ValueContainer { internal let isIndexed = false internal let isTransient: Bool internal let defaultValue: Any? + internal let versionHashModifier: String? + internal let renamingIdentifier: String? internal var parentObject: () -> CoreStoreObject = { @@ -263,12 +271,14 @@ public enum TransformableContainer { attribute.value = attribute2.value } - public init(_ keyPath: KeyPath, `default`: V, isIndexed: Bool = false, isTransient: Bool = false, customGetter: @escaping (_ `self`: O, _ getValue: () -> V) -> V = { $1() }, customSetter: @escaping (_ `self`: O, _ setValue: (V) -> Void, _ newValue: V) -> Void = { $1($2) }) { + public init(_ keyPath: KeyPath, `default`: V, isIndexed: Bool = false, isTransient: Bool = false, versionHashModifier: String? = nil, renamingIdentifier: String? = nil, customGetter: @escaping (_ `self`: O, _ getValue: () -> V) -> V = { $1() }, customSetter: @escaping (_ `self`: O, _ setValue: (V) -> Void, _ newValue: V) -> Void = { $1($2) }) { self.keyPath = keyPath self.defaultValue = `default` self.isIndexed = isIndexed self.isTransient = isTransient + self.versionHashModifier = versionHashModifier + self.renamingIdentifier = renamingIdentifier self.customGetter = customGetter self.customSetter = customSetter } @@ -332,6 +342,8 @@ public enum TransformableContainer { internal let isIndexed: Bool internal let isTransient: Bool internal let defaultValue: Any? + internal let versionHashModifier: String? + internal let renamingIdentifier: String? internal var parentObject: () -> CoreStoreObject = { @@ -365,12 +377,14 @@ public enum TransformableContainer { attribute.value = attribute2.value } - public init(_ keyPath: KeyPath, `default`: V? = nil, isIndexed: Bool = false, isTransient: Bool = false, customGetter: @escaping (_ `self`: O, _ getValue: () -> V?) -> V? = { $1() }, customSetter: @escaping (_ `self`: O, _ setValue: (V?) -> Void, _ newValue: V?) -> Void = { $1($2) }) { + public init(_ keyPath: KeyPath, `default`: V? = nil, isIndexed: Bool = false, isTransient: Bool = false, versionHashModifier: String? = nil, renamingIdentifier: String? = nil, customGetter: @escaping (_ `self`: O, _ getValue: () -> V?) -> V? = { $1() }, customSetter: @escaping (_ `self`: O, _ setValue: (V?) -> Void, _ newValue: V?) -> Void = { $1($2) }) { self.keyPath = keyPath self.defaultValue = `default` self.isIndexed = isIndexed self.isTransient = isTransient + self.versionHashModifier = versionHashModifier + self.renamingIdentifier = renamingIdentifier self.customGetter = customGetter self.customSetter = customSetter } @@ -434,6 +448,8 @@ public enum TransformableContainer { internal let isIndexed: Bool internal let isTransient: Bool internal let defaultValue: Any? + internal let versionHashModifier: String? + internal let renamingIdentifier: String? internal var parentObject: () -> CoreStoreObject = { @@ -460,5 +476,7 @@ internal protocol AttributeProtocol: class { var isIndexed: Bool { get } var isTransient: Bool { get } var defaultValue: Any? { get } + var versionHashModifier: String? { get } + var renamingIdentifier: String? { get } var parentObject: () -> CoreStoreObject { get set } }