From 7508d150d6cd42bc5160a82f47c43c164c023a9e Mon Sep 17 00:00:00 2001 From: cool8jay Date: Wed, 5 Jun 2019 08:43:06 +0800 Subject: [PATCH 1/7] Update code style. Update code style. --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8edd35c..327dff0 100644 --- a/README.md +++ b/README.md @@ -766,13 +766,13 @@ While the syntax is straightforward, CoreStore does not just naively insert a ne - If the entity belongs to multiple stores, an assertion failure will be raised. **This is also a programmer error and should never occur in production code.** Normally, with Core Data you can insert an object in this state but saving the `NSManagedObjectContext` will always fail. CoreStore checks this for you at creation time when it makes sense (not during save). If the entity exists in multiple configurations, you need to provide the configuration name for the destination persistent store: - - let person = transaction.create(Into("Config1")) - +```swift +let person = transaction.create(Into("Config1")) +``` or if the persistent store is the auto-generated "Default" configuration, specify `nil`: - - let person = transaction.create(Into(nil)) - +```swift +let person = transaction.create(Into(nil)) +``` Note that if you do explicitly specify the configuration name, CoreStore will only try to insert the created object to that particular store and will fail if that store is not found; it will not fall back to any other configuration that the entity belongs to. ### Updating objects From 9f397b433735d3fbba83e01601d00a8b96be19a9 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Mon, 10 Jun 2019 18:34:15 +0900 Subject: [PATCH 2/7] Prevent crashing when DataStack is deallocated ahead of ListMonitor and child objects --- Sources/From.swift | 12 ++++++++++-- Sources/ListMonitor.swift | 11 +++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Sources/From.swift b/Sources/From.swift index e75a1bb..5a9b778 100644 --- a/Sources/From.swift +++ b/Sources/From.swift @@ -140,8 +140,16 @@ public struct From { } internal func applyToFetchRequest(_ fetchRequest: CoreStoreFetchRequest, context: NSManagedObjectContext, applyAffectedStores: Bool = true) throws { - - fetchRequest.entity = context.parentStack!.entityDescription(for: EntityIdentifier(self.entityClass))! + + guard let parentStack = context.parentStack else { + + CoreStore.log( + .warning, + message: "Attempted to perform a fetch but the \(cs_typeName(DataStack.self)) has already been deallocated." + ) + throw CoreStoreError.unknown + } + fetchRequest.entity = parentStack.entityDescription(for: EntityIdentifier(self.entityClass))! guard applyAffectedStores else { return diff --git a/Sources/ListMonitor.swift b/Sources/ListMonitor.swift index 9d8ab88..30f134b 100644 --- a/Sources/ListMonitor.swift +++ b/Sources/ListMonitor.swift @@ -963,8 +963,15 @@ public final class ListMonitor: Hashable { return } - - try! newFetchedResultsController.performFetchFromSpecifiedStores() + do { + + try newFetchedResultsController.performFetchFromSpecifiedStores() + } + catch { + + // DataStack may have been deallocated + return + } self.fetchedResultsControllerDelegate.taskGroup.notify(queue: .main) { self.fetchedResultsControllerDelegate.enabled = false From 67bb9340c77c9b13624b44d3a6f559229e4f5b72 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Fri, 5 Jul 2019 19:07:25 +0900 Subject: [PATCH 3/7] provide way to check if an object has updated properties --- Sources/BaseDataTransaction.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Sources/BaseDataTransaction.swift b/Sources/BaseDataTransaction.swift index b61bd50..64c1790 100644 --- a/Sources/BaseDataTransaction.swift +++ b/Sources/BaseDataTransaction.swift @@ -213,6 +213,25 @@ public /*abstract*/ class BaseDataTransaction { // MARK: Inspecting Pending Objects + + /** + Returns `true` if the object has any property values changed. This method should not be called after the `commit()` method was called. + + - parameter entity: the `DynamicObject` instance + - returns: `true` if the object has any property values changed. + */ + public func objectHasPersistentChangedValues(_ entity: D) -> Bool { + + CoreStore.assert( + self.isRunningInAllowedQueue(), + "Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue." + ) + CoreStore.assert( + !self.isCommitted, + "Attempted to access inserted objects from an already committed \(cs_typeName(self))." + ) + return entity.cs_toRaw().hasPersistentChangedValues + } /** Returns all pending `DynamicObject`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called. From ed3d21db775038bcc17621af1c573104c9ca1179 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 9 Jul 2019 14:50:23 +0900 Subject: [PATCH 4/7] WIP: reorganization of keypath utilities (in prep for @propertyWrappers) --- CoreStore.xcodeproj/project.pbxproj | 38 +++-- Sources/CoreStoreObject+Querying.swift | 1 - Sources/CoreStoreObject.swift | 22 ++- Sources/DynamicKeyPath.swift | 210 ------------------------- Sources/Entity.swift | 4 +- Sources/KeyPath+KeyPaths.swift | 46 ++++++ Sources/KeyPathGenericBindings.swift | 80 +++++++--- Sources/KeyPathStringConvertible.swift | 103 ++++++++++++ Sources/OrderBy.swift | 4 +- Sources/Relationship.swift | 81 ++++++++-- Sources/String+KeyPaths.swift | 66 ++++++++ Sources/Transformable.swift | 50 +++++- Sources/Value.swift | 54 ++++++- Sources/Where.Expression.swift | 78 ++++----- 14 files changed, 523 insertions(+), 314 deletions(-) delete mode 100644 Sources/DynamicKeyPath.swift create mode 100644 Sources/KeyPath+KeyPaths.swift create mode 100644 Sources/KeyPathStringConvertible.swift create mode 100644 Sources/String+KeyPaths.swift diff --git a/CoreStore.xcodeproj/project.pbxproj b/CoreStore.xcodeproj/project.pbxproj index be1d808..c28d06d 100644 --- a/CoreStore.xcodeproj/project.pbxproj +++ b/CoreStore.xcodeproj/project.pbxproj @@ -94,6 +94,8 @@ B51260941E9B28F100402229 /* EntityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51260921E9B28F100402229 /* EntityIdentifier.swift */; }; B51260951E9B28F100402229 /* EntityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51260921E9B28F100402229 /* EntityIdentifier.swift */; }; B51260961E9B28F100402229 /* EntityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51260921E9B28F100402229 /* EntityIdentifier.swift */; }; + B51B5C2B22D43931009FA3BA /* String+KeyPaths.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51B5C2A22D43931009FA3BA /* String+KeyPaths.swift */; }; + B51B5C2D22D43E38009FA3BA /* KeyPath+KeyPaths.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51B5C2C22D43E38009FA3BA /* KeyPath+KeyPaths.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 */; }; B51FE5AE1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */; }; @@ -526,10 +528,10 @@ B5CA2B091F7E5ACA004B1936 /* WhereClauseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B071F7E5ACA004B1936 /* WhereClauseType.swift */; }; B5CA2B0A1F7E5ACA004B1936 /* WhereClauseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B071F7E5ACA004B1936 /* WhereClauseType.swift */; }; B5CA2B0B1F7E5ACA004B1936 /* WhereClauseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B071F7E5ACA004B1936 /* WhereClauseType.swift */; }; - B5CA2B121F81DBFE004B1936 /* DynamicKeyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B111F81DBFE004B1936 /* DynamicKeyPath.swift */; }; - B5CA2B131F81DBFE004B1936 /* DynamicKeyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B111F81DBFE004B1936 /* DynamicKeyPath.swift */; }; - B5CA2B141F81DBFE004B1936 /* DynamicKeyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B111F81DBFE004B1936 /* DynamicKeyPath.swift */; }; - B5CA2B151F81DBFF004B1936 /* DynamicKeyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B111F81DBFE004B1936 /* DynamicKeyPath.swift */; }; + B5CA2B121F81DBFE004B1936 /* KeyPathStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B111F81DBFE004B1936 /* KeyPathStringConvertible.swift */; }; + B5CA2B131F81DBFE004B1936 /* KeyPathStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B111F81DBFE004B1936 /* KeyPathStringConvertible.swift */; }; + B5CA2B141F81DBFE004B1936 /* KeyPathStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B111F81DBFE004B1936 /* KeyPathStringConvertible.swift */; }; + B5CA2B151F81DBFF004B1936 /* KeyPathStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B111F81DBFE004B1936 /* KeyPathStringConvertible.swift */; }; B5D1E22C19FA9FBC003B2874 /* CoreStoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D1E22B19FA9FBC003B2874 /* CoreStoreError.swift */; }; B5D339B41E925C2B00C880DE /* DynamicModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */; }; B5D339B51E925C2B00C880DE /* DynamicModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */; }; @@ -770,6 +772,8 @@ B512607E1E97A18000402229 /* CoreStoreObject+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CoreStoreObject+Convenience.swift"; sourceTree = ""; }; B51260881E9B252B00402229 /* NSEntityDescription+DynamicModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSEntityDescription+DynamicModel.swift"; sourceTree = ""; }; B51260921E9B28F100402229 /* EntityIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntityIdentifier.swift; sourceTree = ""; }; + B51B5C2A22D43931009FA3BA /* String+KeyPaths.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+KeyPaths.swift"; sourceTree = ""; }; + B51B5C2C22D43E38009FA3BA /* KeyPath+KeyPaths.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyPath+KeyPaths.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 = ""; }; B5215CA31FA47DFD00139E3A /* FetchChainBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchChainBuilder.swift; sourceTree = ""; }; @@ -877,7 +881,7 @@ B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UnsafeDataTransaction+Observing.swift"; sourceTree = ""; }; B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreFetchedResultsController.swift; sourceTree = ""; }; B5CA2B071F7E5ACA004B1936 /* WhereClauseType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhereClauseType.swift; sourceTree = ""; }; - B5CA2B111F81DBFE004B1936 /* DynamicKeyPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicKeyPath.swift; sourceTree = ""; }; + B5CA2B111F81DBFE004B1936 /* KeyPathStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPathStringConvertible.swift; sourceTree = ""; }; B5D1E22B19FA9FBC003B2874 /* CoreStoreError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreError.swift; sourceTree = ""; }; B5D2D5A91F7558CB00A4DE67 /* .cocoapods.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .cocoapods.yml; sourceTree = SOURCE_ROOT; }; B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicModelTests.swift; sourceTree = ""; }; @@ -1165,6 +1169,17 @@ name = Observing; sourceTree = ""; }; + B51B5C2922D43854009FA3BA /* KeyPaths */ = { + isa = PBXGroup; + children = ( + B5CA2B111F81DBFE004B1936 /* KeyPathStringConvertible.swift */, + B5DAFB492203E01D003FCCD0 /* KeyPathGenericBindings.swift */, + B51B5C2C22D43E38009FA3BA /* KeyPath+KeyPaths.swift */, + B51B5C2A22D43931009FA3BA /* String+KeyPaths.swift */, + ); + name = KeyPaths; + sourceTree = ""; + }; B5215CA21FA47BF300139E3A /* Chained Clauses */ = { isa = PBXGroup; children = ( @@ -1323,8 +1338,6 @@ children = ( B5A1DAC71F111BFA003CF369 /* KeyPath+Querying.swift */, B5D339EB1E9495E500C880DE /* CoreStoreObject+Querying.swift */, - B5CA2B111F81DBFE004B1936 /* DynamicKeyPath.swift */, - B5DAFB492203E01D003FCCD0 /* KeyPathGenericBindings.swift */, ); name = "KeyPath Utilities"; sourceTree = ""; @@ -1337,6 +1350,7 @@ B549F6721E56A92800FBAB2D /* CoreDataNativeType.swift */, B5D339F01E94AF5800C880DE /* CoreStoreStrings.swift */, B5E84EDA1AFF84500064E85B /* Setup */, + B51B5C2922D43854009FA3BA /* KeyPaths */, B5E84EE21AFF84610064E85B /* Logging */, B5E84EE91AFF846E0064E85B /* Transactions */, B5E834B61B7630BD001D3D50 /* Importing */, @@ -1902,6 +1916,7 @@ B5C976E31C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */, B53FBA121CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */, B5831B751F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */, + B51B5C2D22D43E38009FA3BA /* KeyPath+KeyPaths.swift in Sources */, B5E1B5A81CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */, B5D339F11E94AF5800C880DE /* CoreStoreStrings.swift in Sources */, B56007161B4018AB00A9A8F9 /* MigrationChain.swift in Sources */, @@ -1991,6 +2006,7 @@ B5E84F201AFF84860064E85B /* DataStack+Observing.swift in Sources */, B501FDDD1CA8D05000BE22EF /* CSSectionBy.swift in Sources */, B538BA771D15B3E30003A766 /* CoreStoreBridge.m in Sources */, + B51B5C2B22D43931009FA3BA /* String+KeyPaths.swift in Sources */, B512607F1E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */, B5E84EF81AFF846E0064E85B /* CoreStore+Transaction.swift in Sources */, B5E84F301AFF849C0064E85B /* NSManagedObjectContext+CoreStore.swift in Sources */, @@ -2000,7 +2016,7 @@ B549F65E1E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */, B5E84F211AFF84860064E85B /* CoreStore+Observing.swift in Sources */, B559CD431CAA8B6300E4D58B /* CSSetupResult.swift in Sources */, - B5CA2B121F81DBFE004B1936 /* DynamicKeyPath.swift in Sources */, + B5CA2B121F81DBFE004B1936 /* KeyPathStringConvertible.swift in Sources */, B5A991EC1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */, B5FE4DA71C84FB4400FA6A91 /* InMemoryStore.swift in Sources */, B52F743D1E9B8724005F3DAC /* DynamicSchema.swift in Sources */, @@ -2195,7 +2211,7 @@ B549F65F1E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */, B559CD451CAA8B6300E4D58B /* CSSetupResult.swift in Sources */, 82BA18B81C4BBD4200A0916E /* TypeErasedClauses.swift in Sources */, - B5CA2B131F81DBFE004B1936 /* DynamicKeyPath.swift in Sources */, + B5CA2B131F81DBFE004B1936 /* KeyPathStringConvertible.swift in Sources */, B5A991ED1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */, B5ECDBEE1CA6BF2000C7F112 /* CSFrom.swift in Sources */, B52F743E1E9B8724005F3DAC /* DynamicSchema.swift in Sources */, @@ -2390,7 +2406,7 @@ B549F6611E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */, B52DD19B1BE1F92800949AFE /* CoreStoreLogger.swift in Sources */, B52DD1991BE1F92800949AFE /* DefaultLogger.swift in Sources */, - B5CA2B151F81DBFF004B1936 /* DynamicKeyPath.swift in Sources */, + B5CA2B151F81DBFF004B1936 /* KeyPathStringConvertible.swift in Sources */, B5A991EF1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */, B5220E201D130813009BC71E /* CSObjectMonitor.swift in Sources */, B52F74401E9B8724005F3DAC /* DynamicSchema.swift in Sources */, @@ -2585,7 +2601,7 @@ B549F6601E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */, B559CD461CAA8B6300E4D58B /* CSSetupResult.swift in Sources */, B56321A61BD65216006C9394 /* MigrationType.swift in Sources */, - B5CA2B141F81DBFE004B1936 /* DynamicKeyPath.swift in Sources */, + B5CA2B141F81DBFE004B1936 /* KeyPathStringConvertible.swift in Sources */, B5A991EE1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */, B5ECDBEF1CA6BF2000C7F112 /* CSFrom.swift in Sources */, B52F743F1E9B8724005F3DAC /* DynamicSchema.swift in Sources */, diff --git a/Sources/CoreStoreObject+Querying.swift b/Sources/CoreStoreObject+Querying.swift index c5bb581..dc9d94d 100644 --- a/Sources/CoreStoreObject+Querying.swift +++ b/Sources/CoreStoreObject+Querying.swift @@ -26,7 +26,6 @@ import CoreData import Foundation - // MARK: - ValueContainer.Required extension ValueContainer.Required { diff --git a/Sources/CoreStoreObject.swift b/Sources/CoreStoreObject.swift index eb1dd79..228ee58 100644 --- a/Sources/CoreStoreObject.swift +++ b/Sources/CoreStoreObject.swift @@ -153,9 +153,27 @@ extension DynamicObject where Self: CoreStoreObject { ) return PartialObject(self.rawObject!) } + + + // MARK: Internal internal static var meta: Self { - - return self.init(asMeta: ()) + + let key = ObjectIdentifier(self) + if case let meta as Self = Static.metaCache[key] { + + return meta + } + let meta = self.init(asMeta: ()) + Static.metaCache[key] = meta + return meta } } + + +// MARK: - Static + +fileprivate enum Static { + + fileprivate static var metaCache: [ObjectIdentifier: Any] = [:] +} diff --git a/Sources/DynamicKeyPath.swift b/Sources/DynamicKeyPath.swift deleted file mode 100644 index ef7f365..0000000 --- a/Sources/DynamicKeyPath.swift +++ /dev/null @@ -1,210 +0,0 @@ -// -// DynamicKeyPath.swift -// CoreStore -// -// Copyright © 2018 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: - AnyDynamicKeyPath - -public protocol AnyDynamicKeyPath { - - /** - The keyPath string - */ - var cs_keyPathString: String { get } -} - - -// MARK: - DynamicKeyPath - -/** - Used only for utility methods. - */ -public protocol DynamicKeyPath: AnyDynamicKeyPath { - - /** - The DynamicObject type - */ - associatedtype ObjectType: DynamicObject - - /** - The Value type - */ - associatedtype ValueType -} - - -// MARK: - KeyPathString - -extension KeyPathString { - - /** - Extracts the keyPath string from the property. - ``` - let keyPath = String(keyPath: \Person.nickname) - ``` - */ - public init(keyPath: KeyPath) { - - self = keyPath.cs_keyPathString - } - - /** - Extracts the keyPath string from the property. - ``` - let keyPath = String(keyPath: \Person.nickname) - ``` - */ - public init(keyPath: KeyPath) { - - self = O.meta[keyPath: keyPath].cs_keyPathString - } - - /** - Extracts the keyPath string from the property. - ``` - let keyPath = String(keyPath: \Person.nickname) - ``` - */ - public init(keyPath: Where.Expression) { - - self = keyPath.cs_keyPathString - } -} - - - -// MARK: - KeyPath: DynamicKeyPath - -extension KeyPath: DynamicKeyPath, AnyDynamicKeyPath where Root: DynamicObject, Value: AllowedObjectiveCKeyPathValue { - - public typealias ObjectType = Root - public typealias ValueType = Value - - public var cs_keyPathString: String { - - return self._kvcKeyPathString! - } -} - - -// MARK: - ValueContainer.Required: DynamicKeyPath - -extension ValueContainer.Required: DynamicKeyPath { - - public typealias ObjectType = O - public typealias ValueType = V - - public var cs_keyPathString: String { - - return self.keyPath - } -} - - -// MARK: - ValueContainer.Optional: DynamicKeyPath - -extension ValueContainer.Optional: DynamicKeyPath { - - public typealias ObjectType = O - public typealias ValueType = V - - public var cs_keyPathString: String { - - return self.keyPath - } -} - - -// MARK: - TransformableContainer.Required: DynamicKeyPath - -extension TransformableContainer.Required: DynamicKeyPath { - - public typealias ObjectType = O - public typealias ValueType = V - - public var cs_keyPathString: String { - - return self.keyPath - } -} - - -// MARK: - TransformableContainer.Optional: DynamicKeyPath - -extension TransformableContainer.Optional: DynamicKeyPath { - - public typealias ObjectType = O - public typealias ValueType = V - - public var cs_keyPathString: String { - - return self.keyPath - } -} - - -// MARK: - RelationshipContainer.ToOne: DynamicKeyPath - -extension RelationshipContainer.ToOne: DynamicKeyPath { - - public typealias ObjectType = O - public typealias ValueType = D - - public var cs_keyPathString: String { - - return self.keyPath - } -} - - -// MARK: - RelationshipContainer.ToManyOrdered: DynamicKeyPath - -extension RelationshipContainer.ToManyOrdered: DynamicKeyPath { - - public typealias ObjectType = O - public typealias ValueType = D - - public var cs_keyPathString: String { - - return self.keyPath - } -} - - -// MARK: - RelationshipContainer.ToManyUnordered: DynamicKeyPath - -extension RelationshipContainer.ToManyUnordered: DynamicKeyPath { - - public typealias ObjectType = O - public typealias ValueType = D - - public var cs_keyPathString: String { - - return self.keyPath - } -} - diff --git a/Sources/Entity.swift b/Sources/Entity.swift index 69d1834..fb77f03 100644 --- a/Sources/Entity.swift +++ b/Sources/Entity.swift @@ -124,7 +124,7 @@ public final class Entity: DynamicEntity { return $0.map { - return (meta[keyPath: $0] as! AnyDynamicKeyPath).cs_keyPathString + return (meta[keyPath: $0] as! AnyKeyPathStringConvertible).cs_keyPathString } } super.init( @@ -156,7 +156,7 @@ public final class Entity: DynamicEntity { return $0.map { - return (meta[keyPath: $0] as! AnyDynamicKeyPath).cs_keyPathString + return (meta[keyPath: $0] as! AnyKeyPathStringConvertible).cs_keyPathString } } super.init( diff --git a/Sources/KeyPath+KeyPaths.swift b/Sources/KeyPath+KeyPaths.swift new file mode 100644 index 0000000..63e9435 --- /dev/null +++ b/Sources/KeyPath+KeyPaths.swift @@ -0,0 +1,46 @@ +// +// KeyPath+KeyPaths.swift +// CoreStore +// +// Copyright © 2019 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 CoreData +import Foundation + + +// MARK: - KeyPath: AnyKeyPathStringConvertible, KeyPathStringConvertible where Root: NSManagedObject, Value: AllowedObjectiveCKeyPathValue + +extension KeyPath: AnyKeyPathStringConvertible, KeyPathStringConvertible where Root: NSManagedObject, Value: AllowedObjectiveCKeyPathValue { + + // MARK: AnyKeyPathStringConvertible + + public var cs_keyPathString: String { + + return self._kvcKeyPathString! + } + + + // MARK: KeyPathStringConvertible + + public typealias ObjectType = Root + public typealias DestinationValueType = Value +} diff --git a/Sources/KeyPathGenericBindings.swift b/Sources/KeyPathGenericBindings.swift index 72cbb60..29ea924 100644 --- a/Sources/KeyPathGenericBindings.swift +++ b/Sources/KeyPathGenericBindings.swift @@ -92,49 +92,87 @@ extension UUID: AllowedOptionalObjectiveCKeyPathValue {} extension Optional: AllowedObjectiveCKeyPathValue where Wrapped: AllowedOptionalObjectiveCKeyPathValue {} -// MARK: - AllowedObjectiveCCollectionKeyPathValue +// MARK: - AllowedObjectiveCAttributeKeyPathValue /** Used only for utility methods. Types allowed as `Value` generic type to `KeyPath` utilities. */ -public protocol AllowedObjectiveCCollectionKeyPathValue: AllowedOptionalObjectiveCKeyPathValue {} +public protocol AllowedObjectiveCAttributeKeyPathValue: AllowedObjectiveCKeyPathValue {} -extension NSSet: AllowedObjectiveCCollectionKeyPathValue {} +extension Bool: AllowedObjectiveCAttributeKeyPathValue {} -extension NSOrderedSet: AllowedObjectiveCCollectionKeyPathValue {} +extension CGFloat: AllowedObjectiveCAttributeKeyPathValue {} -extension Optional: AllowedObjectiveCCollectionKeyPathValue, AllowedOptionalObjectiveCKeyPathValue where Wrapped: AllowedObjectiveCCollectionKeyPathValue {} +extension Data: AllowedObjectiveCAttributeKeyPathValue {} + +extension Date: AllowedObjectiveCAttributeKeyPathValue {} + +extension Double: AllowedObjectiveCAttributeKeyPathValue {} + +extension Float: AllowedObjectiveCAttributeKeyPathValue {} + +extension Int: AllowedObjectiveCAttributeKeyPathValue {} + +extension Int8: AllowedObjectiveCAttributeKeyPathValue {} + +extension Int16: AllowedObjectiveCAttributeKeyPathValue {} + +extension Int32: AllowedObjectiveCAttributeKeyPathValue {} + +extension Int64: AllowedObjectiveCAttributeKeyPathValue {} + +extension NSData: AllowedObjectiveCAttributeKeyPathValue {} + +extension NSDate: AllowedObjectiveCAttributeKeyPathValue {} + +extension NSNumber: AllowedObjectiveCAttributeKeyPathValue {} + +extension NSString: AllowedObjectiveCAttributeKeyPathValue {} + +extension NSURL: AllowedObjectiveCAttributeKeyPathValue {} + +extension NSUUID: AllowedObjectiveCAttributeKeyPathValue {} + +extension String: AllowedObjectiveCAttributeKeyPathValue {} + +extension URL: AllowedObjectiveCAttributeKeyPathValue {} + +extension UUID: AllowedObjectiveCAttributeKeyPathValue {} + +extension Optional: AllowedObjectiveCAttributeKeyPathValue where Wrapped: AllowedObjectiveCAttributeKeyPathValue, Wrapped: AllowedOptionalObjectiveCKeyPathValue {} -// MARK: - AllowedCoreStoreObjectKeyPathValue +// MARK: - AllowedObjectiveCRelationshipKeyPathValue /** Used only for utility methods. Types allowed as `Value` generic type to `KeyPath` utilities. */ -public protocol AllowedCoreStoreObjectKeyPathValue: DynamicKeyPath {} +public protocol AllowedObjectiveCRelationshipKeyPathValue: AllowedOptionalObjectiveCKeyPathValue {} -extension ValueContainer.Required: AllowedCoreStoreObjectKeyPathValue {} +extension NSManagedObject: AllowedObjectiveCRelationshipKeyPathValue {} -extension ValueContainer.Optional: AllowedCoreStoreObjectKeyPathValue {} +extension NSSet: AllowedObjectiveCRelationshipKeyPathValue {} -extension TransformableContainer.Required: AllowedCoreStoreObjectKeyPathValue {} +extension NSOrderedSet: AllowedObjectiveCRelationshipKeyPathValue {} -extension TransformableContainer.Optional: AllowedCoreStoreObjectKeyPathValue {} - -extension RelationshipContainer.ToOne: AllowedCoreStoreObjectKeyPathValue {} - -extension RelationshipContainer.ToManyOrdered: AllowedCoreStoreObjectKeyPathValue {} - -extension RelationshipContainer.ToManyUnordered: AllowedCoreStoreObjectKeyPathValue {} +extension Optional: AllowedOptionalObjectiveCKeyPathValue, AllowedObjectiveCRelationshipKeyPathValue where Wrapped: AllowedObjectiveCRelationshipKeyPathValue {} -// MARK: - AllowedCoreStoreObjectCollectionKeyPathValue +// MARK: - AllowedObjectiveCToManyRelationshipKeyPathValue /** Used only for utility methods. Types allowed as `Value` generic type to `KeyPath` utilities. */ -public protocol AllowedCoreStoreObjectCollectionKeyPathValue: AllowedCoreStoreObjectKeyPathValue {} +public protocol AllowedObjectiveCToManyRelationshipKeyPathValue: AllowedOptionalObjectiveCKeyPathValue {} -extension RelationshipContainer.ToManyOrdered: AllowedCoreStoreObjectCollectionKeyPathValue {} +extension NSSet: AllowedObjectiveCToManyRelationshipKeyPathValue {} -extension RelationshipContainer.ToManyUnordered: AllowedCoreStoreObjectCollectionKeyPathValue {} +extension NSOrderedSet: AllowedObjectiveCToManyRelationshipKeyPathValue {} + +extension Optional: AllowedObjectiveCToManyRelationshipKeyPathValue where Wrapped: AllowedObjectiveCToManyRelationshipKeyPathValue, Wrapped: AllowedObjectiveCRelationshipKeyPathValue {} + + +// MARK: - Deprecated + +@available(*, deprecated, renamed: "AllowedObjectiveCToManyRelationshipKeyPathValue") +public typealias AllowedCoreStoreObjectCollectionKeyPathValue = AllowedObjectiveCToManyRelationshipKeyPathValue diff --git a/Sources/KeyPathStringConvertible.swift b/Sources/KeyPathStringConvertible.swift new file mode 100644 index 0000000..dfb3fa4 --- /dev/null +++ b/Sources/KeyPathStringConvertible.swift @@ -0,0 +1,103 @@ +// +// KeyPathStringConvertible.swift +// CoreStore +// +// Copyright © 2018 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: - AnyKeyPathStringConvertible + +public protocol AnyKeyPathStringConvertible { + + /** + The keyPath string + */ + var cs_keyPathString: KeyPathString { get } +} + + +// MARK: - KeyPathStringConvertible + +/** + Used only for utility methods. + */ +public protocol KeyPathStringConvertible: AnyKeyPathStringConvertible { + + /** + The DynamicObject type + */ + associatedtype ObjectType: DynamicObject + + /** + The destination value type + */ + associatedtype DestinationValueType +} + + +// MARK: - AttributeKeyPathStringConvertible + +/** + Used only for utility methods. + */ +public protocol AttributeKeyPathStringConvertible: KeyPathStringConvertible { + + /** + The attribute value type + */ + associatedtype ReturnValueType +} + + +// MARK: - RelationshipKeyPathStringConvertible + +/** + Used only for utility methods. + */ +public protocol RelationshipKeyPathStringConvertible: KeyPathStringConvertible { + + /** + The relationship value type + */ + associatedtype ReturnValueType +} + + +// MARK: - ToManyRelationshipKeyPathStringConvertible + +/** + Used only for utility methods. + */ +public protocol ToManyRelationshipKeyPathStringConvertible: RelationshipKeyPathStringConvertible where ReturnValueType: Sequence {} + + +// MARK: - Deprecated + +@available(*, deprecated, renamed: "AnyKeyPathStringConvertible") +public typealias AnyDynamicKeyPath = AnyKeyPathStringConvertible + +@available(*, deprecated, renamed: "KeyPathStringConvertible") +public typealias DynamicKeyPath = KeyPathStringConvertible + diff --git a/Sources/OrderBy.swift b/Sources/OrderBy.swift index cf93ffd..19167d9 100644 --- a/Sources/OrderBy.swift +++ b/Sources/OrderBy.swift @@ -265,7 +265,7 @@ extension OrderBy.SortKey where D: CoreStoreObject { /** Indicates that the `KeyPathString` should be sorted in ascending order */ - public static func ascending(_ attribute: (D) -> K) -> OrderBy.SortKey { + public static func ascending(_ attribute: (D) -> K) -> OrderBy.SortKey { return .ascending(attribute(D.meta).cs_keyPathString) } @@ -273,7 +273,7 @@ extension OrderBy.SortKey where D: CoreStoreObject { /** Indicates that the `KeyPathString` should be sorted in descending order */ - public static func descending(_ attribute: (D) -> K) -> OrderBy.SortKey { + public static func descending(_ attribute: (D) -> K) -> OrderBy.SortKey { return .descending(attribute(D.meta).cs_keyPathString) } diff --git a/Sources/Relationship.swift b/Sources/Relationship.swift index 62fefde..6dfec8a 100644 --- a/Sources/Relationship.swift +++ b/Sources/Relationship.swift @@ -76,7 +76,7 @@ public enum RelationshipContainer { ``` - Important: `Relationship.ToOne` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties. */ - public final class ToOne: RelationshipProtocol { + public final class ToOne: RelationshipKeyPathStringConvertible, RelationshipProtocol { /** Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument. @@ -215,11 +215,11 @@ public enum RelationshipContainer { affectedByKeyPaths: affectedByKeyPaths() ) } - + /** - The relationship destination object. + The relationship value */ - public var value: D? { + public var value: ReturnValueType { get { @@ -230,6 +230,25 @@ public enum RelationshipContainer { self.nativeValue = newValue?.rawObject } } + + + // MARK: AnyKeyPathStringConvertible + + public var cs_keyPathString: String { + + return self.keyPath + } + + + // MARK: KeyPathStringConvertible + + public typealias ObjectType = O + public typealias DestinationValueType = D + + + // MARK: RelationshipKeyPathStringConvertible + + public typealias ReturnValueType = DestinationValueType? // MARK: RelationshipProtocol @@ -319,7 +338,7 @@ public enum RelationshipContainer { ``` - Important: `Relationship.ToManyOrdered` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties. */ - public final class ToManyOrdered: RelationshipProtocol { + public final class ToManyOrdered: ToManyRelationshipKeyPathStringConvertible, RelationshipProtocol { /** Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument. @@ -482,11 +501,11 @@ public enum RelationshipContainer { affectedByKeyPaths: affectedByKeyPaths() ) } - + /** - The relationship ordered objects. + The relationship value */ - public var value: [D] { + public var value: ReturnValueType { get { @@ -497,6 +516,25 @@ public enum RelationshipContainer { self.nativeValue = NSOrderedSet(array: newValue.map({ $0.rawObject! })) } } + + + // MARK: AnyKeyPathStringConvertible + + public var cs_keyPathString: String { + + return self.keyPath + } + + + // MARK: KeyPathStringConvertible + + public typealias ObjectType = O + public typealias DestinationValueType = D + + + // MARK: RelationshipKeyPathStringConvertible + + public typealias ReturnValueType = [DestinationValueType] // MARK: RelationshipProtocol @@ -591,7 +629,7 @@ public enum RelationshipContainer { ``` - Important: `Relationship.ToManyUnordered` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties. */ - public final class ToManyUnordered: RelationshipProtocol { + public final class ToManyUnordered: ToManyRelationshipKeyPathStringConvertible, RelationshipProtocol { /** Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument. @@ -755,11 +793,11 @@ public enum RelationshipContainer { affectedByKeyPaths: affectedByKeyPaths() ) } - + /** - The relationship unordered objects. + The relationship value */ - public var value: Set { + public var value: ReturnValueType { get { @@ -770,6 +808,25 @@ public enum RelationshipContainer { self.nativeValue = NSSet(array: newValue.map({ $0.rawObject! })) } } + + + // MARK: AnyKeyPathStringConvertible + + public var cs_keyPathString: String { + + return self.keyPath + } + + + // MARK: KeyPathStringConvertible + + public typealias ObjectType = O + public typealias DestinationValueType = D + + + // MARK: RelationshipKeyPathStringConvertible + + public typealias ReturnValueType = Set // MARK: RelationshipProtocol diff --git a/Sources/String+KeyPaths.swift b/Sources/String+KeyPaths.swift new file mode 100644 index 0000000..7054891 --- /dev/null +++ b/Sources/String+KeyPaths.swift @@ -0,0 +1,66 @@ +// +// String+KeyPaths.swift +// CoreStore +// +// Copyright © 2019 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 CoreData +import Foundation + + +// MARK: - KeyPathString + +extension KeyPathString { + + /** + Extracts the keyPath string from the property. + ``` + let keyPath = String(keyPath: \Person.nickname) + ``` + */ + public init(keyPath: KeyPath) { + + self = keyPath.cs_keyPathString + } + + /** + Extracts the keyPath string from the property. + ``` + let keyPath = String(keyPath: \Person.nickname) + ``` + */ + public init(keyPath: KeyPath) { + + self = O.meta[keyPath: keyPath].cs_keyPathString + } + + /** + Extracts the keyPath string from the property. + ``` + let keyPath = String(keyPath: \Person.nickname) + ``` + */ + public init(keyPath: Where.Expression) { + + self = keyPath.cs_keyPathString + } +} diff --git a/Sources/Transformable.swift b/Sources/Transformable.swift index 02ade8d..3f27575 100644 --- a/Sources/Transformable.swift +++ b/Sources/Transformable.swift @@ -73,7 +73,7 @@ public enum TransformableContainer { ``` - Important: `Transformable.Required` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties. */ - public final class Required: AttributeProtocol { + public final class Required: AttributeKeyPathStringConvertible, AttributeProtocol { /** Initializes the metadata for the property. @@ -138,9 +138,9 @@ public enum TransformableContainer { } /** - The property value. + The attribute value */ - public var value: V { + public var value: ReturnValueType { get { @@ -190,6 +190,25 @@ public enum TransformableContainer { } + // MARK: AnyKeyPathStringConvertible + + public var cs_keyPathString: String { + + return self.keyPath + } + + + // MARK: KeyPathStringConvertible + + public typealias ObjectType = O + public typealias DestinationValueType = V + + + // MARK: AttributeKeyPathStringConvertible + + public typealias ReturnValueType = DestinationValueType + + // MARK: AttributeProtocol internal static var attributeType: NSAttributeType { @@ -270,7 +289,7 @@ public enum TransformableContainer { ``` - Important: `Transformable.Optional` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties. */ - public final class Optional: AttributeProtocol { + public final class Optional: AttributeKeyPathStringConvertible, AttributeProtocol { /** Initializes the metadata for the property. @@ -332,9 +351,9 @@ public enum TransformableContainer { } /** - The property value. + The attribute value */ - public var value: V? { + public var value: ReturnValueType { get { @@ -384,6 +403,25 @@ public enum TransformableContainer { } + // MARK: AnyKeyPathStringConvertible + + public var cs_keyPathString: String { + + return self.keyPath + } + + + // MARK: KeyPathStringConvertible + + public typealias ObjectType = O + public typealias DestinationValueType = V + + + // MARK: AttributeKeyPathStringConvertible + + public typealias ReturnValueType = DestinationValueType? + + // MARK: AttributeProtocol internal static var attributeType: NSAttributeType { diff --git a/Sources/Value.swift b/Sources/Value.swift index bd72074..6945299 100644 --- a/Sources/Value.swift +++ b/Sources/Value.swift @@ -73,7 +73,7 @@ public enum ValueContainer { ``` - Important: `Value.Required` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties. */ - public final class Required: AttributeProtocol { + public final class Required: AttributeKeyPathStringConvertible, AttributeProtocol { /** Initializes the metadata for the property. @@ -129,11 +129,11 @@ public enum ValueContainer { self.customSetter = customSetter self.affectedByKeyPaths = affectedByKeyPaths } - + /** - The property value. + The attribute value */ - public var value: V { + public var value: ReturnValueType { get { @@ -183,6 +183,25 @@ public enum ValueContainer { } } } + + + // MARK: AnyKeyPathStringConvertible + + public var cs_keyPathString: String { + + return self.keyPath + } + + + // MARK: KeyPathStringConvertible + + public typealias ObjectType = O + public typealias DestinationValueType = V + + + // MARK: AttributeKeyPathStringConvertible + + public typealias ReturnValueType = DestinationValueType // MARK: AttributeProtocol @@ -265,7 +284,7 @@ public enum ValueContainer { ``` - Important: `Value.Optional` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties. */ - public final class Optional: AttributeProtocol { + public final class Optional: AttributeKeyPathStringConvertible, AttributeProtocol { /** Initializes the metadata for the property. @@ -324,11 +343,11 @@ public enum ValueContainer { self.customSetter = customSetter self.affectedByKeyPaths = affectedByKeyPaths } - + /** - The property value. + The attribute value */ - public var value: V? { + public var value: ReturnValueType { get { @@ -377,6 +396,25 @@ public enum ValueContainer { } } } + + + // MARK: AnyKeyPathStringConvertible + + public var cs_keyPathString: String { + + return self.keyPath + } + + + // MARK: KeyPathStringConvertible + + public typealias ObjectType = O + public typealias DestinationValueType = V + + + // MARK: AttributeKeyPathStringConvertible + + public typealias ReturnValueType = DestinationValueType? // MARK: AttributeProtocol diff --git a/Sources/Where.Expression.swift b/Sources/Where.Expression.swift index bc1808b..73c43b6 100644 --- a/Sources/Where.Expression.swift +++ b/Sources/Where.Expression.swift @@ -30,7 +30,7 @@ import CoreData // MARK: - ~ /** - Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions + Connects multiple `KeyPathStringConvertible`s to create a type-safe chain usable in query/fetch expressions ``` let owner = CoreStore.fetchOne( From().where( @@ -65,7 +65,7 @@ extension Where { ) ``` */ - public struct Expression: CustomStringConvertible, DynamicKeyPath { + public struct Expression: CustomStringConvertible, KeyPathStringConvertible { /** Currently supports `SingleTarget` and `CollectionTarget`. @@ -73,15 +73,15 @@ extension Where { public typealias Trait = T - // MARK: AnyDynamicKeyPath + // MARK: AnyKeyPathStringConvertible public let cs_keyPathString: String - // MARK: DynamicKeyPath + // MARK: KeyPathStringConvertible public typealias ObjectType = D - public typealias ValueType = V + public typealias DestinationValueType = V // MARK: CustomStringConvertible @@ -128,7 +128,7 @@ extension Where { // MARK: ~ where D: NSManagedObject /** - Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions + Connects multiple `KeyPathStringConvertible`s to create a type-safe chain usable in query/fetch expressions ``` let owner = CoreStore.fetchOne(From().where((\.master ~ \.name) == "John")) ``` @@ -139,7 +139,7 @@ public func ~().where((\.master ~ \.name) == "John")) ``` @@ -150,29 +150,29 @@ public func ~ ().where((\.master ~ \.pets).count() > 1)) ``` */ -public func ~ (_ lhs: KeyPath, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, V> { +public func ~ (_ lhs: KeyPath, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, V> { return .init(lhs.cs_keyPathString, rhs.cs_keyPathString) } /** - Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions + Connects multiple `KeyPathStringConvertible`s to create a type-safe chain usable in query/fetch expressions ``` let happyPets = CoreStore.fetchAll(From().where((\.master ~ \.pets).count() > 1)) ``` */ -public func ~ (_ lhs: KeyPath, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, V> { +public func ~ (_ lhs: KeyPath, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, V> { return .init(lhs.cs_keyPathString, rhs.cs_keyPathString) } /** - Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions + Connects multiple `KeyPathStringConvertible`s to create a type-safe chain usable in query/fetch expressions ``` let johnsSonInLaw = CoreStore.fetchOne(From().where((\.spouse ~ \.father ~ \.name) == "John")) ``` @@ -183,7 +183,7 @@ public func ~ ().where((\.spouse ~ \.father ~ \.name) == "John")) ``` @@ -194,34 +194,34 @@ public func ~ ().where((\.spouse ~ \.father ~ \.children).count() > 0)) ``` */ -public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, V> { +public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, V> { return .init(lhs.cs_keyPathString, rhs.cs_keyPathString) } /** - Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions + Connects multiple `KeyPathStringConvertible`s to create a type-safe chain usable in query/fetch expressions ``` let spouseHasSiblings = CoreStore.fetchOne(From().where((\.spouse ~ \.father ~ \.children).count() > 0)) ``` */ -public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, V> { +public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, V> { return .init(lhs.cs_keyPathString, rhs.cs_keyPathString) } /** - Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions + Connects multiple `KeyPathStringConvertible`s to create a type-safe chain usable in query/fetch expressions ``` let spousesWithBadNamingSense = CoreStore.fetchAll(From().where((\.spouse ~ \.pets ~ \.name).any() == "Spot")) ``` */ -public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, V> { +public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, V> { return .init(lhs.cs_keyPathString, rhs.cs_keyPathString) } @@ -230,12 +230,12 @@ public func ~ ().where((\.master ~ \.name) == "John")) ``` */ -public func ~ (_ lhs: KeyPath.ToOne>, _ rhs: KeyPath) -> Where.Expression.SingleTarget, K.ValueType> where K.ObjectType == O { +public func ~ (_ lhs: KeyPath.ToOne>, _ rhs: KeyPath) -> Where.Expression.SingleTarget, K.DestinationValueType> where K.ObjectType == O { return .init( D.meta[keyPath: lhs].cs_keyPathString, @@ -244,12 +244,12 @@ public func ~ ().where((\.master ~ \.name) == "John")) ``` */ -public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression where K.ObjectType == O { +public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression where K.ObjectType == O { return .init( lhs.cs_keyPathString, @@ -258,12 +258,12 @@ public func ~ ().where((\.master ~ \.name) == "John")) ``` */ -public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression where K.ObjectType == O { +public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression where K.ObjectType == O { return .init( lhs.cs_keyPathString, @@ -272,12 +272,12 @@ public func ~ ().where((\.master ~ \.pets).count() > 1)) ``` */ -public func ~ (_ lhs: KeyPath.ToOne>, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, K.ValueType> where K.ObjectType == O { +public func ~ (_ lhs: KeyPath.ToOne>, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, K.DestinationValueType> where K.ObjectType == O { return .init( D.meta[keyPath: lhs].cs_keyPathString, @@ -286,12 +286,12 @@ public func ~ ().where((\.master ~ \.pets).count() > 1)) ``` */ -public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, K.ValueType> where K.ObjectType == O { +public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, K.DestinationValueType> where K.ObjectType == O { return .init( lhs.cs_keyPathString, @@ -300,12 +300,12 @@ public func ~ ().where((\.master ~ \.pets).count() > 1)) ``` */ -public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, K.ValueType> where K.ObjectType == O { +public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, K.DestinationValueType> where K.ObjectType == O { return .init( lhs.cs_keyPathString, @@ -314,12 +314,12 @@ public func ~ ().where((\.master ~ \.pets ~ \.name).any() == "Spot")) ``` */ -public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, KV.ValueType> where KC.ObjectType == D, KV.ObjectType == O { +public func ~ (_ lhs: Where.Expression, _ rhs: KeyPath) -> Where.Expression.CollectionTarget, KV.DestinationValueType> where KC.ObjectType == D, KV.ObjectType == O { return .init( lhs.cs_keyPathString, @@ -516,9 +516,9 @@ public func >= (_ lhs: Where.Ex } -// MARK: - KeyPath where Root: NSManagedObject, Value: AllowedObjectiveCCollectionKeyPathValue +// MARK: - KeyPath where Root: NSManagedObject, Value: AllowedObjectiveCToManyRelationshipKeyPathValue -extension KeyPath where Root: NSManagedObject, Value: AllowedObjectiveCCollectionKeyPathValue { +extension KeyPath where Root: NSManagedObject, Value: AllowedObjectiveCToManyRelationshipKeyPathValue { /** Creates a `Where.Expression` clause for COUNT @@ -532,9 +532,9 @@ extension KeyPath where Root: NSManagedObject, Value: AllowedObjectiveCCollectio } } -// MARK: - Where.Expression where D: NSManagedObject, T == Where.CollectionTarget, V: AllowedObjectiveCCollectionKeyPathValue +// MARK: - Where.Expression where D: NSManagedObject, T == Where.CollectionTarget, V: AllowedObjectiveCToManyRelationshipKeyPathValue -extension Where.Expression where D: NSManagedObject, T == Where.CollectionTarget, V: AllowedObjectiveCCollectionKeyPathValue { +extension Where.Expression where D: NSManagedObject, T == Where.CollectionTarget, V: AllowedObjectiveCToManyRelationshipKeyPathValue { /** Creates a `Where.Expression` clause for COUNT @@ -588,9 +588,9 @@ extension Where.Expression where D: NSManagedObject, T == Where.CollectionTar } -// MARK: - KeyPath where Root: CoreStoreObject, Value: AllowedObjectiveCCollectionKeyPathValue +// MARK: - KeyPath where Root: CoreStoreObject, Value: AllowedObjectiveCToManyRelationshipKeyPathValue -extension KeyPath where Root: CoreStoreObject, Value: AllowedCoreStoreObjectCollectionKeyPathValue { +extension KeyPath where Root: CoreStoreObject, Value: ToManyRelationshipKeyPathStringConvertible { /** Creates a `Where.Expression` clause for COUNT From 02d5bf85ae398c5f0d9c6336ba4a90c9d0580295 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 20 Aug 2019 12:42:34 +0900 Subject: [PATCH 5/7] fix ListMonitor demo for iOS 13 --- .../ListObserverDemoViewController.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ListObserverDemoViewController.swift b/CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ListObserverDemoViewController.swift index 6838694..265d4f5 100644 --- a/CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ListObserverDemoViewController.swift +++ b/CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ListObserverDemoViewController.swift @@ -260,9 +260,8 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver } func listMonitor(_ monitor: ListMonitor, didMoveObject object: Palette, fromIndexPath: IndexPath, toIndexPath: IndexPath) { - - self.tableView.deleteRows(at: [fromIndexPath], with: .automatic) - self.tableView.insertRows(at: [toIndexPath], with: .automatic) + + self.tableView.moveRow(at: fromIndexPath, to: toIndexPath) } From 058cc1915b007ce35e7231d017c291051d419d3f Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 27 Aug 2019 14:21:33 +0900 Subject: [PATCH 6/7] fix optimization issues in release build --- Sources/CoreStoreObject+Observing.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/CoreStoreObject+Observing.swift b/Sources/CoreStoreObject+Observing.swift index 81d4365..06db158 100644 --- a/Sources/CoreStoreObject+Observing.swift +++ b/Sources/CoreStoreObject+Observing.swift @@ -462,8 +462,8 @@ extension AttributeProtocol { let notification = CoreStoreObjectValueDiff( kind: kind, - newNativeValue: newValue as! V.QueryableNativeType?, - oldNativeValue: oldValue as! V.QueryableNativeType?, + newNativeValue: newValue as? V.QueryableNativeType, + oldNativeValue: oldValue as? V.QueryableNativeType, isPrior: isPrior ) changeHandler( @@ -485,8 +485,8 @@ extension AttributeProtocol { let notification = CoreStoreObjectTransformableDiff( kind: kind, - newValue: newValue as! V?, - oldValue: oldValue as! V?, + newValue: newValue as? V, + oldValue: oldValue as? V, isPrior: isPrior ) changeHandler( From d42b397090218834d66f656828ea1962acf0a157 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 27 Aug 2019 14:38:05 +0900 Subject: [PATCH 7/7] version bump --- CoreStore.podspec | 2 +- CoreStoreDemo/CoreStoreDemo/Info.plist | 2 +- Sources/Info.plist | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CoreStore.podspec b/CoreStore.podspec index 77f0e7a..fdb9527 100644 --- a/CoreStore.podspec +++ b/CoreStore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "CoreStore" - s.version = "6.3.1" + s.version = "6.3.2" s.swift_version = "5.0" s.license = "MIT" s.homepage = "https://github.com/JohnEstropia/CoreStore" diff --git a/CoreStoreDemo/CoreStoreDemo/Info.plist b/CoreStoreDemo/CoreStoreDemo/Info.plist index bdbcece..15874fa 100644 --- a/CoreStoreDemo/CoreStoreDemo/Info.plist +++ b/CoreStoreDemo/CoreStoreDemo/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 6.3.1 + 6.3.2 CFBundleSignature ???? CFBundleVersion diff --git a/Sources/Info.plist b/Sources/Info.plist index 032c5c4..da1d595 100644 --- a/Sources/Info.plist +++ b/Sources/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 6.3.1 + 6.3.2 CFBundleSignature ???? CFBundleVersion