From 645034dde5b2dacd71b8adb2ad11cda4e42576c0 Mon Sep 17 00:00:00 2001 From: John Rommel Estropia Date: Sun, 24 Sep 2017 10:38:17 +0900 Subject: [PATCH] keyPath utilities for SectionBy clauses --- ...etchingAndQueryingDemoViewController.swift | 40 +++--- .../MigrationsDemoViewController.swift | 4 +- CoreStoreTests/SectionByTests.swift | 4 +- Sources/CSSectionBy.swift | 22 +++- Sources/ChainedClauseBuilder.swift | 23 +++- Sources/CoreStore+Observing.swift | 8 +- .../CoreStoreFetchedResultsController.swift | 4 +- Sources/DataStack+Observing.swift | 8 +- Sources/ListMonitor.swift | 14 +- ...FetchedResultsController+Convenience.swift | 10 +- Sources/SectionBy.swift | 120 +++++++++++++++++- Sources/UnsafeDataTransaction+Observing.swift | 8 +- 12 files changed, 207 insertions(+), 58 deletions(-) diff --git a/CoreStoreDemo/CoreStoreDemo/Fetching and Querying Demo/FetchingAndQueryingDemoViewController.swift b/CoreStoreDemo/CoreStoreDemo/Fetching and Querying Demo/FetchingAndQueryingDemoViewController.swift index cfee272..d39a850 100644 --- a/CoreStoreDemo/CoreStoreDemo/Fetching and Querying Demo/FetchingAndQueryingDemoViewController.swift +++ b/CoreStoreDemo/CoreStoreDemo/Fetching and Querying Demo/FetchingAndQueryingDemoViewController.swift @@ -237,7 +237,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo return Static.timeZonesStack.queryValue( From() - .select(NSNumber.self, .count(#keyPath(TimeZone.name))) + .select(NSNumber.self, .count(\.name)) )! as Any } ), @@ -247,7 +247,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo return Static.timeZonesStack.queryValue( From() - .select(String.self, .attribute(#keyPath(TimeZone.abbreviation))) + .select(String.self, .attribute(\.abbreviation)) .where(format: "%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo") )! as Any } @@ -260,10 +260,10 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo From() .select( NSDictionary.self, - .attribute(#keyPath(TimeZone.name)), - .attribute(#keyPath(TimeZone.abbreviation)) + .attribute(\.name), + .attribute(\.abbreviation) ) - .orderBy(.ascending(#keyPath(TimeZone.name))) + .orderBy(.ascending(\.name)) )! } ), @@ -275,14 +275,14 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo From() .select( NSDictionary.self, - .count(#keyPath(TimeZone.abbreviation)), - .attribute(#keyPath(TimeZone.abbreviation)) + .count(\.abbreviation), + .attribute(\.abbreviation) ) - .groupBy(#keyPath(TimeZone.abbreviation)) + .groupBy(\.abbreviation) .orderBy( - .ascending(#keyPath(TimeZone.secondsFromGMT)), - .ascending(#keyPath(TimeZone.name)) - ) + .ascending(\.secondsFromGMT), + .ascending(\.name) + ) )! } ), @@ -291,13 +291,17 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo query: { () -> Any in return Static.timeZonesStack.queryAttributes( - From(), - Select( - .count(#keyPath(TimeZone.hasDaylightSavingTime), as: "numberOfCountries"), - #keyPath(TimeZone.hasDaylightSavingTime) - ), - GroupBy(#keyPath(TimeZone.hasDaylightSavingTime)), - OrderBy(.descending(#keyPath(TimeZone.hasDaylightSavingTime))) + From() + .select( + NSDictionary.self, + .count(\.hasDaylightSavingTime, as: "numberOfCountries"), + .attribute(\.hasDaylightSavingTime) + ) + .groupBy(\.hasDaylightSavingTime) + .orderBy( + .descending(\.hasDaylightSavingTime), + .ascending(\.name) + ) )! } ) diff --git a/CoreStoreDemo/CoreStoreDemo/MIgrations Demo/MigrationsDemoViewController.swift b/CoreStoreDemo/CoreStoreDemo/MIgrations Demo/MigrationsDemoViewController.swift index 9227773..56fa48f 100644 --- a/CoreStoreDemo/CoreStoreDemo/MIgrations Demo/MigrationsDemoViewController.swift +++ b/CoreStoreDemo/CoreStoreDemo/MIgrations Demo/MigrationsDemoViewController.swift @@ -287,8 +287,8 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD self.set(dataStack: dataStack, model: model, scrollToSelection: true) let count = dataStack.queryValue( - From(model.entityType), - Select(.count(#keyPath(OrganismV1.dna))))! + From(model.entityType) + .select(Int.self, .count(#keyPath(OrganismV1.dna))))! if count > 0 { self.setEnabled(true) diff --git a/CoreStoreTests/SectionByTests.swift b/CoreStoreTests/SectionByTests.swift index 29132e6..686d109 100644 --- a/CoreStoreTests/SectionByTests.swift +++ b/CoreStoreTests/SectionByTests.swift @@ -39,13 +39,13 @@ final class SectionByTests: XCTestCase { do { - let sectionBy = SectionBy("key") + let sectionBy = SectionBy("key") XCTAssertEqual(sectionBy.sectionKeyPath, "key") XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key") } do { - let sectionBy = SectionBy("key") { $0.flatMap { "\($0):suffix" } } + let sectionBy = SectionBy("key") { $0.flatMap { "\($0):suffix" } } XCTAssertEqual(sectionBy.sectionKeyPath, "key") XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key:suffix") XCTAssertNil(sectionBy.sectionIndexTransformer(nil)) diff --git a/Sources/CSSectionBy.swift b/Sources/CSSectionBy.swift index bccdffc..f8c2fc7 100644 --- a/Sources/CSSectionBy.swift +++ b/Sources/CSSectionBy.swift @@ -36,7 +36,7 @@ import CoreData */ @available(OSX 10.12, *) @objc -public final class CSSectionBy: NSObject, CoreStoreObjectiveCType { +public final class CSSectionBy: NSObject { /** Initializes a `CSSectionBy` clause with the key path to use to group `CSListMonitor` objects into sections @@ -47,7 +47,7 @@ public final class CSSectionBy: NSObject, CoreStoreObjectiveCType { @objc public static func keyPath(_ sectionKeyPath: KeyPathString) -> CSSectionBy { - return self.init(SectionBy(sectionKeyPath)) + return self.init(SectionBy(sectionKeyPath)) } /** @@ -60,7 +60,7 @@ public final class CSSectionBy: NSObject, CoreStoreObjectiveCType { @objc public static func keyPath(_ sectionKeyPath: KeyPathString, sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> CSSectionBy { - return self.init(SectionBy(sectionKeyPath, sectionIndexTransformer)) + return self.init(SectionBy(sectionKeyPath, sectionIndexTransformer)) } @@ -74,11 +74,11 @@ public final class CSSectionBy: NSObject, CoreStoreObjectiveCType { // MARK: CoreStoreObjectiveCType - public let bridgeToSwift: SectionBy + public let bridgeToSwift: SectionBy - public init(_ swiftValue: SectionBy) { + public init(_ swiftValue: SectionBy) { - self.bridgeToSwift = swiftValue + self.bridgeToSwift = swiftValue.downcast() super.init() } } @@ -87,7 +87,7 @@ public final class CSSectionBy: NSObject, CoreStoreObjectiveCType { // MARK: - SectionBy @available(OSX 10.12, *) -extension SectionBy: CoreStoreSwiftType { +extension SectionBy { // MARK: CoreStoreSwiftType @@ -95,4 +95,12 @@ extension SectionBy: CoreStoreSwiftType { return CSSectionBy(self) } + + + // MARK: FilePrivate + + fileprivate func downcast() -> SectionBy { + + return SectionBy(self.sectionKeyPath, self.sectionIndexTransformer) + } } diff --git a/Sources/ChainedClauseBuilder.swift b/Sources/ChainedClauseBuilder.swift index 30119d1..1433d94 100644 --- a/Sources/ChainedClauseBuilder.swift +++ b/Sources/ChainedClauseBuilder.swift @@ -51,7 +51,7 @@ public protocol SectionMonitorBuilderType { associatedtype ObjectType: DynamicObject var from: From { get set } - var sectionBy: SectionBy { get set } + var sectionBy: SectionBy { get set } var fetchClauses: [FetchClause] { get set } } @@ -92,7 +92,7 @@ public struct SectionMonitorChainBuilder: SectionMonitorBuilde // MARK: SectionMonitorBuilderType public var from: From - public var sectionBy: SectionBy + public var sectionBy: SectionBy public var fetchClauses: [FetchClause] = [] } @@ -101,6 +101,15 @@ public struct SectionMonitorChainBuilder: SectionMonitorBuilde public extension From { + public func select(_ clause: Select) -> QueryChainBuilder { + + return .init( + from: self, + select: clause, + queryClauses: [] + ) + } + public func select(_ resultType: R.Type, _ selectTerm: SelectTerm, _ selectTerms: SelectTerm...) -> QueryChainBuilder { return self.select(resultType, [selectTerm] + selectTerms) @@ -115,6 +124,16 @@ public extension From { ) } + @available(OSX 10.12, *) + public func sectionBy(_ clause: SectionBy) -> SectionMonitorChainBuilder { + + return .init( + from: self, + sectionBy: clause, + fetchClauses: [] + ) + } + @available(OSX 10.12, *) public func sectionBy(_ sectionKeyPath: KeyPathString) -> SectionMonitorChainBuilder { diff --git a/Sources/CoreStore+Observing.swift b/Sources/CoreStore+Observing.swift index 546f740..01f5993 100644 --- a/Sources/CoreStore+Observing.swift +++ b/Sources/CoreStore+Observing.swift @@ -115,7 +115,7 @@ public extension CoreStore { - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: a `ListMonitor` instance that monitors changes to the list */ - public static func monitorSectionedList(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> ListMonitor { + public static func monitorSectionedList(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> ListMonitor { return self.defaultStack.monitorSectionedList(from, sectionBy, fetchClauses) } @@ -128,7 +128,7 @@ public extension CoreStore { - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: a `ListMonitor` instance that monitors changes to the list */ - public static func monitorSectionedList(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> ListMonitor { + public static func monitorSectionedList(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> ListMonitor { return self.defaultStack.monitorSectionedList(from, sectionBy, fetchClauses) } @@ -151,7 +151,7 @@ public extension CoreStore { - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. */ - public static func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) { + public static func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) { self.defaultStack.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses) } @@ -164,7 +164,7 @@ public extension CoreStore { - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. */ - public static func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) { + public static func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) { self.defaultStack.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses) } diff --git a/Sources/CoreStoreFetchedResultsController.swift b/Sources/CoreStoreFetchedResultsController.swift index b0c18cb..2230a22 100644 --- a/Sources/CoreStoreFetchedResultsController.swift +++ b/Sources/CoreStoreFetchedResultsController.swift @@ -35,7 +35,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll // MARK: Internal @nonobjc - internal convenience init(dataStack: DataStack, fetchRequest: NSFetchRequest, from: From, sectionBy: SectionBy? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void) { + internal convenience init(dataStack: DataStack, fetchRequest: NSFetchRequest, from: From, sectionBy: SectionBy? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void) { self.init( context: dataStack.mainContext, @@ -47,7 +47,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll } @nonobjc - internal init(context: NSManagedObjectContext, fetchRequest: NSFetchRequest, from: From, sectionBy: SectionBy? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void) { + internal init(context: NSManagedObjectContext, fetchRequest: NSFetchRequest, from: From, sectionBy: SectionBy? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void) { _ = from.applyToFetchRequest( fetchRequest, diff --git a/Sources/DataStack+Observing.swift b/Sources/DataStack+Observing.swift index 1c08c18..611130d 100644 --- a/Sources/DataStack+Observing.swift +++ b/Sources/DataStack+Observing.swift @@ -154,7 +154,7 @@ public extension DataStack { - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: a `ListMonitor` instance that monitors changes to the list */ - public func monitorSectionedList(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> ListMonitor { + public func monitorSectionedList(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> ListMonitor { return self.monitorSectionedList(from, sectionBy, fetchClauses) } @@ -167,7 +167,7 @@ public extension DataStack { - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: a `ListMonitor` instance that monitors changes to the list */ - public func monitorSectionedList(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> ListMonitor { + public func monitorSectionedList(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> ListMonitor { CoreStore.assert( Thread.isMainThread, @@ -208,7 +208,7 @@ public extension DataStack { - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. */ - public func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) { + public func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) { self.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses) } @@ -221,7 +221,7 @@ public extension DataStack { - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. */ - public func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) { + public func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) { CoreStore.assert( Thread.isMainThread, diff --git a/Sources/ListMonitor.swift b/Sources/ListMonitor.swift index 1492405..acf2019 100644 --- a/Sources/ListMonitor.swift +++ b/Sources/ListMonitor.swift @@ -626,7 +626,7 @@ public final class ListMonitor: Hashable { // MARK: Internal - internal convenience init(dataStack: DataStack, from: From, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void) { + internal convenience init(dataStack: DataStack, from: From, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void) { self.init( context: dataStack.mainContext, @@ -638,7 +638,7 @@ public final class ListMonitor: Hashable { ) } - internal convenience init(dataStack: DataStack, from: From, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void, createAsynchronously: @escaping (ListMonitor) -> Void) { + internal convenience init(dataStack: DataStack, from: From, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void, createAsynchronously: @escaping (ListMonitor) -> Void) { self.init( context: dataStack.mainContext, @@ -650,7 +650,7 @@ public final class ListMonitor: Hashable { ) } - internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void) { + internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void) { self.init( context: unsafeTransaction.context, @@ -662,7 +662,7 @@ public final class ListMonitor: Hashable { ) } - internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void, createAsynchronously: @escaping (ListMonitor) -> Void) { + internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void, createAsynchronously: @escaping (ListMonitor) -> Void) { self.init( context: unsafeTransaction.context, @@ -1041,7 +1041,7 @@ public final class ListMonitor: Hashable { } } - private static func recreateFetchedResultsController(context: NSManagedObjectContext, from: From, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void) -> (controller: CoreStoreFetchedResultsController, delegate: FetchedResultsControllerDelegate) { + private static func recreateFetchedResultsController(context: NSManagedObjectContext, from: From, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void) -> (controller: CoreStoreFetchedResultsController, delegate: FetchedResultsControllerDelegate) { let fetchRequest = CoreStoreFetchRequest() fetchRequest.fetchLimit = 0 @@ -1065,9 +1065,9 @@ public final class ListMonitor: Hashable { } private let from: From - private let sectionBy: SectionBy? + private let sectionBy: SectionBy? - private init(context: NSManagedObjectContext, transactionQueue: DispatchQueue, from: From, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void, createAsynchronously: ((ListMonitor) -> Void)?) { + private init(context: NSManagedObjectContext, transactionQueue: DispatchQueue, from: From, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest) -> Void, createAsynchronously: ((ListMonitor) -> Void)?) { self.isSectioned = (sectionBy != nil) self.from = from diff --git a/Sources/NSFetchedResultsController+Convenience.swift b/Sources/NSFetchedResultsController+Convenience.swift index 3d1c552..1bcb1fa 100644 --- a/Sources/NSFetchedResultsController+Convenience.swift +++ b/Sources/NSFetchedResultsController+Convenience.swift @@ -42,7 +42,7 @@ public extension DataStack { - returns: an `NSFetchedResultsController` that observes the `DataStack` */ @nonobjc - public func createFetchedResultsController(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController { + public func createFetchedResultsController(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController { return createFRC( fromContext: self.mainContext, @@ -62,7 +62,7 @@ public extension DataStack { - returns: an `NSFetchedResultsController` that observes the `DataStack` */ @nonobjc - public func createFetchedResultsController(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController { + public func createFetchedResultsController(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController { return createFRC( fromContext: self.mainContext, @@ -127,7 +127,7 @@ public extension UnsafeDataTransaction { - returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction` */ @nonobjc - public func createFetchedResultsController(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController { + public func createFetchedResultsController(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController { return createFRC( fromContext: self.context, @@ -147,7 +147,7 @@ public extension UnsafeDataTransaction { - returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction` */ @nonobjc - public func createFetchedResultsController(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController { + public func createFetchedResultsController(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController { return createFRC( fromContext: self.context, @@ -201,7 +201,7 @@ public extension UnsafeDataTransaction { // MARK: - Private @available(OSX 10.12, *) -fileprivate func createFRC(fromContext context: NSManagedObjectContext, from: From, sectionBy: SectionBy? = nil, fetchClauses: [FetchClause]) -> NSFetchedResultsController { +fileprivate func createFRC(fromContext context: NSManagedObjectContext, from: From, sectionBy: SectionBy? = nil, fetchClauses: [FetchClause]) -> NSFetchedResultsController { let controller = CoreStoreFetchedResultsController( context: context, diff --git a/Sources/SectionBy.swift b/Sources/SectionBy.swift index f9ac2b7..629fd2f 100644 --- a/Sources/SectionBy.swift +++ b/Sources/SectionBy.swift @@ -40,7 +40,7 @@ import CoreData ``` */ @available(OSX 10.12, *) -public struct SectionBy { +public struct SectionBy { /** Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections @@ -71,3 +71,121 @@ public struct SectionBy { internal let sectionKeyPath: KeyPathString internal let sectionIndexTransformer: (_ sectionName: String?) -> String? } + +@available(OSX 10.12, *) +public extension SectionBy where D: NSManagedObject { + + /** + Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections + + - parameter sectionKeyPath: the key path to use to group the objects into sections + */ + public init(_ sectionKeyPath: KeyPath) { + + self.init(sectionKeyPath, { $0 }) + } + + /** + Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name + + - Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly. + - parameter sectionKeyPath: the key path to use to group the objects into sections + - parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name + */ + public init(_ sectionKeyPath: KeyPath, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) { + + self.init(sectionKeyPath._kvcKeyPathString!, sectionIndexTransformer) + } +} + +@available(OSX 10.12, *) +public extension SectionBy where D: CoreStoreObject { + + /** + Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections + + - parameter sectionKeyPath: the key path to use to group the objects into sections + */ + public init(_ sectionKeyPath: KeyPath.Required>) { + + self.init(sectionKeyPath, { $0 }) + } + + /** + Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections + + - parameter sectionKeyPath: the key path to use to group the objects into sections + */ + public init(_ sectionKeyPath: KeyPath.Optional>) { + + self.init(sectionKeyPath, { $0 }) + } + + /** + Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections + + - parameter sectionKeyPath: the key path to use to group the objects into sections + */ + public init(_ sectionKeyPath: KeyPath.Required>) { + + self.init(sectionKeyPath, { $0 }) + } + + /** + Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections + + - parameter sectionKeyPath: the key path to use to group the objects into sections + */ + public init(_ sectionKeyPath: KeyPath.Optional>) { + + self.init(sectionKeyPath, { $0 }) + } + + /** + Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name + + - Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly. + - parameter sectionKeyPath: the key path to use to group the objects into sections + - parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name + */ + public init(_ sectionKeyPath: KeyPath.Required>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) { + + self.init(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer) + } + + /** + Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name + + - Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly. + - parameter sectionKeyPath: the key path to use to group the objects into sections + - parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name + */ + public init(_ sectionKeyPath: KeyPath.Optional>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) { + + self.init(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer) + } + + /** + Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name + + - Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly. + - parameter sectionKeyPath: the key path to use to group the objects into sections + - parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name + */ + public init(_ sectionKeyPath: KeyPath.Required>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) { + + self.init(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer) + } + + /** + Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name + + - Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly. + - parameter sectionKeyPath: the key path to use to group the objects into sections + - parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name + */ + public init(_ sectionKeyPath: KeyPath.Optional>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) { + + self.init(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer) + } +} diff --git a/Sources/UnsafeDataTransaction+Observing.swift b/Sources/UnsafeDataTransaction+Observing.swift index 9a9b861..7ad6a67 100644 --- a/Sources/UnsafeDataTransaction+Observing.swift +++ b/Sources/UnsafeDataTransaction+Observing.swift @@ -145,7 +145,7 @@ public extension UnsafeDataTransaction { - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: a `ListMonitor` instance that monitors changes to the list */ - public func monitorSectionedList(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> ListMonitor { + public func monitorSectionedList(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> ListMonitor { return self.monitorSectionedList(from, sectionBy, fetchClauses) } @@ -158,7 +158,7 @@ public extension UnsafeDataTransaction { - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: a `ListMonitor` instance that monitors changes to the list */ - public func monitorSectionedList(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> ListMonitor { + public func monitorSectionedList(_ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> ListMonitor { CoreStore.assert( fetchClauses.filter { $0 is OrderBy }.count > 0, @@ -194,7 +194,7 @@ public extension UnsafeDataTransaction { - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. */ - public func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) { + public func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) { self.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses) } @@ -207,7 +207,7 @@ public extension UnsafeDataTransaction { - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. */ - public func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) { + public func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ from: From, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) { CoreStore.assert( fetchClauses.filter { $0 is OrderBy }.count > 0,