From 57778315653f1f3583a73c3ad140732eec8329f2 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Fri, 11 Jan 2019 19:52:12 +0900 Subject: [PATCH] WIP: make fetching methods throwable --- Sources/BaseDataTransaction+Querying.swift | 36 ++--- Sources/CSError.swift | 8 ++ Sources/CSListMonitor.swift | 20 +-- Sources/CoreStore+Observing.swift | 7 +- Sources/CoreStore+Querying.swift | 36 ++--- Sources/CoreStoreError.swift | 24 ++++ .../CoreStoreFetchedResultsController.swift | 14 +- Sources/DataStack+Observing.swift | 7 +- Sources/DataStack+Querying.swift | 36 ++--- Sources/FetchableSource.swift | 18 +-- Sources/From.swift | 35 +++-- Sources/ListMonitor.swift | 127 ++++++++++++++---- .../NSManagedObjectContext+ObjectiveC.swift | 60 +++------ Sources/NSManagedObjectContext+Querying.swift | 95 ++++++------- Sources/UnsafeDataTransaction+Observing.swift | 21 ++- Sources/Where.swift | 8 +- 16 files changed, 326 insertions(+), 226 deletions(-) diff --git a/Sources/BaseDataTransaction+Querying.swift b/Sources/BaseDataTransaction+Querying.swift index 39b05bd..4d712c5 100644 --- a/Sources/BaseDataTransaction+Querying.swift +++ b/Sources/BaseDataTransaction+Querying.swift @@ -138,13 +138,13 @@ extension BaseDataTransaction: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s */ - public func fetchOne(_ from: From, _ fetchClauses: FetchClause...) -> D? { + public func fetchOne(_ from: From, _ fetchClauses: FetchClause...) throws -> D? { CoreStore.assert( self.isRunningInAllowedQueue(), "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." ) - return self.context.fetchOne(from, fetchClauses) + return try self.context.fetchOne(from, fetchClauses) } /** @@ -154,13 +154,13 @@ extension BaseDataTransaction: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s */ - public func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) -> D? { + public func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) throws -> D? { CoreStore.assert( self.isRunningInAllowedQueue(), "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." ) - return self.context.fetchOne(from, fetchClauses) + return try self.context.fetchOne(from, fetchClauses) } /** @@ -175,13 +175,13 @@ extension BaseDataTransaction: FetchableSource, QueryableSource { - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - returns: the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType` */ - public func fetchOne(_ clauseChain: B) -> B.ObjectType? { + public func fetchOne(_ clauseChain: B) throws -> B.ObjectType? { CoreStore.assert( self.isRunningInAllowedQueue(), "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." ) - return self.context.fetchOne(clauseChain) + return try self.context.fetchOne(clauseChain) } /** @@ -191,13 +191,13 @@ extension BaseDataTransaction: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s */ - public func fetchAll(_ from: From, _ fetchClauses: FetchClause...) -> [D]? { + public func fetchAll(_ from: From, _ fetchClauses: FetchClause...) throws -> [D] { CoreStore.assert( self.isRunningInAllowedQueue(), "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." ) - return self.context.fetchAll(from, fetchClauses) + return try self.context.fetchAll(from, fetchClauses) } /** @@ -207,13 +207,13 @@ extension BaseDataTransaction: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s */ - public func fetchAll(_ from: From, _ fetchClauses: [FetchClause]) -> [D]? { + public func fetchAll(_ from: From, _ fetchClauses: [FetchClause]) throws -> [D] { CoreStore.assert( self.isRunningInAllowedQueue(), "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." ) - return self.context.fetchAll(from, fetchClauses) + return try self.context.fetchAll(from, fetchClauses) } /** @@ -228,13 +228,13 @@ extension BaseDataTransaction: FetchableSource, QueryableSource { - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - returns: all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType` */ - public func fetchAll(_ clauseChain: B) -> [B.ObjectType]? { + public func fetchAll(_ clauseChain: B) throws -> [B.ObjectType] { CoreStore.assert( self.isRunningInAllowedQueue(), "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." ) - return self.context.fetchAll(clauseChain) + return try self.context.fetchAll(clauseChain) } /** @@ -244,13 +244,13 @@ extension BaseDataTransaction: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s */ - public func fetchCount(_ from: From, _ fetchClauses: FetchClause...) -> Int? { + public func fetchCount(_ from: From, _ fetchClauses: FetchClause...) throws -> Int { CoreStore.assert( self.isRunningInAllowedQueue(), "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." ) - return self.context.fetchCount(from, fetchClauses) + return try self.context.fetchCount(from, fetchClauses) } /** @@ -260,13 +260,13 @@ extension BaseDataTransaction: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s */ - public func fetchCount(_ from: From, _ fetchClauses: [FetchClause]) -> Int? { + public func fetchCount(_ from: From, _ fetchClauses: [FetchClause]) throws -> Int { CoreStore.assert( self.isRunningInAllowedQueue(), "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." ) - return self.context.fetchCount(from, fetchClauses) + return try self.context.fetchCount(from, fetchClauses) } /** @@ -281,13 +281,13 @@ extension BaseDataTransaction: FetchableSource, QueryableSource { - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - returns: the number `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` */ - public func fetchCount(_ clauseChain: B) -> Int? { + public func fetchCount(_ clauseChain: B) throws -> Int { CoreStore.assert( self.isRunningInAllowedQueue(), "Attempted to fetch from a \(cs_typeName(self)) outside its designated queue." ) - return self.context.fetchCount(clauseChain) + return try self.context.fetchCount(clauseChain) } /** diff --git a/Sources/CSError.swift b/Sources/CSError.swift index 9fb1feb..84908ff 100644 --- a/Sources/CSError.swift +++ b/Sources/CSError.swift @@ -247,6 +247,14 @@ extension CoreStoreError: CoreStoreSwiftType, _ObjectiveCBridgeableError { case .userCancelled: self = .userCancelled + + case .persistentStoreNotFound: + guard let entity = info["entity"] as? DynamicObject.Type else { + + self = .unknown + return + } + self = .persistentStoreNotFound(entity: entity) } } } diff --git a/Sources/CSListMonitor.swift b/Sources/CSListMonitor.swift index d639067..44097f6 100644 --- a/Sources/CSListMonitor.swift +++ b/Sources/CSListMonitor.swift @@ -132,7 +132,7 @@ public final class CSListMonitor: NSObject { @objc public func hasObjectsInSection(_ section: Int) -> Bool { - return self.bridgeToSwift.hasObjectsInSection(section) + return self.bridgeToSwift.hasObjects(in: section) } /** @@ -155,7 +155,7 @@ public final class CSListMonitor: NSObject { @objc public func objectsInSection(_ section: Int) -> [NSManagedObject] { - return self.bridgeToSwift.objectsInSection(section) + return self.bridgeToSwift.objects(in: section) } /** @@ -167,7 +167,7 @@ public final class CSListMonitor: NSObject { @objc public func objectsInSafeSection(safeSectionIndex section: Int) -> [NSManagedObject]? { - return self.bridgeToSwift.objectsInSection(safeSectionIndex: section) + return self.bridgeToSwift.objects(safelyIn: section) } /** @@ -201,7 +201,7 @@ public final class CSListMonitor: NSObject { @objc public func numberOfObjectsInSection(_ section: Int) -> Int { - return self.bridgeToSwift.numberOfObjectsInSection(section) + return self.bridgeToSwift.numberOfObjects(in: section) } /** @@ -214,7 +214,7 @@ public final class CSListMonitor: NSObject { public func numberOfObjectsInSafeSection(safeSectionIndex section: Int) -> NSNumber? { return self.bridgeToSwift - .numberOfObjectsInSection(safeSectionIndex: section) + .numberOfObjects(safelyIn: section) .flatMap { NSNumber(value: $0) } } @@ -227,7 +227,7 @@ public final class CSListMonitor: NSObject { @objc public func sectionInfoAtIndex(_ section: Int) -> NSFetchedResultsSectionInfo { - return self.bridgeToSwift.sectionInfoAtIndex(section) + return self.bridgeToSwift.sectionInfo(at: section) } /** @@ -239,7 +239,7 @@ public final class CSListMonitor: NSObject { @objc public func sectionInfoAtSafeSectionIndex(safeSectionIndex section: Int) -> NSFetchedResultsSectionInfo? { - return self.bridgeToSwift.sectionInfoAtIndex(safeSectionIndex: section) + return self.bridgeToSwift.sectionInfo(safelyAt: section) } /** @@ -263,7 +263,7 @@ public final class CSListMonitor: NSObject { @objc public func targetSectionForSectionIndexTitle(title: String, index: Int) -> Int { - return self.bridgeToSwift.targetSectionForSectionIndex(title: title, index: index) + return self.bridgeToSwift.targetSection(forSectionIndexTitle: title, at: index) } /** @@ -287,7 +287,7 @@ public final class CSListMonitor: NSObject { public func indexOf(_ object: NSManagedObject) -> NSNumber? { return self.bridgeToSwift - .indexOf(object) + .index(of: object) .flatMap { NSNumber(value: $0) } } @@ -300,7 +300,7 @@ public final class CSListMonitor: NSObject { @objc public func indexPathOf(_ object: NSManagedObject) -> IndexPath? { - return self.bridgeToSwift.indexPathOf(object) + return self.bridgeToSwift.indexPath(of: object) } diff --git a/Sources/CoreStore+Observing.swift b/Sources/CoreStore+Observing.swift index e594c26..ca11967 100644 --- a/Sources/CoreStore+Observing.swift +++ b/Sources/CoreStore+Observing.swift @@ -113,7 +113,7 @@ public extension CoreStore { ``` CoreStore.monitorList( - { (monitor) in + createAsynchronously: { (monitor) in self.monitor = monitor }, From() @@ -123,7 +123,6 @@ public extension CoreStore { ``` - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - - returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` */ public static func monitorList(createAsynchronously: @escaping (ListMonitor) -> Void, _ clauseChain: B) { @@ -212,7 +211,7 @@ public extension CoreStore { Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` built from a chain of clauses. ``` CoreStore.monitorSectionedList( - { (monitor) in + createAsynchronously: { (monitor) in self.monitor = monitor }, From() @@ -221,8 +220,8 @@ public extension CoreStore { .orderBy(.ascending(\.age)) ) ``` + - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter clauseChain: a `SectionMonitorBuilderType` built from a chain of clauses - - returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` */ public static func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ clauseChain: B) { diff --git a/Sources/CoreStore+Querying.swift b/Sources/CoreStore+Querying.swift index 66f9f7b..2976a28 100644 --- a/Sources/CoreStore+Querying.swift +++ b/Sources/CoreStore+Querying.swift @@ -82,9 +82,9 @@ public extension CoreStore { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s */ - public static func fetchOne(_ from: From, _ fetchClauses: FetchClause...) -> D? { + public static func fetchOne(_ from: From, _ fetchClauses: FetchClause...) throws -> D? { - return self.defaultStack.fetchOne(from, fetchClauses) + return try self.defaultStack.fetchOne(from, fetchClauses) } /** @@ -94,9 +94,9 @@ public extension CoreStore { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s */ - public static func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) -> D? { + public static func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) throws -> D? { - return self.defaultStack.fetchOne(from, fetchClauses) + return try self.defaultStack.fetchOne(from, fetchClauses) } /** @@ -111,9 +111,9 @@ public extension CoreStore { - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - returns: the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType` */ - public static func fetchOne(_ clauseChain: B) -> B.ObjectType? { + public static func fetchOne(_ clauseChain: B) throws -> B.ObjectType? { - return self.defaultStack.fetchOne(clauseChain) + return try self.defaultStack.fetchOne(clauseChain) } /** @@ -123,9 +123,9 @@ public extension CoreStore { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s */ - public static func fetchAll(_ from: From, _ fetchClauses: FetchClause...) -> [D]? { + public static func fetchAll(_ from: From, _ fetchClauses: FetchClause...) throws -> [D] { - return self.defaultStack.fetchAll(from, fetchClauses) + return try self.defaultStack.fetchAll(from, fetchClauses) } /** @@ -135,9 +135,9 @@ public extension CoreStore { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s */ - public static func fetchAll(_ from: From, _ fetchClauses: [FetchClause]) -> [D]? { + public static func fetchAll(_ from: From, _ fetchClauses: [FetchClause]) throws -> [D] { - return self.defaultStack.fetchAll(from, fetchClauses) + return try self.defaultStack.fetchAll(from, fetchClauses) } /** @@ -152,9 +152,9 @@ public extension CoreStore { - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - returns: all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType` */ - public static func fetchAll(_ clauseChain: B) -> [B.ObjectType]? { + public static func fetchAll(_ clauseChain: B) throws -> [B.ObjectType] { - return self.defaultStack.fetchAll(clauseChain) + return try self.defaultStack.fetchAll(clauseChain) } /** @@ -164,9 +164,9 @@ public extension CoreStore { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s */ - public static func fetchCount(_ from: From, _ fetchClauses: FetchClause...) -> Int? { + public static func fetchCount(_ from: From, _ fetchClauses: FetchClause...) throws -> Int { - return self.defaultStack.fetchCount(from, fetchClauses) + return try self.defaultStack.fetchCount(from, fetchClauses) } /** @@ -176,9 +176,9 @@ public extension CoreStore { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s */ - public static func fetchCount(_ from: From, _ fetchClauses: [FetchClause]) -> Int? { + public static func fetchCount(_ from: From, _ fetchClauses: [FetchClause]) throws -> Int { - return self.defaultStack.fetchCount(from, fetchClauses) + return try self.defaultStack.fetchCount(from, fetchClauses) } /** @@ -193,9 +193,9 @@ public extension CoreStore { - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - returns: the number `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` */ - public static func fetchCount(_ clauseChain: B) -> Int? { + public static func fetchCount(_ clauseChain: B) throws -> Int { - return self.defaultStack.fetchCount(clauseChain) + return try self.defaultStack.fetchCount(clauseChain) } /** diff --git a/Sources/CoreStoreError.swift b/Sources/CoreStoreError.swift index 9dec792..67e09f9 100644 --- a/Sources/CoreStoreError.swift +++ b/Sources/CoreStoreError.swift @@ -73,6 +73,11 @@ public enum CoreStoreError: Error, CustomNSError, Hashable { The transaction was cancelled by the user. */ case userCancelled + + /** + Attempted to perform a fetch but could not find any related persistent store. + */ + case persistentStoreNotFound(entity: DynamicObject.Type) // MARK: CustomNSError @@ -109,6 +114,9 @@ public enum CoreStoreError: Error, CustomNSError, Hashable { case .userCancelled: return CoreStoreErrorCode.userCancelled.rawValue + + case .persistentStoreNotFound: + return CoreStoreErrorCode.persistentStoreNotFound.rawValue } } @@ -154,6 +162,11 @@ public enum CoreStoreError: Error, CustomNSError, Hashable { case .userCancelled: return [:] + + case .persistentStoreNotFound(let entity): + return [ + "entity": entity + ] } } @@ -195,6 +208,9 @@ public enum CoreStoreError: Error, CustomNSError, Hashable { case (.userCancelled, .userCancelled): return true + + case (.persistentStoreNotFound(let entity1), .persistentStoreNotFound(let entity2)): + return entity1 == entity2 default: return false @@ -233,6 +249,9 @@ public enum CoreStoreError: Error, CustomNSError, Hashable { case .userError(let error): hasher.combine(error as NSError) + case .persistentStoreNotFound(let entity): + hasher.combine(ObjectIdentifier(entity)) + case .userCancelled: break } @@ -303,6 +322,11 @@ public enum CoreStoreErrorCode: Int { The transaction was cancelled by the user. */ case userCancelled + + /** + Attempted to perform a fetch but could not find any related persistent store. + */ + case persistentStoreNotFound } diff --git a/Sources/CoreStoreFetchedResultsController.swift b/Sources/CoreStoreFetchedResultsController.swift index f8e6280..5cad260 100644 --- a/Sources/CoreStoreFetchedResultsController.swift +++ b/Sources/CoreStoreFetchedResultsController.swift @@ -58,7 +58,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll self.reapplyAffectedStores = { fetchRequest, context in - return from.applyAffectedStoresForFetchedRequest(fetchRequest, context: context) + return try rom.applyAffectedStoresForFetchedRequest(fetchRequest, context: context) } super.init( @@ -71,14 +71,8 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll @nonobjc internal func performFetchFromSpecifiedStores() throws { - - if !self.reapplyAffectedStores(self.fetchRequest, self.managedObjectContext) { - - CoreStore.log( - .warning, - message: "Attempted to perform a fetch on an \(cs_typeName(self)) but could not find any persistent store for the entity \(cs_typeName(self.fetchRequest.entityName))" - ) - } + + try self.reapplyAffectedStores(self.fetchRequest, self.managedObjectContext) try self.performFetch() } @@ -97,5 +91,5 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll // MARK: Private @nonobjc - private let reapplyAffectedStores: (_ fetchRequest: NSFetchRequest, _ context: NSManagedObjectContext) -> Bool + private let reapplyAffectedStores: (_ fetchRequest: NSFetchRequest, _ context: NSManagedObjectContext) throws -> Bool } diff --git a/Sources/DataStack+Observing.swift b/Sources/DataStack+Observing.swift index 0e469ba..0bffe76 100644 --- a/Sources/DataStack+Observing.swift +++ b/Sources/DataStack+Observing.swift @@ -152,7 +152,7 @@ public extension DataStack { ``` dataStack.monitorList( - { (monitor) in + createAsynchronously: { (monitor) in self.monitor = monitor }, From() @@ -162,7 +162,6 @@ public extension DataStack { ``` - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - - returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` */ public func monitorList(createAsynchronously: @escaping (ListMonitor) -> Void, _ clauseChain: B) { @@ -288,7 +287,7 @@ public extension DataStack { Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` built from a chain of clauses. ``` dataStack.monitorSectionedList( - { (monitor) in + createAsynchronously: { (monitor) in self.monitor = monitor }, From() @@ -297,8 +296,8 @@ public extension DataStack { .orderBy(.ascending(\.age)) ) ``` + - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter clauseChain: a `SectionMonitorBuilderType` built from a chain of clauses - - returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` */ public func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ clauseChain: B) { diff --git a/Sources/DataStack+Querying.swift b/Sources/DataStack+Querying.swift index ba1374c..1d07566 100644 --- a/Sources/DataStack+Querying.swift +++ b/Sources/DataStack+Querying.swift @@ -84,13 +84,13 @@ extension DataStack: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s */ - public func fetchOne(_ from: From, _ fetchClauses: FetchClause...) -> D? { + public func fetchOne(_ from: From, _ fetchClauses: FetchClause...) throws -> D? { CoreStore.assert( Thread.isMainThread, "Attempted to fetch from a \(cs_typeName(self)) outside the main thread." ) - return self.mainContext.fetchOne(from, fetchClauses) + return try self.mainContext.fetchOne(from, fetchClauses) } /** @@ -100,13 +100,13 @@ extension DataStack: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s */ - public func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) -> D? { + public func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) throws -> D? { CoreStore.assert( Thread.isMainThread, "Attempted to fetch from a \(cs_typeName(self)) outside the main thread." ) - return self.mainContext.fetchOne(from, fetchClauses) + return try self.mainContext.fetchOne(from, fetchClauses) } /** @@ -121,13 +121,13 @@ extension DataStack: FetchableSource, QueryableSource { - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - returns: the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType` */ - public func fetchOne(_ clauseChain: B) -> B.ObjectType? { + public func fetchOne(_ clauseChain: B) throws -> B.ObjectType? { CoreStore.assert( Thread.isMainThread, "Attempted to fetch from a \(cs_typeName(self)) outside the main thread." ) - return self.mainContext.fetchOne(clauseChain) + return try self.mainContext.fetchOne(clauseChain) } /** @@ -137,13 +137,13 @@ extension DataStack: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s */ - public func fetchAll(_ from: From, _ fetchClauses: FetchClause...) -> [D]? { + public func fetchAll(_ from: From, _ fetchClauses: FetchClause...) throws -> [D] { CoreStore.assert( Thread.isMainThread, "Attempted to fetch from a \(cs_typeName(self)) outside the main thread." ) - return self.mainContext.fetchAll(from, fetchClauses) + return try self.mainContext.fetchAll(from, fetchClauses) } /** @@ -153,13 +153,13 @@ extension DataStack: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s */ - public func fetchAll(_ from: From, _ fetchClauses: [FetchClause]) -> [D]? { + public func fetchAll(_ from: From, _ fetchClauses: [FetchClause]) throws -> [D] { CoreStore.assert( Thread.isMainThread, "Attempted to fetch from a \(cs_typeName(self)) outside the main thread." ) - return self.mainContext.fetchAll(from, fetchClauses) + return try self.mainContext.fetchAll(from, fetchClauses) } /** @@ -174,13 +174,13 @@ extension DataStack: FetchableSource, QueryableSource { - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - returns: all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType` */ - public func fetchAll(_ clauseChain: B) -> [B.ObjectType]? { + public func fetchAll(_ clauseChain: B) throws -> [B.ObjectType] { CoreStore.assert( Thread.isMainThread, "Attempted to fetch from a \(cs_typeName(self)) outside the main thread." ) - return self.mainContext.fetchAll(clauseChain) + return try self.mainContext.fetchAll(clauseChain) } /** @@ -190,13 +190,13 @@ extension DataStack: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s */ - public func fetchCount(_ from: From, _ fetchClauses: FetchClause...) -> Int? { + public func fetchCount(_ from: From, _ fetchClauses: FetchClause...) throws -> Int { CoreStore.assert( Thread.isMainThread, "Attempted to fetch from a \(cs_typeName(self)) outside the main thread." ) - return self.mainContext.fetchCount(from, fetchClauses) + return try self.mainContext.fetchCount(from, fetchClauses) } /** @@ -206,13 +206,13 @@ extension DataStack: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s */ - public func fetchCount(_ from: From, _ fetchClauses: [FetchClause]) -> Int? { + public func fetchCount(_ from: From, _ fetchClauses: [FetchClause]) throws -> Int { CoreStore.assert( Thread.isMainThread, "Attempted to fetch from a \(cs_typeName(self)) outside the main thread." ) - return self.mainContext.fetchCount(from, fetchClauses) + return try self.mainContext.fetchCount(from, fetchClauses) } /** @@ -227,13 +227,13 @@ extension DataStack: FetchableSource, QueryableSource { - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - returns: the number `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` */ - public func fetchCount(_ clauseChain: B) -> Int? { + public func fetchCount(_ clauseChain: B) throws -> Int { CoreStore.assert( Thread.isMainThread, "Attempted to fetch from a \(cs_typeName(self)) outside the main thread." ) - return self.mainContext.fetchCount(clauseChain) + return try self.mainContext.fetchCount(clauseChain) } /** diff --git a/Sources/FetchableSource.swift b/Sources/FetchableSource.swift index 31f1d50..38bc57d 100644 --- a/Sources/FetchableSource.swift +++ b/Sources/FetchableSource.swift @@ -73,7 +73,7 @@ public protocol FetchableSource: class { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s */ - func fetchOne(_ from: From, _ fetchClauses: FetchClause...) -> D? + func fetchOne(_ from: From, _ fetchClauses: FetchClause...) throws -> D? /** Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. @@ -82,7 +82,7 @@ public protocol FetchableSource: class { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s */ - func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) -> D? + func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) throws -> D? /** Fetches the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses. @@ -96,7 +96,7 @@ public protocol FetchableSource: class { - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - returns: the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType` */ - func fetchOne(_ clauseChain: B) -> B.ObjectType? + func fetchOne(_ clauseChain: B) throws -> B.ObjectType? /** Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. @@ -105,7 +105,7 @@ public protocol FetchableSource: class { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s */ - func fetchAll(_ from: From, _ fetchClauses: FetchClause...) -> [D]? + func fetchAll(_ from: From, _ fetchClauses: FetchClause...) throws -> [D] /** Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. @@ -114,7 +114,7 @@ public protocol FetchableSource: class { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s */ - func fetchAll(_ from: From, _ fetchClauses: [FetchClause]) -> [D]? + func fetchAll(_ from: From, _ fetchClauses: [FetchClause]) throws -> [D] /** Fetches all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses. @@ -128,7 +128,7 @@ public protocol FetchableSource: class { - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - returns: all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType` */ - func fetchAll(_ clauseChain: B) -> [B.ObjectType]? + func fetchAll(_ clauseChain: B) throws -> [B.ObjectType] /** Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. @@ -137,7 +137,7 @@ public protocol FetchableSource: class { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s */ - func fetchCount(_ from: From, _ fetchClauses: FetchClause...) -> Int? + func fetchCount(_ from: From, _ fetchClauses: FetchClause...) throws -> Int /** Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. @@ -146,7 +146,7 @@ public protocol FetchableSource: class { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s */ - func fetchCount(_ from: From, _ fetchClauses: [FetchClause]) -> Int? + func fetchCount(_ from: From, _ fetchClauses: [FetchClause]) throws -> Int /** Fetches the number of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses. @@ -160,7 +160,7 @@ public protocol FetchableSource: class { - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses - returns: the number `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` */ - func fetchCount(_ clauseChain: B) -> Int? + func fetchCount(_ clauseChain: B) throws -> Int /** Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. diff --git a/Sources/From.swift b/Sources/From.swift index 65de91d..13b2e9e 100644 --- a/Sources/From.swift +++ b/Sources/From.swift @@ -139,29 +139,40 @@ public struct From { self.findPersistentStores = findPersistentStores } - internal func applyToFetchRequest(_ fetchRequest: NSFetchRequest, context: NSManagedObjectContext, applyAffectedStores: Bool = true) -> Bool { + internal func applyToFetchRequest(_ fetchRequest: NSFetchRequest, context: NSManagedObjectContext, applyAffectedStores: Bool = true) throws { fetchRequest.entity = context.parentStack!.entityDescription(for: EntityIdentifier(self.entityClass))! guard applyAffectedStores else { - return true + return } - if self.applyAffectedStoresForFetchedRequest(fetchRequest, context: context) { - - return true + do { + + try self.applyAffectedStoresForFetchedRequest(fetchRequest, context: context) + } + catch let error as CoreStoreError { + + CoreStore.log( + error, + "Attempted to perform a fetch but could not find any persistent store for the entity \(cs_typeName(fetchRequest.entityName))" + ) + throw error + } + catch { + + throw error } - CoreStore.log( - .warning, - message: "Attempted to perform a fetch but could not find any persistent store for the entity \(cs_typeName(fetchRequest.entityName))" - ) - return false } - internal func applyAffectedStoresForFetchedRequest(_ fetchRequest: NSFetchRequest, context: NSManagedObjectContext) -> Bool { + internal func applyAffectedStoresForFetchedRequest(_ fetchRequest: NSFetchRequest, context: NSManagedObjectContext) throws { let stores = self.findPersistentStores(context) fetchRequest.affectedStores = stores - return stores?.isEmpty == false + if stores?.isEmpty == false { + + return + } + throw CoreStoreError.persistentStoreNotFound(entity: self.entityClass) } diff --git a/Sources/ListMonitor.swift b/Sources/ListMonitor.swift index b8da0b1..6d9c3d1 100644 --- a/Sources/ListMonitor.swift +++ b/Sources/ListMonitor.swift @@ -136,7 +136,7 @@ public final class ListMonitor: Hashable { */ public subscript(safeSectionIndex sectionIndex: Int, safeItemIndex itemIndex: Int) -> ObjectType? { - guard let section = self.sectionInfoAtIndex(safeSectionIndex: sectionIndex) else { + guard let section = self.sectionInfo(safelyAt: sectionIndex) else { return nil } @@ -202,9 +202,9 @@ public final class ListMonitor: Hashable { - parameter section: the section index. Using an index outside the valid range will return `false`. - returns: `true` if at least one object in the specified section exists, `false` otherwise */ - public func hasObjectsInSection(_ section: Int) -> Bool { + public func hasObjects(in section: Int) -> Bool { - return self.numberOfObjectsInSection(safeSectionIndex: section)! > 0 + return self.numberOfObjects(safelyIn: section)! > 0 } /** @@ -241,9 +241,9 @@ public final class ListMonitor: Hashable { - parameter section: the section index. Using an index outside the valid range will raise an exception. - returns: the number of objects in the specified section */ - public func numberOfObjectsInSection(_ section: Int) -> Int { + public func numberOfObjects(in section: Int) -> Int { - return self.sectionInfoAtIndex(section).numberOfObjects + return self.sectionInfo(at: section).numberOfObjects } /** @@ -252,9 +252,9 @@ public final class ListMonitor: Hashable { - parameter section: the section index. Using an index outside the valid range will return `nil`. - returns: the number of objects in the specified section */ - public func numberOfObjectsInSection(safeSectionIndex section: Int) -> Int? { + public func numberOfObjects(safelyIn section: Int) -> Int? { - return self.sectionInfoAtIndex(safeSectionIndex: section)?.numberOfObjects + return self.sectionInfo(safelyAt: section)?.numberOfObjects } /** @@ -263,7 +263,7 @@ public final class ListMonitor: Hashable { - parameter section: the section index. Using an index outside the valid range will raise an exception. - returns: the `NSFetchedResultsSectionInfo` for the specified section */ - public func sectionInfoAtIndex(_ section: Int) -> NSFetchedResultsSectionInfo { + public func sectionInfo(at section: Int) -> NSFetchedResultsSectionInfo { CoreStore.assert( !self.isPendingRefetch || Thread.isMainThread, @@ -278,7 +278,7 @@ public final class ListMonitor: Hashable { - parameter section: the section index. Using an index outside the valid range will return `nil`. - returns: the `NSFetchedResultsSectionInfo` for the specified section, or `nil` if the section index is out of bounds. */ - public func sectionInfoAtIndex(safeSectionIndex section: Int) -> NSFetchedResultsSectionInfo? { + public func sectionInfo(safelyAt section: Int) -> NSFetchedResultsSectionInfo? { CoreStore.assert( !self.isPendingRefetch || Thread.isMainThread, @@ -312,17 +312,17 @@ public final class ListMonitor: Hashable { /** Returns the target section for a specified "Section Index" title and index. - - parameter title: the title of the Section Index - - parameter index: the index of the Section Index + - parameter sectionIndexTitle: the title of the Section Index + - parameter sectionIndex: the index of the Section Index - returns: the target section for the specified "Section Index" title and index. */ - public func targetSectionForSectionIndex(title: String, index: Int) -> Int { + public func targetSection(forSectionIndexTitle sectionIndexTitle: String, at sectionIndex: Int) -> Int { CoreStore.assert( !self.isPendingRefetch || Thread.isMainThread, "Attempted to access a \(cs_typeName(self)) outside the main thread while a refetch is in progress." ) - return self.fetchedResultsController.section(forSectionIndexTitle: title, at: index) + return self.fetchedResultsController.section(forSectionIndexTitle: sectionIndexTitle, at: sectionIndex) } /** @@ -345,7 +345,7 @@ public final class ListMonitor: Hashable { - parameter object: the `DynamicObject` to search the index of - returns: the index of the `DynamicObject` if it exists in the `ListMonitor`'s fetched objects, or `nil` if not found. */ - public func indexOf(_ object: ObjectType) -> Int? { + public func index(of object: ObjectType) -> Int? { CoreStore.assert( !self.isPendingRefetch || Thread.isMainThread, @@ -364,7 +364,7 @@ public final class ListMonitor: Hashable { - parameter object: the `DynamicObject` to search the index of - returns: the `IndexPath` of the `DynamicObject` if it exists in the `ListMonitor`'s fetched objects, or `nil` if not found. */ - public func indexPathOf(_ object: ObjectType) -> IndexPath? { + public func indexPath(of object: ObjectType) -> IndexPath? { CoreStore.assert( !self.isPendingRefetch || Thread.isMainThread, @@ -1164,6 +1164,57 @@ public final class ListMonitor: Hashable { try! self.fetchedResultsController.performFetchFromSpecifiedStores() } } + + + // MARK: Deprecated + + @available(*, deprecated, renamed: "hasObjects(in:)") + public func hasObjectsInSection(_ section: Int) -> Bool { + + return self.hasObjects(in: section) + } + + @available(*, deprecated, renamed: "numberOfObjects(in:)") + public func numberOfObjectsInSection(_ section: Int) -> Int { + + return self.numberOfObjects(in: section) + } + + @available(*, deprecated, renamed: "numberOfObjects(safelyIn:)") + public func numberOfObjectsInSection(safeSectionIndex section: Int) -> Int? { + + return self.numberOfObjects(safelyIn: section) + } + + @available(*, deprecated, renamed: "sectionInfo(at:)") + public func sectionInfoAtIndex(_ section: Int) -> NSFetchedResultsSectionInfo { + + return self.sectionInfo(at: section) + } + + @available(*, deprecated, renamed: "sectionInfo(safelyAt:)") + public func sectionInfoAtIndex(safeSectionIndex section: Int) -> NSFetchedResultsSectionInfo? { + + return self.sectionInfo(safelyAt: section) + } + + @available(*, deprecated, renamed: "targetSection(forSectionIndexTitle:at:)") + public func targetSectionForSectionIndex(title: String, index: Int) -> Int { + + return self.targetSection(forSectionIndexTitle: title, at: index) + } + + @available(*, deprecated, renamed: "index(of:)") + public func indexOf(_ object: ObjectType) -> Int? { + + return self.index(of: object) + } + + @available(*, deprecated, renamed: "indexPath(of:)") + public func indexPathOf(_ object: ObjectType) -> IndexPath? { + + return self.indexPath(of: object) + } } @@ -1192,9 +1243,9 @@ extension ListMonitor where ListMonitor.ObjectType: NSManagedObject { - parameter section: the section index. Using an index outside the valid range will raise an exception. - returns: all objects in the specified section */ - public func objectsInSection(_ section: Int) -> [ObjectType] { + public func objects(in section: Int) -> [ObjectType] { - return (self.sectionInfoAtIndex(section).objects as! [ObjectType]?) ?? [] + return (self.sectionInfo(at: section).objects as! [ObjectType]?) ?? [] } /** @@ -1203,9 +1254,24 @@ extension ListMonitor where ListMonitor.ObjectType: NSManagedObject { - parameter section: the section index. Using an index outside the valid range will return `nil`. - returns: all objects in the specified section */ - public func objectsInSection(safeSectionIndex section: Int) -> [ObjectType]? { + public func objects(safelyIn section: Int) -> [ObjectType]? { - return self.sectionInfoAtIndex(safeSectionIndex: section)?.objects as! [ObjectType]? + return self.sectionInfo(safelyAt: section)?.objects as! [ObjectType]? + } + + + // MARK: Deprecated + + @available(*, deprecated, renamed: "objects(in:)") + public func objectsInSection(_ section: Int) -> [ObjectType] { + + return self.objects(in: section) + } + + @available(*, deprecated, renamed: "objects(safelyIn:)") + public func objectsInSection(safeSectionIndex section: Int) -> [ObjectType]? { + + return self.objects(safelyIn: section) } } @@ -1236,9 +1302,9 @@ extension ListMonitor where ListMonitor.ObjectType: CoreStoreObject { - parameter section: the section index. Using an index outside the valid range will raise an exception. - returns: all objects in the specified section */ - public func objectsInSection(_ section: Int) -> [ObjectType] { + public func objects(in section: Int) -> [ObjectType] { - return (self.sectionInfoAtIndex(section).objects ?? []) + return (self.sectionInfo(at: section).objects ?? []) .map({ ObjectType.cs_fromRaw(object: $0 as! NSManagedObject) }) } @@ -1248,11 +1314,26 @@ extension ListMonitor where ListMonitor.ObjectType: CoreStoreObject { - parameter section: the section index. Using an index outside the valid range will return `nil`. - returns: all objects in the specified section */ - public func objectsInSection(safeSectionIndex section: Int) -> [ObjectType]? { + public func objects(safelyIn section: Int) -> [ObjectType]? { - return (self.sectionInfoAtIndex(safeSectionIndex: section)?.objects)? + return (self.sectionInfo(safelyAt: section)?.objects)? .map({ ObjectType.cs_fromRaw(object: $0 as! NSManagedObject) }) } + + + // MARK: Deprecated + + @available(*, deprecated, renamed: "objects(in:)") + public func objectsInSection(_ section: Int) -> [ObjectType] { + + return self.objects(in: section) + } + + @available(*, deprecated, renamed: "objects(safelyIn:)") + public func objectsInSection(safeSectionIndex section: Int) -> [ObjectType]? { + + return self.objects(safelyIn: section) + } } diff --git a/Sources/NSManagedObjectContext+ObjectiveC.swift b/Sources/NSManagedObjectContext+ObjectiveC.swift index 4b1b259..a2482b6 100644 --- a/Sources/NSManagedObjectContext+ObjectiveC.swift +++ b/Sources/NSManagedObjectContext+ObjectiveC.swift @@ -34,85 +34,65 @@ internal extension NSManagedObjectContext { // MARK: Internal @nonobjc - internal func fetchOne(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) -> NSManagedObject? { + internal func fetchOne(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) throws -> NSManagedObject? { let fetchRequest = CoreStoreFetchRequest() - let storeFound = from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self) + try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self) fetchRequest.fetchLimit = 1 fetchRequest.resultType = .managedObjectResultType fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } - - guard storeFound else { - - return nil - } - return self.fetchOne(fetchRequest.dynamicCast()) + + return try self.fetchOne(fetchRequest.dynamicCast()) } @nonobjc - internal func fetchAll(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) -> [T]? { + internal func fetchAll(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) throws -> [T] { let fetchRequest = CoreStoreFetchRequest() - let storeFound = from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self) + try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self) fetchRequest.fetchLimit = 0 fetchRequest.resultType = .managedObjectResultType fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } - - guard storeFound else { - - return nil - } - return self.fetchAll(fetchRequest.dynamicCast()) + + return try self.fetchAll(fetchRequest.dynamicCast()) } @nonobjc - internal func fetchCount(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) -> Int? { + internal func fetchCount(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) throws -> Int { let fetchRequest = CoreStoreFetchRequest() - let storeFound = from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self) + try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self) fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } - - guard storeFound else { - - return nil - } - return self.fetchCount(fetchRequest.dynamicCast()) + + return try self.fetchCount(fetchRequest.dynamicCast()) } @nonobjc - internal func fetchObjectID(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) -> NSManagedObjectID? { + internal func fetchObjectID(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) throws -> NSManagedObjectID? { let fetchRequest = CoreStoreFetchRequest() - let storeFound = from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self) + try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self) fetchRequest.fetchLimit = 1 fetchRequest.resultType = .managedObjectIDResultType fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } - - guard storeFound else { - - return nil - } - return self.fetchObjectID(fetchRequest.dynamicCast()) + + return try self.fetchObjectID(fetchRequest.dynamicCast()) } @nonobjc - internal func fetchObjectIDs(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) -> [NSManagedObjectID]? { + internal func fetchObjectIDs(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) throws -> [NSManagedObjectID] { let fetchRequest = CoreStoreFetchRequest() - let storeFound = from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self) + try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self) fetchRequest.fetchLimit = 0 fetchRequest.resultType = .managedObjectIDResultType fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } - - guard storeFound else { - - return nil - } - return self.fetchObjectIDs(fetchRequest.dynamicCast()) + + return try self.fetchObjectIDs(fetchRequest.dynamicCast()) } @nonobjc diff --git a/Sources/NSManagedObjectContext+Querying.swift b/Sources/NSManagedObjectContext+Querying.swift index 6625833..57b747e 100644 --- a/Sources/NSManagedObjectContext+Querying.swift +++ b/Sources/NSManagedObjectContext+Querying.swift @@ -101,88 +101,76 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource { } @nonobjc - public func fetchOne(_ from: From, _ fetchClauses: FetchClause...) -> D? { + public func fetchOne(_ from: From, _ fetchClauses: FetchClause...) throws -> D? { - return self.fetchOne(from, fetchClauses) + return try self.fetchOne(from, fetchClauses) } @nonobjc - public func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) -> D? { + public func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) throws -> D? { let fetchRequest = CoreStoreFetchRequest() - let storeFound = from.applyToFetchRequest(fetchRequest, context: self) + try from.applyToFetchRequest(fetchRequest, context: self) fetchRequest.fetchLimit = 1 fetchRequest.resultType = .managedObjectResultType fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } - - guard storeFound else { - - return nil - } - return self.fetchOne(fetchRequest.dynamicCast()).flatMap(from.entityClass.cs_fromRaw) + + return try self.fetchOne(fetchRequest.dynamicCast()).flatMap(from.entityClass.cs_fromRaw) } @nonobjc - public func fetchOne(_ clauseChain: B) -> B.ObjectType? { + public func fetchOne(_ clauseChain: B) throws -> B.ObjectType? { - return self.fetchOne(clauseChain.from, clauseChain.fetchClauses) + return try self.fetchOne(clauseChain.from, clauseChain.fetchClauses) } @nonobjc - public func fetchAll(_ from: From, _ fetchClauses: FetchClause...) -> [D]? { + public func fetchAll(_ from: From, _ fetchClauses: FetchClause...) throws -> [D] { - return self.fetchAll(from, fetchClauses) + return try self.fetchAll(from, fetchClauses) } @nonobjc - public func fetchAll(_ from: From, _ fetchClauses: [FetchClause]) -> [D]? { + public func fetchAll(_ from: From, _ fetchClauses: [FetchClause]) throws -> [D] { let fetchRequest = CoreStoreFetchRequest() - let storeFound = from.applyToFetchRequest(fetchRequest, context: self) + try from.applyToFetchRequest(fetchRequest, context: self) fetchRequest.fetchLimit = 0 fetchRequest.resultType = .managedObjectResultType fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } - - guard storeFound else { - - return nil - } + let entityClass = from.entityClass - return self.fetchAll(fetchRequest.dynamicCast())?.map(entityClass.cs_fromRaw) + return try self.fetchAll(fetchRequest.dynamicCast())?.map(entityClass.cs_fromRaw) } @nonobjc - public func fetchAll(_ clauseChain: B) -> [B.ObjectType]? { + public func fetchAll(_ clauseChain: B) throw -> [B.ObjectType] { - return self.fetchAll(clauseChain.from, clauseChain.fetchClauses) + return try self.fetchAll(clauseChain.from, clauseChain.fetchClauses) } @nonobjc - public func fetchCount(_ from: From, _ fetchClauses: FetchClause...) -> Int? { + public func fetchCount(_ from: From, _ fetchClauses: FetchClause...) throws -> Int { - return self.fetchCount(from, fetchClauses) + return try self.fetchCount(from, fetchClauses) } @nonobjc - public func fetchCount(_ from: From, _ fetchClauses: [FetchClause]) -> Int? { + public func fetchCount(_ from: From, _ fetchClauses: [FetchClause]) throws -> Int { let fetchRequest = CoreStoreFetchRequest() - let storeFound = from.applyToFetchRequest(fetchRequest, context: self) + try from.applyToFetchRequest(fetchRequest, context: self) fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } - - guard storeFound else { - - return nil - } - return self.fetchCount(fetchRequest.dynamicCast()) + + return try self.fetchCount(fetchRequest.dynamicCast()) } @nonobjc - public func fetchCount(_ clauseChain: B) -> Int? { + public func fetchCount(_ clauseChain: B) throws -> Int { - return self.fetchCount(clauseChain.from, clauseChain.fetchClauses) + return try self.fetchCount(clauseChain.from, clauseChain.fetchClauses) } @nonobjc @@ -207,8 +195,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource { } return self.fetchObjectID(fetchRequest.dynamicCast()) } - - // TODO: docs + @nonobjc public func fetchObjectID(_ clauseChain: B) -> NSManagedObjectID? { @@ -225,7 +212,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource { public func fetchObjectIDs(_ from: From, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? { let fetchRequest = CoreStoreFetchRequest() - let storeFound = from.applyToFetchRequest(fetchRequest, context: self) + try from.applyToFetchRequest(fetchRequest, context: self) fetchRequest.fetchLimit = 0 fetchRequest.resultType = .managedObjectIDResultType @@ -237,8 +224,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource { } return self.fetchObjectIDs(fetchRequest.dynamicCast()) } - - // TODO: docs + @nonobjc public func fetchObjectIDs(_ clauseChain: B) -> [NSManagedObjectID]? { @@ -383,7 +369,7 @@ internal extension NSManagedObjectContext { // MARK: Fetching @nonobjc - internal func fetchOne(_ fetchRequest: NSFetchRequest) -> D? { + internal func fetchOne(_ fetchRequest: NSFetchRequest) throws -> D? { var fetchResults: [D]? var fetchError: Error? @@ -399,18 +385,19 @@ internal extension NSManagedObjectContext { } } if fetchResults == nil { - + + let coreStoreError = CoreStoreError(fetchError) CoreStore.log( - CoreStoreError(fetchError), + coreStoreError, "Failed executing fetch request." ) - return nil + throw coreStoreError } return fetchResults?.first } @nonobjc - internal func fetchAll(_ fetchRequest: NSFetchRequest) -> [D]? { + internal func fetchAll(_ fetchRequest: NSFetchRequest) throws -> [D] { var fetchResults: [D]? var fetchError: Error? @@ -426,18 +413,19 @@ internal extension NSManagedObjectContext { } } if fetchResults == nil { - + + let coreStoreError = CoreStoreError(fetchError) CoreStore.log( - CoreStoreError(fetchError), + coreStoreError, "Failed executing fetch request." ) - return nil + throw coreStoreError } return fetchResults } @nonobjc - internal func fetchCount(_ fetchRequest: NSFetchRequest) -> Int? { + internal func fetchCount(_ fetchRequest: NSFetchRequest) throws -> Int { var count = 0 var countError: Error? @@ -453,12 +441,13 @@ internal extension NSManagedObjectContext { } } if count == NSNotFound { - + + let coreStoreError = CoreStoreError(fetchError) CoreStore.log( - CoreStoreError(countError), + coreStoreError, "Failed executing count request." ) - return nil + throw coreStoreError } return count } diff --git a/Sources/UnsafeDataTransaction+Observing.swift b/Sources/UnsafeDataTransaction+Observing.swift index 7287ed6..3ca12ac 100644 --- a/Sources/UnsafeDataTransaction+Observing.swift +++ b/Sources/UnsafeDataTransaction+Observing.swift @@ -142,8 +142,23 @@ public extension UnsafeDataTransaction { createAsynchronously: createAsynchronously ) } - - // TODO: docs + + /** + Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. + + ``` + dataStack.monitorList( + createAsynchronously: { (monitor) in + self.monitor = monitor + }, + From() + .where(\.age > 18) + .orderBy(.ascending(\.age)) + ) + ``` + - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance + - parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses + */ public func monitorList(createAsynchronously: @escaping (ListMonitor) -> Void, _ clauseChain: B) { self.monitorList( @@ -267,8 +282,8 @@ public extension UnsafeDataTransaction { .orderBy(.ascending(\.age)) ) ``` + - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter clauseChain: a `SectionMonitorBuilderType` built from a chain of clauses - - returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` */ public func monitorSectionedList(createAsynchronously: @escaping (ListMonitor) -> Void, _ clauseChain: B) { diff --git a/Sources/Where.swift b/Sources/Where.swift index ae98cc5..5e2da49 100644 --- a/Sources/Where.swift +++ b/Sources/Where.swift @@ -541,7 +541,7 @@ public extension Sequence where Iterator.Element: WhereClauseType { public extension Where { - @available(*, deprecated: 4.0, renamed: "&&?") + @available(*, deprecated, renamed: "&&?") public static func && (left: Where, right: Where?) -> Where { if let right = right { @@ -551,7 +551,7 @@ public extension Where { return left } - @available(*, deprecated: 4.0, renamed: "&&?") + @available(*, deprecated, renamed: "&&?") public static func && (left: Where?, right: Where) -> Where { if let left = left { @@ -561,7 +561,7 @@ public extension Where { return right } - @available(*, deprecated: 4.0, renamed: "||?") + @available(*, deprecated, renamed: "||?") public static func || (left: Where, right: Where?) -> Where { if let right = right { @@ -571,7 +571,7 @@ public extension Where { return left } - @available(*, deprecated: 4.0, renamed: "||?") + @available(*, deprecated, renamed: "||?") public static func || (left: Where?, right: Where) -> Where { if let left = left {