From 73450d0b2995efb6c75db0b48ff855fc1eac2bed Mon Sep 17 00:00:00 2001 From: John Estropia Date: Fri, 20 Jan 2017 21:51:00 +0900 Subject: [PATCH] WIP: minor conveniences to the ImportableUniqueObject protocol --- CoreStore.podspec | 2 +- CoreStore.xcodeproj/project.pbxproj | 10 + CoreStoreTests/ImportTests.swift | 39 +++ Sources/Importing/CoreDataNativeType.swift | 316 ++++++++++++++++++ Sources/Importing/ImportableObject.swift | 2 +- .../Importing/ImportableUniqueObject.swift | 28 +- Sources/Info.plist | 2 +- 7 files changed, 394 insertions(+), 5 deletions(-) create mode 100644 Sources/Importing/CoreDataNativeType.swift diff --git a/CoreStore.podspec b/CoreStore.podspec index a83f5e6..d10a730 100644 --- a/CoreStore.podspec +++ b/CoreStore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "CoreStore" - s.version = "3.0.0" + s.version = "3.0.1" s.license = "MIT" s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift" s.homepage = "https://github.com/JohnEstropia/CoreStore" diff --git a/CoreStore.xcodeproj/project.pbxproj b/CoreStore.xcodeproj/project.pbxproj index 4565140..8239992 100644 --- a/CoreStore.xcodeproj/project.pbxproj +++ b/CoreStore.xcodeproj/project.pbxproj @@ -80,6 +80,10 @@ B50392FA1C47963F009900CA /* NSManagedObject+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B50392F81C478FF3009900CA /* NSManagedObject+Transaction.swift */; }; B50392FB1C479640009900CA /* NSManagedObject+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B50392F81C478FF3009900CA /* NSManagedObject+Transaction.swift */; }; B504D0D61B02362500B2BBB1 /* CoreStore+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B504D0D51B02362500B2BBB1 /* CoreStore+Setup.swift */; }; + B50956B81E30B810003DF913 /* CoreDataNativeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B50956B71E30B810003DF913 /* CoreDataNativeType.swift */; }; + B50956B91E30B810003DF913 /* CoreDataNativeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B50956B71E30B810003DF913 /* CoreDataNativeType.swift */; }; + B50956BA1E30B810003DF913 /* CoreDataNativeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B50956B71E30B810003DF913 /* CoreDataNativeType.swift */; }; + B50956BB1E30B810003DF913 /* CoreDataNativeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B50956B71E30B810003DF913 /* CoreDataNativeType.swift */; }; B51BE06A1B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */; }; B51FE5AB1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */; }; B51FE5AD1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */; }; @@ -596,6 +600,7 @@ B501FDE61CA8D20500BE22EF /* CSListObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSListObserver.swift; sourceTree = ""; }; B50392F81C478FF3009900CA /* NSManagedObject+Transaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Transaction.swift"; sourceTree = ""; }; B504D0D51B02362500B2BBB1 /* CoreStore+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CoreStore+Setup.swift"; sourceTree = ""; }; + B50956B71E30B810003DF913 /* CoreDataNativeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataNativeType.swift; sourceTree = ""; }; B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectModel+Setup.swift"; sourceTree = ""; }; B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CoreStore+CustomDebugStringConvertible.swift"; sourceTree = ""; }; B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSFetchedResultsController+Convenience.swift"; sourceTree = ""; }; @@ -1093,6 +1098,7 @@ B5F1DA8C1B9AA97D007C5CBB /* ImportableObject.swift */, B5F1DA8F1B9AA991007C5CBB /* ImportableUniqueObject.swift */, B5E834B81B76311F001D3D50 /* BaseDataTransaction+Importing.swift */, + B50956B71E30B810003DF913 /* CoreDataNativeType.swift */, ); path = Importing; sourceTree = ""; @@ -1593,6 +1599,7 @@ B5F1DA8D1B9AA97D007C5CBB /* ImportableObject.swift in Sources */, B56965241B356B820075EE4A /* MigrationResult.swift in Sources */, B5FE4DAC1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */, + B50956B81E30B810003DF913 /* CoreDataNativeType.swift in Sources */, B501FDE71CA8D20500BE22EF /* CSListObserver.swift in Sources */, B501FDE21CA8D1F500BE22EF /* CSListMonitor.swift in Sources */, 2F291E2719C6D3CF007AF63F /* CoreStore.swift in Sources */, @@ -1745,6 +1752,7 @@ 82BA18B01C4BBD3100A0916E /* NSManagedObject+Transaction.swift in Sources */, 82BA18D41C4BBD7100A0916E /* NSManagedObjectContext+Querying.swift in Sources */, 82BA18D51C4BBD7100A0916E /* NSManagedObjectContext+Setup.swift in Sources */, + B50956B91E30B810003DF913 /* CoreDataNativeType.swift in Sources */, B501FDE91CA8D20500BE22EF /* CSListObserver.swift in Sources */, B501FDE41CA8D1F500BE22EF /* CSListMonitor.swift in Sources */, B5FE4DA31C8481E100FA6A91 /* StorageInterface.swift in Sources */, @@ -1897,6 +1905,7 @@ B5220E231D130826009BC71E /* NSFetchedResultsController+ObjectiveC.swift in Sources */, B52DD19D1BE1F92C00949AFE /* BaseDataTransaction.swift in Sources */, B5220E131D1305ED009BC71E /* SectionBy.swift in Sources */, + B50956BB1E30B810003DF913 /* CoreDataNativeType.swift in Sources */, B559CD4D1CAA8C6D00E4D58B /* CSStorageInterface.swift in Sources */, B5ECDBE91CA6BEA300C7F112 /* CSClauseTypes.swift in Sources */, B52DD1B81BE1F94000949AFE /* DataStack+Migration.swift in Sources */, @@ -2049,6 +2058,7 @@ B5FE4DA41C8481E100FA6A91 /* StorageInterface.swift in Sources */, B56321B31BD6521C006C9394 /* NSManagedObjectContext+Setup.swift in Sources */, B501FDEA1CA8D20500BE22EF /* CSListObserver.swift in Sources */, + B50956BA1E30B810003DF913 /* CoreDataNativeType.swift in Sources */, B501FDE51CA8D1F500BE22EF /* CSListMonitor.swift in Sources */, B5ECDC141CA816E500C7F112 /* CSTweak.swift in Sources */, B56321AE1BD6521C006C9394 /* NotificationObserver.swift in Sources */, diff --git a/CoreStoreTests/ImportTests.swift b/CoreStoreTests/ImportTests.swift index f48c1bf..30ad492 100644 --- a/CoreStoreTests/ImportTests.swift +++ b/CoreStoreTests/ImportTests.swift @@ -33,6 +33,45 @@ import CoreStore class ImportTests: BaseTestDataTestCase { + @objc + dynamic func test_ThatAttributeProtocols_BehaveCorrectly() { + + XCTAssertEqual(NSNumber.cs_fromNativeType(NSNumber(value: true))?.boolValue, true) + XCTAssertEqual(NSNumber.cs_fromNativeType(NSNumber(value: Int16.max))?.int16Value, Int16.max) + XCTAssertEqual(NSNumber.cs_fromNativeType(NSNumber(value: Int32.max))?.int32Value, Int32.max) + XCTAssertEqual(NSNumber.cs_fromNativeType(NSNumber(value: Int64.max))?.int64Value, Int64.max) + XCTAssertEqual(NSNumber.cs_fromNativeType(NSNumber(value: MAXFLOAT))?.floatValue, MAXFLOAT) + XCTAssertEqual(NSNumber.cs_fromNativeType(NSNumber(value: Double(MAXFLOAT)))?.doubleValue, Double(MAXFLOAT)) + + XCTAssertEqual(NSDecimalNumber.cs_fromNativeType(NSDecimalNumber(string: "1"))?.boolValue, true) + XCTAssertEqual(NSDecimalNumber.cs_fromNativeType(NSDecimalNumber(string: Int16.max.description))?.int16Value, Int16.max) + XCTAssertEqual(NSDecimalNumber.cs_fromNativeType(NSDecimalNumber(string: Int32.max.description))?.int32Value, Int32.max) + XCTAssertEqual(NSDecimalNumber.cs_fromNativeType(NSDecimalNumber(string: Int64.max.description))?.int64Value, Int64.max) + XCTAssertEqual(NSDecimalNumber.cs_fromNativeType(NSDecimalNumber(string: MAXFLOAT.description))?.doubleValue, NSDecimalNumber(string: MAXFLOAT.description).doubleValue) + XCTAssertEqual(NSDecimalNumber.cs_fromNativeType(NSDecimalNumber(string: MAXFLOAT.description))?.floatValue, NSDecimalNumber(string: MAXFLOAT.description).floatValue) + + XCTAssertEqual(NSNumber.cs_fromNativeType(NSDecimalNumber(string: "1"))?.boolValue, true) + XCTAssertEqual(NSNumber.cs_fromNativeType(NSDecimalNumber(string: Int16.max.description))?.int16Value, Int16.max) + XCTAssertEqual(NSNumber.cs_fromNativeType(NSDecimalNumber(string: Int32.max.description))?.int32Value, Int32.max) + XCTAssertEqual(NSNumber.cs_fromNativeType(NSDecimalNumber(string: Int64.max.description))?.int64Value, Int64.max) + XCTAssertEqual(NSNumber.cs_fromNativeType(NSDecimalNumber(string: MAXFLOAT.description))?.doubleValue, NSDecimalNumber(string: MAXFLOAT.description).doubleValue) + XCTAssertEqual(NSNumber.cs_fromNativeType(NSDecimalNumber(string: MAXFLOAT.description))?.floatValue, NSDecimalNumber(string: MAXFLOAT.description).floatValue) + + XCTAssertNil(NSDecimalNumber.cs_fromNativeType(NSNumber(value: true))) + XCTAssertNil(NSDecimalNumber.cs_fromNativeType(NSNumber(value: Int16.max))) + XCTAssertNil(NSDecimalNumber.cs_fromNativeType(NSNumber(value: Int32.max))) + XCTAssertNil(NSDecimalNumber.cs_fromNativeType(NSNumber(value: Int64.max))) + XCTAssertNil(NSDecimalNumber.cs_fromNativeType(NSNumber(value: MAXFLOAT))) + XCTAssertNil(NSDecimalNumber.cs_fromNativeType(NSNumber(value: Double(MAXFLOAT)))) + + XCTAssertEqual(true.cs_toNativeType(), NSNumber(value: true)) + XCTAssertEqual(Int16.max.cs_toNativeType(), NSNumber(value: Int16.max)) + XCTAssertEqual(Int32.max.cs_toNativeType(), NSNumber(value: Int32.max)) + XCTAssertEqual(Int64.max.cs_toNativeType(), NSNumber(value: Int64.max)) + XCTAssertEqual(MAXFLOAT.cs_toNativeType(), NSNumber(value: MAXFLOAT)) + XCTAssertEqual(Double(MAXFLOAT).cs_toNativeType(), NSNumber(value: Double(MAXFLOAT))) + } + @objc dynamic func test_ThatImportObject_CanSkipImport() { diff --git a/Sources/Importing/CoreDataNativeType.swift b/Sources/Importing/CoreDataNativeType.swift new file mode 100644 index 0000000..5216d5e --- /dev/null +++ b/Sources/Importing/CoreDataNativeType.swift @@ -0,0 +1,316 @@ +// +// CoreDataNativeType.swift +// CoreStore +// +// Copyright © 2017 John Rommel Estropia +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import Foundation +import CoreData + + +// MARK: - CoreDataNativeType + +public protocol CoreDataNativeType: class, NSObjectProtocol, AnyObject {} + +extension NSNumber: CoreDataNativeType {} +extension NSString: CoreDataNativeType {} +extension NSDate: CoreDataNativeType {} +extension NSData: CoreDataNativeType {} +extension NSSet: CoreDataNativeType {} +extension NSOrderedSet: CoreDataNativeType {} + + +public protocol CoreStoreSupportedAttributeType { + + associatedtype CoreStoreNativeType: CoreDataNativeType + + static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? + func cs_toNativeType() -> CoreStoreNativeType +} + +extension NSNumber: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSNumber + + public class func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? { + + func forceCast(_ value: Any) -> T? { + + return value as? T + } + return forceCast(value) + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self + } +} + +extension NSString: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSString + + public class func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? { + + func forceCast(_ value: Any) -> T? { + + return value as? T + } + return forceCast(value) + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self + } +} + +extension NSDate: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSDate + + public class func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? { + + func forceCast(_ value: Any) -> T? { + + return value as? T + } + return forceCast(value) + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self + } +} + +extension NSData: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSData + + public class func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? { + + func forceCast(_ value: Any) -> T? { + + return value as? T + } + return forceCast(value) + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self + } +} + +extension NSSet: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSSet + + public class func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? { + + func forceCast(_ value: Any) -> T? { + + return value as? T + } + return forceCast(value) + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self + } +} + +extension NSOrderedSet: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSOrderedSet + + public class func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? { + + func forceCast(_ value: Any) -> T? { + + return value as? T + } + return forceCast(value) + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self + } +} + + + +extension Bool: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSNumber + + public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Bool? { + + return value as Bool + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self as NSNumber + } +} + +extension Int16: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSNumber + + public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Int16? { + + return value as Int16 + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self as NSNumber + } +} + +extension Int32: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSNumber + + public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Int32? { + + return value as Int32 + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self as NSNumber + } +} + +extension Int64: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSNumber + + public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Int64? { + + return value as Int64 + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self as NSNumber + } +} + +extension Double: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSNumber + + public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Double? { + + return value as Double + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self as NSNumber + } +} + +extension Float: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSNumber + + public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Float? { + + return value as Float + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self as NSNumber + } +} + +extension Date: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSDate + + public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Date? { + + return value as Date + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self as NSDate + } +} + +extension String: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSString + + public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> String? { + + return value as String + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self as NSString + } +} + +extension Data: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSData + + public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Data? { + + return value as Data + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self as NSData + } +} + +extension Set: CoreStoreSupportedAttributeType { + + public typealias CoreStoreNativeType = NSSet + + public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Set? { + + return value as? Set + } + + public func cs_toNativeType() -> CoreStoreNativeType { + + return self as NSSet + } +} + + diff --git a/Sources/Importing/ImportableObject.swift b/Sources/Importing/ImportableObject.swift index 2dcd018..f9eafcb 100644 --- a/Sources/Importing/ImportableObject.swift +++ b/Sources/Importing/ImportableObject.swift @@ -48,7 +48,7 @@ import CoreData } ``` */ -public protocol ImportableObject: class { +public protocol ImportableObject: class, NSObjectProtocol, AnyObject { /** The data type for the import source. This is most commonly an `NSDictionary` or another external source such as an `NSUserDefaults`. diff --git a/Sources/Importing/ImportableUniqueObject.swift b/Sources/Importing/ImportableUniqueObject.swift index 7c54cb4..fb56502 100644 --- a/Sources/Importing/ImportableUniqueObject.swift +++ b/Sources/Importing/ImportableUniqueObject.swift @@ -59,7 +59,7 @@ public protocol ImportableUniqueObject: ImportableObject { /** The data type for the entity's unique ID attribute */ - associatedtype UniqueIDType: NSObject + associatedtype UniqueIDType: CoreStoreSupportedAttributeType /** The keyPath to the entity's unique ID attribute @@ -67,7 +67,8 @@ public protocol ImportableUniqueObject: ImportableObject { static var uniqueIDKeyPath: String { get } /** - The object's unique ID value + The object's unique ID value. The default implementation returns the value of the attribute pertained to by `uniqueIDKeyPath` + - Important: It is the developer's responsibility to ensure that the attribute value pertained by `uniqueIDKeyPath` is not `nil` during the call to `uniqueIDValue`. */ var uniqueIDValue: UniqueIDType { get set } @@ -181,3 +182,26 @@ public extension ImportableUniqueObject { try self.update(from: source, in: transaction) } } + + +// MARK: - ImportableUniqueObject (Default Implementations) + +public extension ImportableUniqueObject where Self: NSManagedObject { + + var uniqueIDValue: UniqueIDType { + + get { + + return UniqueIDType.cs_fromNativeType( + self.value(forKey: type(of: self).uniqueIDKeyPath) as! UniqueIDType.CoreStoreNativeType + )! + } + set { + + self.setValue( + newValue.cs_toNativeType(), + forKey: type(of: self).uniqueIDKeyPath + ) + } + } +} diff --git a/Sources/Info.plist b/Sources/Info.plist index e0f4bf7..dc2b99a 100644 --- a/Sources/Info.plist +++ b/Sources/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 3.0.0 + 3.0.1 CFBundleSignature ???? CFBundleVersion