diff --git a/Sources/AttributeProtocol.swift b/Sources/AttributeProtocol.swift index df70185..5447d9a 100644 --- a/Sources/AttributeProtocol.swift +++ b/Sources/AttributeProtocol.swift @@ -30,16 +30,19 @@ import CoreData // MARK: - AttributeProtocol internal protocol AttributeProtocol: PropertyProtocol { - - static var attributeType: NSAttributeType { get } - - var isOptional: Bool { get } - var isTransient: Bool { get } - var allowsExternalBinaryDataStorage: Bool { get } - var versionHashModifier: () -> String? { get } - var renamingIdentifier: () -> String? { get } - var defaultValue: () -> Any? { get } - var affectedByKeyPaths: () -> Set { get } + + typealias EntityDescriptionValues = ( + attributeType: NSAttributeType, + isOptional: Bool, + isTransient: Bool, + allowsExternalBinaryDataStorage: Bool, + versionHashModifier: String?, + renamingIdentifier: String?, + affectedByKeyPaths: Set, + defaultValue: Any? + ) + + var entityDescriptionValues: () -> EntityDescriptionValues { get } var rawObject: CoreStoreManagedObject? { get set } var getter: CoreStoreManagedObject.CustomGetter? { get } var setter: CoreStoreManagedObject.CustomSetter? { get } diff --git a/Sources/CSError.swift b/Sources/CSError.swift index b250245..96b5ad0 100644 --- a/Sources/CSError.swift +++ b/Sources/CSError.swift @@ -44,6 +44,17 @@ public final class CSError: NSError { */ @objc public static let errorDomain = CoreStoreErrorDomain + + public var bridgeToSwift: CoreStoreError { + + if let swift = self.swiftError { + + return swift + } + let swift = CoreStoreError(_bridgedNSError: self) ?? .unknown + self.swiftError = swift + return swift + } // MARK: NSObject @@ -88,21 +99,7 @@ public final class CSError: NSError { } @available(*, deprecated, message: "CoreStore Objective-C API will be removed soon.") -extension CSError: CoreStoreObjectiveCType { - - // MARK: CoreStoreObjectiveCType - - public var bridgeToSwift: CoreStoreError { - - if let swift = self.swiftError { - - return swift - } - let swift = CoreStoreError(_bridgedNSError: self) ?? .unknown - self.swiftError = swift - return swift - } -} +extension CSError: CoreStoreObjectiveCType {} // MARK: - CSErrorCode @@ -156,16 +153,7 @@ public enum CSErrorCode: Int { // MARK: - CoreStoreError -@available(*, deprecated, message: "CoreStore Objective-C API will be removed soon.") -extension CoreStoreError: CoreStoreSwiftType, _ObjectiveCBridgeableError { - - // MARK: CoreStoreSwiftType - - public var bridgeToObjectiveC: CSError { - - return CSError(self) - } - +extension CoreStoreError: _ObjectiveCBridgeableError { // MARK: _ObjectiveCBridgeableError @@ -265,9 +253,11 @@ extension CoreStoreError: CoreStoreSwiftType, _ObjectiveCBridgeableError { } -// MARK: Internal +// MARK: - Error extension Error { + + // MARK: Internal internal var bridgeToSwift: CoreStoreError { @@ -303,3 +293,17 @@ extension Error { } } } + + +// MARK: - CoreStoreError + +@available(*, deprecated, message: "CoreStore Objective-C API will be removed soon.") +extension CoreStoreError: CoreStoreSwiftType { + + // MARK: CoreStoreSwiftType + + public var bridgeToObjectiveC: CSError { + + return CSError(self) + } +} diff --git a/Sources/CoreStoreSchema.swift b/Sources/CoreStoreSchema.swift index 7e78ced..e6ff4e1 100644 --- a/Sources/CoreStoreSchema.swift +++ b/Sources/CoreStoreSchema.swift @@ -292,17 +292,18 @@ public final class CoreStoreSchema: DynamicSchema { !NSManagedObject.instancesRespond(to: Selector(attribute.keyPath)), "Attribute Property name \"\(String(reflecting: entity.type)).\(attribute.keyPath)\" is not allowed because it collides with \"\(String(reflecting: NSManagedObject.self)).\(attribute.keyPath)\"" ) + let entityDescriptionValues = attribute.entityDescriptionValues() let description = NSAttributeDescription() description.name = attribute.keyPath - description.attributeType = Swift.type(of: attribute).attributeType - description.isOptional = attribute.isOptional - description.defaultValue = attribute.defaultValue() - description.isTransient = attribute.isTransient - description.allowsExternalBinaryDataStorage = attribute.allowsExternalBinaryDataStorage - description.versionHashModifier = attribute.versionHashModifier() - description.renamingIdentifier = attribute.renamingIdentifier() + description.attributeType = entityDescriptionValues.attributeType + description.isOptional = entityDescriptionValues.isOptional + description.defaultValue = entityDescriptionValues.defaultValue + description.isTransient = entityDescriptionValues.isTransient + description.allowsExternalBinaryDataStorage = entityDescriptionValues.allowsExternalBinaryDataStorage + description.versionHashModifier = entityDescriptionValues.versionHashModifier + description.renamingIdentifier = entityDescriptionValues.renamingIdentifier propertyDescriptions.append(description) - keyPathsByAffectedKeyPaths[attribute.keyPath] = attribute.affectedByKeyPaths() + keyPathsByAffectedKeyPaths[attribute.keyPath] = entityDescriptionValues.affectedByKeyPaths customGetterSetterByKeyPaths[attribute.keyPath] = (attribute.getter, attribute.setter) case let relationship as RelationshipProtocol: @@ -310,16 +311,17 @@ public final class CoreStoreSchema: DynamicSchema { !NSManagedObject.instancesRespond(to: Selector(relationship.keyPath)), "Relationship Property name \"\(String(reflecting: entity.type)).\(relationship.keyPath)\" is not allowed because it collides with \"\(String(reflecting: NSManagedObject.self)).\(relationship.keyPath)\"" ) + let entityDescriptionValues = relationship.entityDescriptionValues() let description = NSRelationshipDescription() description.name = relationship.keyPath - description.minCount = relationship.minCount - description.maxCount = relationship.maxCount - description.isOrdered = relationship.isOrdered - description.deleteRule = relationship.deleteRule - description.versionHashModifier = relationship.versionHashModifier() - description.renamingIdentifier = relationship.renamingIdentifier() + description.minCount = entityDescriptionValues.minCount + description.maxCount = entityDescriptionValues.maxCount + description.isOrdered = entityDescriptionValues.isOrdered + description.deleteRule = entityDescriptionValues.deleteRule + description.versionHashModifier = entityDescriptionValues.versionHashModifier + description.renamingIdentifier = entityDescriptionValues.renamingIdentifier propertyDescriptions.append(description) - keyPathsByAffectedKeyPaths[relationship.keyPath] = relationship.affectedByKeyPaths() + keyPathsByAffectedKeyPaths[relationship.keyPath] = entityDescriptionValues.affectedByKeyPaths default: continue @@ -384,12 +386,12 @@ public final class CoreStoreSchema: DynamicSchema { switch property { case let relationship as RelationshipProtocol: - let (destinationType, destinationKeyPath) = relationship.inverse + let (destinationType, destinationKeyPath) = relationship.entityDescriptionValues().inverse let destinationEntity = findEntity(for: destinationType) let description = relationshipsByName[relationship.keyPath]! description.destinationEntity = entityDescriptionsByEntity[destinationEntity]! - if let destinationKeyPath = destinationKeyPath() { + if let destinationKeyPath = destinationKeyPath { let inverseRelationshipDescription = findInverseRelationshipMatching( destinationEntity: destinationEntity, diff --git a/Sources/Relationship.swift b/Sources/Relationship.swift index 74c72d5..95946c0 100644 --- a/Sources/Relationship.swift +++ b/Sources/Relationship.swift @@ -258,15 +258,7 @@ public enum RelationshipContainer { // MARK: RelationshipProtocol - internal let isToMany = false - internal let isOrdered = false - internal let deleteRule: NSDeleteRule - internal let minCount: Int = 0 - internal let maxCount: Int = 1 - internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPathString?) - internal let versionHashModifier: () -> String? - internal let renamingIdentifier: () -> String? - internal let affectedByKeyPaths: () -> Set + internal let entityDescriptionValues: () -> RelationshipProtocol.EntityDescriptionValues internal var rawObject: CoreStoreManagedObject? internal var nativeValue: NSManagedObject? { @@ -324,11 +316,19 @@ public enum RelationshipContainer { private init(keyPath: KeyPathString, inverseKeyPath: @escaping () -> KeyPathString?, deleteRule: DeleteRule, versionHashModifier: @autoclosure @escaping () -> String?, renamingIdentifier: @autoclosure @escaping () -> String?, affectedByKeyPaths: @autoclosure @escaping () -> Set) { self.keyPath = keyPath - self.deleteRule = deleteRule.nativeValue - self.inverse = (D.self, inverseKeyPath) - self.versionHashModifier = versionHashModifier - self.renamingIdentifier = renamingIdentifier - self.affectedByKeyPaths = affectedByKeyPaths + self.entityDescriptionValues = { + ( + isToMany: false, + isOrdered: false, + deleteRule: deleteRule.nativeValue, + inverse: (type: D.self, keyPath: inverseKeyPath()), + versionHashModifier: versionHashModifier(), + renamingIdentifier: renamingIdentifier(), + affectedByKeyPaths: affectedByKeyPaths(), + minCount: 0, + maxCount: 1 + ) + } } } @@ -553,16 +553,7 @@ public enum RelationshipContainer { // MARK: RelationshipProtocol - internal let isToMany = true - internal let isOptional = true - internal let isOrdered = true - internal let deleteRule: NSDeleteRule - internal let minCount: Int - internal let maxCount: Int - internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPathString?) - internal let versionHashModifier: () -> String? - internal let renamingIdentifier: () -> String? - internal let affectedByKeyPaths: () -> Set + internal let entityDescriptionValues: () -> RelationshipProtocol.EntityDescriptionValues internal var rawObject: CoreStoreManagedObject? internal var nativeValue: NSOrderedSet { @@ -620,15 +611,20 @@ public enum RelationshipContainer { private init(keyPath: String, minCount: Int, maxCount: Int, inverseKeyPath: @escaping () -> String?, deleteRule: DeleteRule, versionHashModifier: @autoclosure @escaping () -> String?, renamingIdentifier: @autoclosure @escaping () -> String?, affectedByKeyPaths: @autoclosure @escaping () -> Set) { self.keyPath = keyPath - self.deleteRule = deleteRule.nativeValue - self.inverse = (D.self, inverseKeyPath) - self.versionHashModifier = versionHashModifier - self.renamingIdentifier = renamingIdentifier - - let range = (Swift.max(0, minCount) ... maxCount) - self.minCount = range.lowerBound - self.maxCount = range.upperBound - self.affectedByKeyPaths = affectedByKeyPaths + self.entityDescriptionValues = { + let range = (Swift.max(0, minCount) ... maxCount) + return ( + isToMany: true, + isOrdered: true, + deleteRule: deleteRule.nativeValue, + inverse: (type: D.self, keyPath: inverseKeyPath()), + versionHashModifier: versionHashModifier(), + renamingIdentifier: renamingIdentifier(), + affectedByKeyPaths: affectedByKeyPaths(), + minCount: range.lowerBound, + maxCount: range.upperBound + ) + } } } @@ -853,17 +849,8 @@ public enum RelationshipContainer { // MARK: RelationshipProtocol - - internal let isToMany = true - internal let isOptional = true - internal let isOrdered = false - internal let deleteRule: NSDeleteRule - internal let minCount: Int - internal let maxCount: Int - internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPathString?) - internal let versionHashModifier: () -> String? - internal let renamingIdentifier: () -> String? - internal let affectedByKeyPaths: () -> Set + + internal let entityDescriptionValues: () -> RelationshipProtocol.EntityDescriptionValues internal var rawObject: CoreStoreManagedObject? internal var nativeValue: NSSet { @@ -921,15 +908,20 @@ public enum RelationshipContainer { private init(keyPath: KeyPathString, inverseKeyPath: @escaping () -> KeyPathString?, deleteRule: DeleteRule, minCount: Int, maxCount: Int, versionHashModifier: @autoclosure @escaping () -> String?, renamingIdentifier: @autoclosure @escaping () -> String?, affectedByKeyPaths: @autoclosure @escaping () -> Set) { self.keyPath = keyPath - self.deleteRule = deleteRule.nativeValue - self.inverse = (D.self, inverseKeyPath) - self.versionHashModifier = versionHashModifier - self.renamingIdentifier = renamingIdentifier - - let range = (Swift.max(0, minCount) ... maxCount) - self.minCount = range.lowerBound - self.maxCount = range.upperBound - self.affectedByKeyPaths = affectedByKeyPaths + self.entityDescriptionValues = { + let range = (Swift.max(0, minCount) ... maxCount) + return ( + isToMany: true, + isOrdered: false, + deleteRule: deleteRule.nativeValue, + inverse: (type: D.self, keyPath: inverseKeyPath()), + versionHashModifier: versionHashModifier(), + renamingIdentifier: renamingIdentifier(), + affectedByKeyPaths: affectedByKeyPaths(), + minCount: range.lowerBound, + maxCount: range.upperBound + ) + } } } diff --git a/Sources/RelationshipProtocol.swift b/Sources/RelationshipProtocol.swift index 0f53b88..cd0b4c6 100644 --- a/Sources/RelationshipProtocol.swift +++ b/Sources/RelationshipProtocol.swift @@ -31,15 +31,20 @@ import CoreData internal protocol RelationshipProtocol: PropertyProtocol { - var isToMany: Bool { get } - var isOrdered: Bool { get } - var deleteRule: NSDeleteRule { get } - var inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPathString?) { get } - var affectedByKeyPaths: () -> Set { get } + typealias EntityDescriptionValues = ( + isToMany: Bool, + isOrdered: Bool, + deleteRule: NSDeleteRule, + inverse: (type: CoreStoreObject.Type, KeyPathString?), + versionHashModifier: String?, + renamingIdentifier: String?, + affectedByKeyPaths: Set, + minCount: Int, + maxCount: Int + ) + + var entityDescriptionValues: () -> EntityDescriptionValues { get } + var rawObject: CoreStoreManagedObject? { get set } - var versionHashModifier: () -> String? { get } - var renamingIdentifier: () -> String? { get } - var minCount: Int { get } - var maxCount: Int { get } var valueForSnapshot: Any? { get } } diff --git a/Sources/Transformable.swift b/Sources/Transformable.swift index 5129047..33194f0 100644 --- a/Sources/Transformable.swift +++ b/Sources/Transformable.swift @@ -127,14 +127,20 @@ public enum TransformableContainer { affectedByKeyPaths: @autoclosure @escaping () -> Set = []) { self.keyPath = keyPath - self.defaultValue = initial - self.isTransient = isTransient - self.allowsExternalBinaryDataStorage = allowsExternalBinaryDataStorage - self.versionHashModifier = versionHashModifier - self.renamingIdentifier = renamingIdentifier + self.entityDescriptionValues = { + ( + attributeType: .transformableAttributeType, + isOptional: false, + isTransient: isTransient, + allowsExternalBinaryDataStorage: allowsExternalBinaryDataStorage, + versionHashModifier: versionHashModifier(), + renamingIdentifier: renamingIdentifier(), + affectedByKeyPaths: affectedByKeyPaths(), + defaultValue: initial() + ) + } self.customGetter = customGetter self.customSetter = customSetter - self.affectedByKeyPaths = affectedByKeyPaths } /** @@ -215,19 +221,8 @@ public enum TransformableContainer { // MARK: AttributeProtocol - - internal static var attributeType: NSAttributeType { - return .transformableAttributeType - } - - internal let isOptional = false - internal let isTransient: Bool - internal let allowsExternalBinaryDataStorage: Bool - internal let versionHashModifier: () -> String? - internal let renamingIdentifier: () -> String? - internal let defaultValue: () -> Any? - internal let affectedByKeyPaths: () -> Set + internal let entityDescriptionValues: () -> AttributeProtocol.EntityDescriptionValues internal var rawObject: CoreStoreManagedObject? internal private(set) lazy var getter: CoreStoreManagedObject.CustomGetter? = Internals.with { [unowned self] in @@ -349,14 +344,20 @@ public enum TransformableContainer { affectedByKeyPaths: @autoclosure @escaping () -> Set = []) { self.keyPath = keyPath - self.defaultValue = initial - self.isTransient = isTransient - self.allowsExternalBinaryDataStorage = allowsExternalBinaryDataStorage - self.versionHashModifier = versionHashModifier - self.renamingIdentifier = renamingIdentifier + self.entityDescriptionValues = { + ( + attributeType: .transformableAttributeType, + isOptional: true, + isTransient: isTransient, + allowsExternalBinaryDataStorage: allowsExternalBinaryDataStorage, + versionHashModifier: versionHashModifier(), + renamingIdentifier: renamingIdentifier(), + affectedByKeyPaths: affectedByKeyPaths(), + defaultValue: initial() + ) + } self.customGetter = customGetter self.customSetter = customSetter - self.affectedByKeyPaths = affectedByKeyPaths } /** @@ -438,18 +439,7 @@ public enum TransformableContainer { // MARK: AttributeProtocol - internal static var attributeType: NSAttributeType { - - return .transformableAttributeType - } - - internal let isOptional = true - internal let isTransient: Bool - internal let allowsExternalBinaryDataStorage: Bool - internal let versionHashModifier: () -> String? - internal let renamingIdentifier: () -> String? - internal let defaultValue: () -> Any? - internal let affectedByKeyPaths: () -> Set + internal let entityDescriptionValues: () -> AttributeProtocol.EntityDescriptionValues internal var rawObject: CoreStoreManagedObject? internal private(set) lazy var getter: CoreStoreManagedObject.CustomGetter? = Internals.with { [unowned self] in diff --git a/Sources/Value.swift b/Sources/Value.swift index 2bd6cef..be33313 100644 --- a/Sources/Value.swift +++ b/Sources/Value.swift @@ -121,13 +121,20 @@ public enum ValueContainer { affectedByKeyPaths: @autoclosure @escaping () -> Set = []) { self.keyPath = keyPath - self.isTransient = isTransient - self.defaultValue = { initial().cs_toQueryableNativeType() } - self.versionHashModifier = versionHashModifier - self.renamingIdentifier = renamingIdentifier + self.entityDescriptionValues = { + ( + attributeType: V.cs_rawAttributeType, + isOptional: false, + isTransient: isTransient, + allowsExternalBinaryDataStorage: false, + versionHashModifier: versionHashModifier(), + renamingIdentifier: renamingIdentifier(), + affectedByKeyPaths: affectedByKeyPaths(), + defaultValue: initial().cs_toQueryableNativeType() + ) + } self.customGetter = customGetter self.customSetter = customSetter - self.affectedByKeyPaths = affectedByKeyPaths } /** @@ -210,19 +217,8 @@ public enum ValueContainer { // MARK: AttributeProtocol - - internal static var attributeType: NSAttributeType { - - return V.cs_rawAttributeType - } - internal let isOptional = false - internal let isTransient: Bool - internal let allowsExternalBinaryDataStorage = false - internal let versionHashModifier: () -> String? - internal let renamingIdentifier: () -> String? - internal let defaultValue: () -> Any? - internal let affectedByKeyPaths: () -> Set + internal let entityDescriptionValues: () -> AttributeProtocol.EntityDescriptionValues internal var rawObject: CoreStoreManagedObject? internal private(set) lazy var getter: CoreStoreManagedObject.CustomGetter? = Internals.with { [unowned self] in @@ -344,13 +340,20 @@ public enum ValueContainer { affectedByKeyPaths: @autoclosure @escaping () -> Set = []) { self.keyPath = keyPath - self.isTransient = isTransient - self.defaultValue = { initial()?.cs_toQueryableNativeType() } - self.versionHashModifier = versionHashModifier - self.renamingIdentifier = renamingIdentifier + self.entityDescriptionValues = { + ( + attributeType: V.cs_rawAttributeType, + isOptional: true, + isTransient: isTransient, + allowsExternalBinaryDataStorage: false, + versionHashModifier: versionHashModifier(), + renamingIdentifier: renamingIdentifier(), + affectedByKeyPaths: affectedByKeyPaths(), + defaultValue: initial()?.cs_toQueryableNativeType() + ) + } self.customGetter = customGetter self.customSetter = customSetter - self.affectedByKeyPaths = affectedByKeyPaths } /** @@ -432,19 +435,8 @@ public enum ValueContainer { // MARK: AttributeProtocol - - internal static var attributeType: NSAttributeType { - - return V.cs_rawAttributeType - } - - internal let isOptional = true - internal let isTransient: Bool - internal let allowsExternalBinaryDataStorage = false - internal let versionHashModifier: () -> String? - internal let renamingIdentifier: () -> String? - internal let defaultValue: () -> Any? - internal let affectedByKeyPaths: () -> Set + + internal let entityDescriptionValues: () -> AttributeProtocol.EntityDescriptionValues internal var rawObject: CoreStoreManagedObject? internal private(set) lazy var getter: CoreStoreManagedObject.CustomGetter? = Internals.with { [unowned self] in