WIP: dynamic migrations

This commit is contained in:
John Estropia
2017-04-25 18:08:43 +09:00
parent 53ab140341
commit 54c81d23f5
7 changed files with 147 additions and 82 deletions

View File

@@ -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)
}
}
}

View File

@@ -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
)
}

View File

@@ -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<O: CoreStoreObject>: DynamicEntity, Hashable {
public struct Entity<O: DynamicObject>: DynamicEntity, Hashable {
public init(_ entityName: String, isAbstract: Bool = false, versionHashModifier: String? = nil) {
@@ -59,7 +59,7 @@ public struct Entity<O: CoreStoreObject>: 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?

View File

@@ -60,24 +60,24 @@ public enum RelationshipContainer<O: CoreStoreObject> {
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<D>.ToOne<O>, deleteRule: DeleteRule = .nullify) {
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>, 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<D>.ToManyOrdered<O>, deleteRule: DeleteRule = .nullify) {
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>, 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<D>.ToManyUnordered<O>, deleteRule: DeleteRule = .nullify) {
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>, 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<O: CoreStoreObject> {
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<O: CoreStoreObject> {
// 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<O: CoreStoreObject> {
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<D>.ToOne<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) {
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>, 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<D>.ToManyOrdered<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) {
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>, 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<D>.ToManyUnordered<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) {
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>, 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<O: CoreStoreObject> {
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<O: CoreStoreObject> {
// 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<O: CoreStoreObject> {
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<D>.ToOne<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) {
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>, 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<D>.ToManyOrdered<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) {
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>, 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<D>.ToManyUnordered<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0) {
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>, 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<O: CoreStoreObject> {
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<O: CoreStoreObject> {
// 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 }
}

View File

@@ -59,12 +59,14 @@ public enum ValueContainer<O: CoreStoreObject> {
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<O: CoreStoreObject> {
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<O: CoreStoreObject> {
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<O: CoreStoreObject> {
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<O: CoreStoreObject> {
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<O: CoreStoreObject> {
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<O: CoreStoreObject> {
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<O: CoreStoreObject> {
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 }
}