diff --git a/CoreStore.xcodeproj/project.pbxproj b/CoreStore.xcodeproj/project.pbxproj index 9d27086..7e25b1e 100644 --- a/CoreStore.xcodeproj/project.pbxproj +++ b/CoreStore.xcodeproj/project.pbxproj @@ -603,10 +603,10 @@ B56E4EE023CEBCF000E1708C /* FieldOptionalType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */; }; B56E4EE123CEBCF000E1708C /* FieldOptionalType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */; }; B56E4EE223CEBCF000E1708C /* FieldOptionalType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */; }; - B56E4EE423CEDF0900E1708C /* Field.Computed.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Computed.swift */; }; - B56E4EE523CEDF0900E1708C /* Field.Computed.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Computed.swift */; }; - B56E4EE623CEDF0900E1708C /* Field.Computed.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Computed.swift */; }; - B56E4EE723CEDF0900E1708C /* Field.Computed.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Computed.swift */; }; + B56E4EE423CEDF0900E1708C /* Field.Virtual.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */; }; + B56E4EE523CEDF0900E1708C /* Field.Virtual.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */; }; + B56E4EE623CEDF0900E1708C /* Field.Virtual.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */; }; + B56E4EE723CEDF0900E1708C /* Field.Virtual.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */; }; B57D27BE1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; }; B57D27BF1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; }; B57D27C01D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; }; @@ -1122,7 +1122,7 @@ B56E4ED323CDB54A00E1708C /* FieldProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldProtocol.swift; sourceTree = ""; }; B56E4ED823CEB8E700E1708C /* FieldStorableType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldStorableType.swift; sourceTree = ""; }; B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldOptionalType.swift; sourceTree = ""; }; - B56E4EE323CEDF0900E1708C /* Field.Computed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.Computed.swift; sourceTree = ""; }; + B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.Virtual.swift; sourceTree = ""; }; B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTestDataTestCase.swift; sourceTree = ""; }; B57D27C11D0BC20100539C58 /* QueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryTests.swift; sourceTree = ""; }; B57E6FA123D302FA000FD031 /* Field.Relationship.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.Relationship.swift; sourceTree = ""; }; @@ -1622,7 +1622,7 @@ children = ( B56E4EC923CD9B4800E1708C /* Field.swift */, B56E4ECE23CD9E4200E1708C /* Field.Stored.swift */, - B56E4EE323CEDF0900E1708C /* Field.Computed.swift */, + B56E4EE323CEDF0900E1708C /* Field.Virtual.swift */, B50C3EE423D153EA00B29880 /* Field.Coded.swift */, B57E6FA123D302FA000FD031 /* Field.Relationship.swift */, B50C3EDE23D05BB200B29880 /* Coders */, @@ -2408,7 +2408,7 @@ B5FAD6A91B50A4B400714891 /* Progress+Convenience.swift in Sources */, B5E84EFC1AFF846E0064E85B /* SynchronousDataTransaction.swift in Sources */, B5215CA91FA4810300139E3A /* QueryChainBuilder.swift in Sources */, - B56E4EE423CEDF0900E1708C /* Field.Computed.swift in Sources */, + B56E4EE423CEDF0900E1708C /* Field.Virtual.swift in Sources */, B50E174D23517C03004F033C /* Internals.DiffableDataUIDispatcher.StagedChangeset.swift in Sources */, B5E222231CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */, B5E84F281AFF84920064E85B /* NSManagedObject+Convenience.swift in Sources */, @@ -2659,7 +2659,7 @@ B514EF0F23A8DB180093DBA4 /* DiffableDataSource.Target.swift in Sources */, B52F744B1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */, B5AEFAB61C9962AE00AD137F /* CoreStoreBridge.swift in Sources */, - B56E4EE523CEDF0900E1708C /* Field.Computed.swift in Sources */, + B56E4EE523CEDF0900E1708C /* Field.Virtual.swift in Sources */, B5E2222C1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */, 82BA18A71C4BBD2900A0916E /* CoreStore+Logging.swift in Sources */, B50E174E23517C03004F033C /* Internals.DiffableDataUIDispatcher.StagedChangeset.swift in Sources */, @@ -2910,7 +2910,7 @@ B514EF1123A8DB190093DBA4 /* DiffableDataSource.Target.swift in Sources */, B50E175A23517DE4004F033C /* Differentiable.swift in Sources */, B52F744D1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */, - B56E4EE723CEDF0900E1708C /* Field.Computed.swift in Sources */, + B56E4EE723CEDF0900E1708C /* Field.Virtual.swift in Sources */, B52DD19A1BE1F92800949AFE /* CoreStore+Logging.swift in Sources */, B52DD1A71BE1F93200949AFE /* BaseDataTransaction+Querying.swift in Sources */, B546F96C1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */, @@ -3161,7 +3161,7 @@ B514EF1023A8DB190093DBA4 /* DiffableDataSource.Target.swift in Sources */, B563218A1BD65216006C9394 /* SynchronousDataTransaction.swift in Sources */, B52F744C1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */, - B56E4EE623CEDF0900E1708C /* Field.Computed.swift in Sources */, + B56E4EE623CEDF0900E1708C /* Field.Virtual.swift in Sources */, B5AEFAB71C9962AE00AD137F /* CoreStoreBridge.swift in Sources */, B5E2222D1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */, B50E174F23517C03004F033C /* Internals.DiffableDataUIDispatcher.StagedChangeset.swift in Sources */, diff --git a/CoreStoreTests/DynamicModelTests.swift b/CoreStoreTests/DynamicModelTests.swift index 106f7f5..d9f817c 100644 --- a/CoreStoreTests/DynamicModelTests.swift +++ b/CoreStoreTests/DynamicModelTests.swift @@ -100,14 +100,14 @@ class Person: CoreStoreObject { @Field.Stored("name", customSetter: Person.setName(_:_:)) var name: String = "" - @Field.Computed( + @Field.Virtual( "displayName", customGetter: Person.getDisplayName(_:), affectedByKeyPaths: Person.keyPathsAffectingDisplayName() ) var displayName: String? - @Field.Computed( + @Field.Virtual( "customType", customGetter: Person.getCustomField(_:) ) diff --git a/Sources/DynamicObject.swift b/Sources/DynamicObject.swift index 32ed92b..5905216 100644 --- a/Sources/DynamicObject.swift +++ b/Sources/DynamicObject.swift @@ -114,7 +114,8 @@ extension NSManagedObject: DynamicObject { public class func cs_fromRaw(object: NSManagedObject) -> Self { - return unsafeDowncast(object, to: self) + // unsafeDowncast fails debug assertion starting Swift 5.2 + return _unsafeUncheckedDowncast(object, to: self) } public static func cs_matches(object: NSManagedObject) -> Bool { diff --git a/Sources/DynamicSchema+Convenience.swift b/Sources/DynamicSchema+Convenience.swift index 4f84648..5254d5f 100644 --- a/Sources/DynamicSchema+Convenience.swift +++ b/Sources/DynamicSchema+Convenience.swift @@ -70,7 +70,7 @@ extension DynamicSchema { let containerType: String if attribute.isTransient || attribute.attributeType == .undefinedAttributeType { - containerType = "Field.Computed" + containerType = "Field.Virtual" } else if attribute.attributeType == .transformableAttributeType { diff --git a/Sources/Field.Coded.swift b/Sources/Field.Coded.swift index 94e30fd..f014a11 100644 --- a/Sources/Field.Coded.swift +++ b/Sources/Field.Coded.swift @@ -40,7 +40,7 @@ extension FieldContainer { @Field.Stored("species") var species = "" - @Field.Computed("pluralName", customGetter: Animal.pluralName(_:)) + @Field.Virtual("pluralName", customGetter: Animal.pluralName(_:)) var pluralName: String = "" @Field.PlistCoded("color") @@ -62,7 +62,7 @@ extension FieldContainer { @Field.Stored("name") var name: String = "" - @Field.Computed("displayName", customGetter: Person.getName(_:)) + @Field.Virtual("displayName", customGetter: Person.getName(_:)) var displayName: String = "" private static func getName(_ partialObject: PartialObject) -> String { @@ -366,7 +366,7 @@ extension FieldContainer.Coded where V: FieldOptionalType { @Field.Stored("name") var name: String = "" - @Field.Computed("displayName", customGetter: Person.getName(_:)) + @Field.Virtual("displayName", customGetter: Person.getName(_:)) var displayName: String = "" private static func getName(_ partialObject: PartialObject) -> String { @@ -454,7 +454,7 @@ extension FieldContainer.Coded where V: DefaultNSSecureCodable { @Field.Stored("name") var name: String = "" - @Field.Computed("displayName", customGetter: Person.getName(_:)) + @Field.Virtual("displayName", customGetter: Person.getName(_:)) var displayName: String = "" private static func getName(_ partialObject: PartialObject) -> String { diff --git a/Sources/Field.Stored.swift b/Sources/Field.Stored.swift index 16babcd..ce7a914 100644 --- a/Sources/Field.Stored.swift +++ b/Sources/Field.Stored.swift @@ -40,7 +40,7 @@ extension FieldContainer { @Field.Stored("species") var species = "" - @Field.Computed("pluralName", customGetter: Animal.pluralName(_:)) + @Field.Virtual("pluralName", customGetter: Animal.pluralName(_:)) var pluralName: String = "" @Field.PlistCoded("color") @@ -62,7 +62,7 @@ extension FieldContainer { @Field.Stored("name") var name: String = "" - @Field.Computed("displayName", customGetter: Person.getName(_:)) + @Field.Virtual("displayName", customGetter: Person.getName(_:)) var displayName: String = "" private static func getName(_ partialObject: PartialObject) -> String { @@ -320,7 +320,7 @@ extension FieldContainer.Stored where V: FieldOptionalType { @Field.Stored("name") var name: String = "" - @Field.Computed("displayName", customGetter: Person.getName(_:)) + @Field.Virtual("displayName", customGetter: Person.getName(_:)) var displayName: String = "" private static func getName(_ partialObject: PartialObject) -> String { diff --git a/Sources/Field.Computed.swift b/Sources/Field.Virtual.swift similarity index 92% rename from Sources/Field.Computed.swift rename to Sources/Field.Virtual.swift index 8693032..c4fe361 100644 --- a/Sources/Field.Computed.swift +++ b/Sources/Field.Virtual.swift @@ -1,5 +1,5 @@ // -// Field.Computed.swift +// Field.Virtual.swift // CoreStore // // Copyright © 2020 John Rommel Estropia @@ -31,7 +31,7 @@ import Foundation extension FieldContainer { - // MARK: - Computed + // MARK: - Virtual /** The containing type for computed property values. Any type that conforms to `FieldStorableType` are supported. @@ -40,17 +40,17 @@ extension FieldContainer { @Field.Stored("species") var species = "" - @Field.Computed("pluralName", customGetter: Animal.pluralName(_:)) + @Field.Virtual("pluralName", customGetter: Animal.pluralName(_:)) var pluralName: String = "" @Field.PlistCoded("color") var color: UIColor? } ``` - - Important: `Field` properties are required to be used as `@propertyWrapper`s. Any other declaration not using the `@Field.Computed(...) var` syntax will be ignored. + - Important: `Field` properties are required to be used as `@propertyWrapper`s. Any other declaration not using the `@Field.Virtual(...) var` syntax will be ignored. */ @propertyWrapper - public struct Computed: AttributeKeyPathStringConvertible, FieldAttributeProtocol { + public struct Virtual: AttributeKeyPathStringConvertible, FieldAttributeProtocol { /** Initializes the metadata for the property. @@ -62,7 +62,7 @@ extension FieldContainer { @Field.Stored("name") var name: String = "" - @Field.Computed("displayName", customGetter: Person.getName(_:)) + @Field.Virtual("displayName", customGetter: Person.getName(_:)) var displayName: String = "" private static func getName(_ partialObject: PartialObject) -> String { @@ -85,7 +85,7 @@ extension FieldContainer { */ public init( _ keyPath: KeyPathString, - customGetter: ((_ partialObject: PartialObject) -> V)? = nil, + customGetter: @escaping (_ partialObject: PartialObject) -> V, customSetter: ((_ partialObject: PartialObject, _ newValue: V) -> Void)? = nil, affectedByKeyPaths: @autoclosure @escaping () -> Set = []) { @@ -299,3 +299,22 @@ extension FieldContainer { private let customSetter: ((_ partialObject: PartialObject, _ newValue: V) -> Void)? } } + + +extension FieldContainer.Virtual where V: FieldOptionalType { + + public init( + _ keyPath: KeyPathString, + customGetter: ((_ partialObject: PartialObject) -> V)? = nil, + customSetter: ((_ partialObject: PartialObject, _ newValue: V) -> Void)? = nil, + affectedByKeyPaths: @autoclosure @escaping () -> Set = []) { + + self.init( + keyPath: keyPath, + isOptional: false, + customGetter: customGetter, + customSetter: customSetter, + affectedByKeyPaths: affectedByKeyPaths + ) + } +} diff --git a/Sources/ObjectPublisher.swift b/Sources/ObjectPublisher.swift index 5426925..270ef01 100644 --- a/Sources/ObjectPublisher.swift +++ b/Sources/ObjectPublisher.swift @@ -385,7 +385,7 @@ extension ObjectPublisher where O: CoreStoreObject { /** Returns the value for the property identified by a given key. */ - public subscript(dynamicMember member: KeyPath.Computed>) -> V? { + public subscript(dynamicMember member: KeyPath.Virtual>) -> V? { guard let object = self.object, @@ -394,7 +394,7 @@ extension ObjectPublisher where O: CoreStoreObject { return nil } - return FieldContainer.Computed.read(field: object[keyPath: member], for: rawObject) as! V? + return FieldContainer.Virtual.read(field: object[keyPath: member], for: rawObject) as! V? } /** diff --git a/Sources/ObjectSnapshot.swift b/Sources/ObjectSnapshot.swift index 0845636..a8698f7 100644 --- a/Sources/ObjectSnapshot.swift +++ b/Sources/ObjectSnapshot.swift @@ -195,7 +195,7 @@ extension ObjectSnapshot where O: CoreStoreObject { /** Returns the value for the property identified by a given key. */ - public subscript(dynamicMember member: KeyPath.Computed>) -> V { + public subscript(dynamicMember member: KeyPath.Virtual>) -> V { get { diff --git a/Sources/PartialObject.swift b/Sources/PartialObject.swift index 035b817..e9ad364 100644 --- a/Sources/PartialObject.swift +++ b/Sources/PartialObject.swift @@ -58,7 +58,7 @@ public struct PartialObject { /** Returns the value for the property identified by a given key. */ - public func value(for property: (O) -> FieldContainer.Computed) -> V { + public func value(for property: (O) -> FieldContainer.Virtual) -> V { switch self.rawObject.value(forKey: property(O.meta).keyPath) { @@ -89,7 +89,7 @@ public struct PartialObject { This method does not invoke the access notification methods (`willAccessValue(forKey:)` and `didAccessValue(forKey:)`). This method is used primarily by subclasses that implement custom accessor methods that need direct access to the receiver’s private storage. */ - public func primitiveValue(for property: (O) -> FieldContainer.Computed) -> V? { + public func primitiveValue(for property: (O) -> FieldContainer.Virtual) -> V? { switch self.rawObject.primitiveValue(forKey: property(O.meta).keyPath) { @@ -145,7 +145,7 @@ public struct PartialObject { Sets in the receiver’s private internal storage the value of the property specified by key to value. */ - public func setPrimitiveValue(_ value: V, for property: (O) -> FieldContainer.Computed) { + public func setPrimitiveValue(_ value: V, for property: (O) -> FieldContainer.Virtual) { self.rawObject.setPrimitiveValue( value,