FetchableSource and QueryableSource protocols

This commit is contained in:
John Estropia
2016-11-15 18:00:39 +09:00
parent 33a5c123aa
commit b230ed6400
21 changed files with 967 additions and 566 deletions

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "CoreStore"
s.version = "2.1.1"
s.version = "3.0.0"
s.license = "MIT"
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
s.homepage = "https://github.com/JohnEstropia/CoreStore"

View File

@@ -365,6 +365,14 @@
B596BBB21DD5A014001DCDD9 /* ConvenienceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596BBAD1DD59FDB001DCDD9 /* ConvenienceTests.swift */; };
B596BBB31DD5A014001DCDD9 /* ConvenienceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596BBAD1DD59FDB001DCDD9 /* ConvenienceTests.swift */; };
B596BBB41DD5A016001DCDD9 /* ConvenienceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596BBAD1DD59FDB001DCDD9 /* ConvenienceTests.swift */; };
B596BBB61DD5BC67001DCDD9 /* FetchableSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596BBB51DD5BC67001DCDD9 /* FetchableSource.swift */; };
B596BBB71DD5BC67001DCDD9 /* FetchableSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596BBB51DD5BC67001DCDD9 /* FetchableSource.swift */; };
B596BBB81DD5BC67001DCDD9 /* FetchableSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596BBB51DD5BC67001DCDD9 /* FetchableSource.swift */; };
B596BBB91DD5BC67001DCDD9 /* FetchableSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596BBB51DD5BC67001DCDD9 /* FetchableSource.swift */; };
B596BBBB1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596BBBA1DD5C39F001DCDD9 /* QueryableSource.swift */; };
B596BBBC1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596BBBA1DD5C39F001DCDD9 /* QueryableSource.swift */; };
B596BBBD1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596BBBA1DD5C39F001DCDD9 /* QueryableSource.swift */; };
B596BBBE1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596BBBA1DD5C39F001DCDD9 /* QueryableSource.swift */; };
B59851491C90289D00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59AFF401C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift */; };
B598514A1C90289E00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59AFF401C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift */; };
B598514B1C90289F00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59AFF401C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift */; };
@@ -652,6 +660,8 @@
B57D27C11D0BC20100539C58 /* QueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryTests.swift; sourceTree = "<group>"; };
B58085741CDF7F00004C2EEB /* SetupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetupTests.swift; sourceTree = "<group>"; };
B596BBAD1DD59FDB001DCDD9 /* ConvenienceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvenienceTests.swift; sourceTree = "<group>"; };
B596BBB51DD5BC67001DCDD9 /* FetchableSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchableSource.swift; sourceTree = "<group>"; };
B596BBBA1DD5C39F001DCDD9 /* QueryableSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryableSource.swift; sourceTree = "<group>"; };
B59AFF401C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSPersistentStoreCoordinator+Setup.swift"; sourceTree = "<group>"; };
B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ICloudStore.swift; sourceTree = "<group>"; };
B5A261201B64BFDB006EB6D3 /* MigrationType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationType.swift; sourceTree = "<group>"; };
@@ -1130,6 +1140,8 @@
B5E84EFE1AFF847B0064E85B /* BaseDataTransaction+Querying.swift */,
B5E84F061AFF847B0064E85B /* DataStack+Querying.swift */,
B5E84F071AFF847B0064E85B /* CoreStore+Querying.swift */,
B596BBB51DD5BC67001DCDD9 /* FetchableSource.swift */,
B596BBBA1DD5C39F001DCDD9 /* QueryableSource.swift */,
B5E84F0A1AFF847B0064E85B /* Protocol Clauses */,
B5E84EFF1AFF847B0064E85B /* Concrete Clauses */,
);
@@ -1535,6 +1547,7 @@
B5D1E22C19FA9FBC003B2874 /* CoreStoreError.swift in Sources */,
B5E84F131AFF847B0064E85B /* Where.swift in Sources */,
B5D3F6451C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */,
B596BBBB1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */,
B5ECDBFF1CA80CBA00C7F112 /* CSWhere.swift in Sources */,
B5ECDC051CA8138100C7F112 /* CSOrderBy.swift in Sources */,
B5E1B5981CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
@@ -1589,6 +1602,7 @@
B5FAD6AC1B51285300714891 /* MigrationManager.swift in Sources */,
B5E84EF61AFF846E0064E85B /* DataStack+Transaction.swift in Sources */,
B5FEC18E1C9166E200532541 /* NSPersistentStore+Setup.swift in Sources */,
B596BBB61DD5BC67001DCDD9 /* FetchableSource.swift in Sources */,
B5E1B5A21CAA4365007FD580 /* CSCoreStore+Observing.swift in Sources */,
B5E84EDF1AFF84500064E85B /* DataStack.swift in Sources */,
B59AFF411C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
@@ -1685,6 +1699,7 @@
82BA18AE1C4BBD3100A0916E /* DataStack+Transaction.swift in Sources */,
82BA18AB1C4BBD3100A0916E /* AsynchronousDataTransaction.swift in Sources */,
82BA18CE1C4BBD7100A0916E /* FetchedResultsControllerDelegate.swift in Sources */,
B596BBBC1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */,
B5ECDC011CA80CBA00C7F112 /* CSWhere.swift in Sources */,
B5ECDC071CA8138100C7F112 /* CSOrderBy.swift in Sources */,
B5E1B59A1CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
@@ -1739,6 +1754,7 @@
82BA18C61C4BBD5900A0916E /* DataStack+Migration.swift in Sources */,
B59851491C90289D00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
B5E1B5A41CAA4365007FD580 /* CSCoreStore+Observing.swift in Sources */,
B596BBB71DD5BC67001DCDD9 /* FetchableSource.swift in Sources */,
B5FEC18F1C9166E600532541 /* NSPersistentStore+Setup.swift in Sources */,
82BA18B71C4BBD3F00A0916E /* CoreStore+Querying.swift in Sources */,
82BA18AA1C4BBD3100A0916E /* BaseDataTransaction.swift in Sources */,
@@ -1835,6 +1851,7 @@
B53FBA161CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift in Sources */,
B5ECDC271CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */,
B52DD1951BE1F92500949AFE /* CoreStoreError.swift in Sources */,
B596BBBE1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */,
B546F9601C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */,
B5ECDC0F1CA8161B00C7F112 /* CSGroupBy.swift in Sources */,
B5ECDC211CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */,
@@ -1889,6 +1906,7 @@
B5519A621CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
B52DD19C1BE1F92C00949AFE /* Into.swift in Sources */,
B5FE4DA51C8481E100FA6A91 /* StorageInterface.swift in Sources */,
B596BBB91DD5BC67001DCDD9 /* FetchableSource.swift in Sources */,
B529C2081CA4A2DC007E7EBD /* CSSaveResult.swift in Sources */,
B5FE4DAA1C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
B52DD1AF1BE1F93900949AFE /* GroupBy.swift in Sources */,
@@ -1985,6 +2003,7 @@
B563219D1BD65216006C9394 /* DataStack+Observing.swift in Sources */,
B56321961BD65216006C9394 /* From.swift in Sources */,
B5ECDC021CA80CBA00C7F112 /* CSWhere.swift in Sources */,
B596BBBD1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */,
B5ECDC081CA8138100C7F112 /* CSOrderBy.swift in Sources */,
B5E1B59B1CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
B5519A611CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
@@ -2039,6 +2058,7 @@
B5FEC1901C9166E700532541 /* NSPersistentStore+Setup.swift in Sources */,
B56321A11BD65216006C9394 /* ListMonitor.swift in Sources */,
B5E1B5A51CAA4365007FD580 /* CSCoreStore+Observing.swift in Sources */,
B596BBB81DD5BC67001DCDD9 /* FetchableSource.swift in Sources */,
B56321881BD65216006C9394 /* BaseDataTransaction.swift in Sources */,
B56321A31BD65216006C9394 /* DataStack+Migration.swift in Sources */,
B56321901BD65216006C9394 /* ImportableUniqueObject.swift in Sources */,

View File

@@ -42,7 +42,11 @@ class SetupTests: BaseTestCase {
XCTAssertEqual(stack.coordinator.managedObjectModel, model)
XCTAssertEqual(stack.rootSavingContext.persistentStoreCoordinator, stack.coordinator)
XCTAssertNil(stack.rootSavingContext.parent)
XCTAssertFalse(stack.rootSavingContext.isDataStackContext)
XCTAssertFalse(stack.rootSavingContext.isTransactionContext)
XCTAssertEqual(stack.mainContext.parent, stack.rootSavingContext)
XCTAssertTrue(stack.mainContext.isDataStackContext)
XCTAssertFalse(stack.mainContext.isTransactionContext)
XCTAssertEqual(stack.model, model)
XCTAssertTrue(stack.migrationChain.valid)
XCTAssertTrue(stack.migrationChain.empty)

View File

@@ -44,12 +44,20 @@ final class TransactionTests: BaseTestCase {
let createExpectation = self.expectation(description: "create")
stack.beginSynchronous { (transaction) in
XCTAssertEqual(transaction.context, transaction.internalContext())
XCTAssertTrue(transaction.context.isTransactionContext)
XCTAssertFalse(transaction.context.isDataStackContext)
let object = transaction.create(Into<TestEntity1>())
XCTAssertEqual(object.fetchSource()?.internalContext(), transaction.context)
XCTAssertEqual(object.querySource()?.internalContext(), transaction.context)
object.testEntityID = NSNumber(value: 1)
object.testString = "string1"
object.testNumber = 100
object.testDate = testDate
switch transaction.commitAndWait() {
case .success(let hasChanges):
@@ -66,6 +74,9 @@ final class TransactionTests: BaseTestCase {
let object = stack.fetchOne(From<TestEntity1>())
XCTAssertNotNil(object)
XCTAssertEqual(object?.fetchSource()?.internalContext(), stack.mainContext)
XCTAssertEqual(object?.querySource()?.internalContext(), stack.mainContext)
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
XCTAssertEqual(object?.testString, "string1")
XCTAssertEqual(object?.testNumber, 100)
@@ -355,7 +366,14 @@ final class TransactionTests: BaseTestCase {
let createExpectation = self.expectation(description: "create")
stack.beginAsynchronous { (transaction) in
XCTAssertEqual(transaction.context, transaction.internalContext())
XCTAssertTrue(transaction.context.isTransactionContext)
XCTAssertFalse(transaction.context.isDataStackContext)
let object = transaction.create(Into<TestEntity1>())
XCTAssertEqual(object.fetchSource()?.internalContext(), transaction.context)
XCTAssertEqual(object.querySource()?.internalContext(), transaction.context)
object.testEntityID = NSNumber(value: 1)
object.testString = "string1"
object.testNumber = 100
@@ -372,6 +390,9 @@ final class TransactionTests: BaseTestCase {
let object = stack.fetchOne(From<TestEntity1>())
XCTAssertNotNil(object)
XCTAssertEqual(object?.fetchSource()?.internalContext(), stack.mainContext)
XCTAssertEqual(object?.querySource()?.internalContext(), stack.mainContext)
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
XCTAssertEqual(object?.testString, "string1")
XCTAssertEqual(object?.testNumber, 100)
@@ -675,11 +696,17 @@ final class TransactionTests: BaseTestCase {
self.prepareStack { (stack) in
let transaction = stack.beginUnsafe()
XCTAssertEqual(transaction.context, transaction.internalContext())
XCTAssertTrue(transaction.context.isTransactionContext)
XCTAssertFalse(transaction.context.isDataStackContext)
let testDate = Date()
do {
let object = transaction.create(Into<TestEntity1>())
XCTAssertEqual(object.fetchSource()?.internalContext(), transaction.context)
XCTAssertEqual(object.querySource()?.internalContext(), transaction.context)
object.testEntityID = NSNumber(value: 1)
object.testString = "string1"
object.testNumber = 100
@@ -693,6 +720,9 @@ final class TransactionTests: BaseTestCase {
let object = stack.fetchOne(From<TestEntity1>())
XCTAssertNotNil(object)
XCTAssertEqual(object?.fetchSource()?.internalContext(), stack.mainContext)
XCTAssertEqual(object?.querySource()?.internalContext(), stack.mainContext)
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
XCTAssertEqual(object?.testString, "string1")
XCTAssertEqual(object?.testNumber, 100)

View File

@@ -34,6 +34,7 @@ public extension DataStack {
/**
Utility for creating an `NSFetchedResultsController` from the `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- parameter from: a `From` clause indicating the entity type
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections
@@ -53,6 +54,7 @@ public extension DataStack {
/**
Utility for creating an `NSFetchedResultsController` from a `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- parameter from: a `From` clause indicating the entity type
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections
@@ -72,6 +74,7 @@ public extension DataStack {
/**
Utility for creating an `NSFetchedResultsController` from the `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -90,6 +93,7 @@ public extension DataStack {
/**
Utility for creating an `NSFetchedResultsController` from the `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -114,6 +118,7 @@ public extension UnsafeDataTransaction {
/**
Utility for creating an `NSFetchedResultsController` from the `UnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- parameter from: a `From` clause indicating the entity type
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections
@@ -133,6 +138,7 @@ public extension UnsafeDataTransaction {
/**
Utility for creating an `NSFetchedResultsController` from the `UnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- parameter from: a `From` clause indicating the entity type
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections
@@ -152,6 +158,7 @@ public extension UnsafeDataTransaction {
/**
Utility for creating an `NSFetchedResultsController` from the `UnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -170,6 +177,7 @@ public extension UnsafeDataTransaction {
/**
Utility for creating an `NSFetchedResultsController` from the `UnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.

View File

@@ -31,6 +31,52 @@ import CoreData
public extension NSManagedObject {
/**
Exposes a `FetchableSource` that can fetch sibling objects of this `NSManagedObject` instance. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the obejct's parent is already deallocated.
- Warning: Future implementations may change the instance returned by this method depending on the timing or condition that `fetchSource()` was called. Do not make assumptions that the instance will be a specific instance. If the `NSManagedObjectContext` instance is desired, use the `FetchableSource.internalContext()` method to get the correct instance. Also, do not assume that the `fetchSource()` and `querySource()` return the same instance all the time.
- returns: a `FetchableSource` that can fetch sibling objects of this `NSManagedObject` instance. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the object's parent is already deallocated.
*/
@nonobjc
public func fetchSource() -> FetchableSource? {
guard let context = self.managedObjectContext else {
return nil
}
if context.isTransactionContext {
return context.parentTransaction
}
if context.isDataStackContext {
return context.parentStack
}
return context
}
/**
Exposes a `QueryableSource` that can query attributes and aggregate values. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the obejct's parent is already deallocated.
- Warning: Future implementations may change the instance returned by this method depending on the timing or condition that `querySource()` was called. Do not make assumptions that the instance will be a specific instance. If the `NSManagedObjectContext` instance is desired, use the `QueryableSource.internalContext()` method to get the correct instance. Also, do not assume that the `fetchSource()` and `querySource()` return the same instance all the time.
- returns: a `QueryableSource` that can query attributes and aggregate values. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the object's parent is already deallocated.
*/
@nonobjc
public func querySource() -> QueryableSource? {
guard let context = self.managedObjectContext else {
return nil
}
if context.isTransactionContext {
return context.parentTransaction
}
if context.isDataStackContext {
return context.parentStack
}
return context
}
/**
Provides a convenience wrapper for accessing `primitiveValueForKey(...)` with proper calls to `willAccessValueForKey(...)` and `didAccessValueForKey(...)`. This is useful when implementing accessor methods for transient attributes.

View File

@@ -29,206 +29,7 @@ import CoreData
// MARK: - DataTransaction
public extension BaseDataTransaction {
/**
Fetches the `NSManagedObject` instance in the transaction's context from a reference created from a transaction or from a different managed object context.
- parameter object: a reference to the object created/fetched outside the transaction
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found.
*/
public func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
do {
return (try self.context.existingObject(with: object.objectID) as! T)
}
catch _ {
return nil
}
}
/**
Fetches the `NSManagedObject` instance in the transaction's context from an `NSManagedObjectID`.
- parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found.
*/
public func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
do {
return (try self.context.existingObject(with: objectID) as! T)
}
catch _ {
return nil
}
}
/**
Fetches the `NSManagedObject` instances in the transaction's context from references created from a transaction or from a different managed object context.
- parameter objects: an array of `NSManagedObject`s created/fetched outside the transaction
- returns: the `NSManagedObject` array for objects that exists in the transaction
*/
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
return objects.flatMap { (try? self.context.existingObject(with: $0.objectID)) as? T }
}
/**
Fetches the `NSManagedObject` instances in the transaction's context from a list of `NSManagedObjectID`.
- parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the transaction
*/
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
return objectIDs.flatMap { (try? self.context.existingObject(with: $0)) as? T }
}
/**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
return self.fetchOne(from, fetchClauses)
}
/**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchOne(from, fetchClauses)
}
/**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
return self.fetchAll(from, fetchClauses)
}
/**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchAll(from, fetchClauses)
}
/**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
return self.fetchCount(from, fetchClauses)
}
/**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchCount(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
return self.fetchObjectID(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchObjectID(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
return self.fetchObjectIDs(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchObjectIDs(from, fetchClauses)
}
extension BaseDataTransaction: FetchableSource, QueryableSource {
/**
Deletes all `NSManagedObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -266,6 +67,216 @@ public extension BaseDataTransaction {
return self.context.deleteAll(from, deleteClauses)
}
// MARK: FetchableSource
/**
Fetches the `NSManagedObject` instance in the transaction's context from a reference created from a transaction or from a different managed object context.
- parameter object: a reference to the object created/fetched outside the transaction
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found.
*/
public func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
return self.context.fetchExisting(object)
}
/**
Fetches the `NSManagedObject` instance in the transaction's context from an `NSManagedObjectID`.
- parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found.
*/
public func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
return self.context.fetchExisting(objectID)
}
/**
Fetches the `NSManagedObject` instances in the transaction's context from references created from a transaction or from a different managed object context.
- parameter objects: an array of `NSManagedObject`s created/fetched outside the transaction
- returns: the `NSManagedObject` array for objects that exists in the transaction
*/
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
return self.context.fetchExisting(objects)
}
/**
Fetches the `NSManagedObject` instances in the transaction's context from a list of `NSManagedObjectID`.
- parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the transaction
*/
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
return self.context.fetchExisting(objectIDs)
}
/**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchOne(from, fetchClauses)
}
/**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchOne(from, fetchClauses)
}
/**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchAll(from, fetchClauses)
}
/**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchAll(from, fetchClauses)
}
/**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchCount(from, fetchClauses)
}
/**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchCount(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchObjectID(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchObjectID(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchObjectIDs(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchObjectIDs(from, fetchClauses)
}
// MARK: QueryableSource
/**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -282,7 +293,6 @@ public extension BaseDataTransaction {
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.queryValue(from, selectClause, queryClauses)
}
@@ -302,7 +312,6 @@ public extension BaseDataTransaction {
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.queryValue(from, selectClause, queryClauses)
}
@@ -322,7 +331,6 @@ public extension BaseDataTransaction {
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.queryAttributes(from, selectClause, queryClauses)
}
@@ -342,7 +350,17 @@ public extension BaseDataTransaction {
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.queryAttributes(from, selectClause, queryClauses)
}
// MARK: FetchableSource, QueryableSource
/**
The internal `NSManagedObjectContext` managed by this instance. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
*/
public func internalContext() -> NSManagedObjectContext {
return self.context
}
}

View File

@@ -29,7 +29,9 @@ import CoreData
// MARK: - DataStack
public extension DataStack {
extension DataStack: FetchableSource, QueryableSource {
// MARK: FetchableSource
/**
Fetches the `NSManagedObject` instance in the `DataStack`'s context from a reference created from a transaction or from a different managed object context.
@@ -39,14 +41,7 @@ public extension DataStack {
*/
public func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
do {
return (try self.mainContext.existingObject(with: object.objectID) as! T)
}
catch _ {
return nil
}
return self.mainContext.fetchExisting(object)
}
/**
@@ -57,14 +52,7 @@ public extension DataStack {
*/
public func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
do {
return (try self.mainContext.existingObject(with: objectID) as! T)
}
catch _ {
return nil
}
return self.mainContext.fetchExisting(objectID)
}
/**
@@ -75,7 +63,7 @@ public extension DataStack {
*/
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
return objects.flatMap { (try? self.mainContext.existingObject(with: $0.objectID)) as? T }
return self.mainContext.fetchExisting(objects)
}
/**
@@ -86,7 +74,7 @@ public extension DataStack {
*/
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
return objectIDs.flatMap { (try? self.mainContext.existingObject(with: $0)) as? T }
return self.mainContext.fetchExisting(objectIDs)
}
/**
@@ -249,6 +237,9 @@ public extension DataStack {
return self.mainContext.fetchObjectIDs(from, fetchClauses)
}
// MARK: QueryableSource
/**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -324,4 +315,15 @@ public extension DataStack {
)
return self.mainContext.queryAttributes(from, selectClause, queryClauses)
}
// MARK: FetchableSource, QueryableSource
/**
The internal `NSManagedObjectContext` managed by this instance. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
*/
public func internalContext() -> NSManagedObjectContext {
return self.mainContext
}
}

View File

@@ -0,0 +1,163 @@
//
// FetchableSource.swift
// CoreStore
//
// Copyright © 2016 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: - FetchableSource
/**
Encapsulates containers which manages an internal `NSManagedObjectContext`, such as `DataStack`s and transactions, that can be used for fetching objects. CoreStore provides implementations for this protocol and should be used as a read-only abstraction.
*/
public protocol FetchableSource: class {
/**
Fetches the `NSManagedObject` instance in the `FetchableSource`'s context from a reference created from another managed object context.
- parameter object: a reference to the object created/fetched outside the `FetchableSource`'s context
- returns: the `NSManagedObject` instance if the object exists in the `FetchableSource`'s context, or `nil` if not found.
*/
func fetchExisting<T: NSManagedObject>(_ object: T) -> T?
/**
Fetches the `NSManagedObject` instance in the `FetchableSource`'s context from an `NSManagedObjectID`.
- parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the `FetchableSource`, or `nil` if not found.
*/
func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T?
/**
Fetches the `NSManagedObject` instances in the `FetchableSource`'s context from references created from another managed object context.
- parameter objects: an array of `NSManagedObject`s created/fetched outside the `FetchableSource`'s context
- returns: the `NSManagedObject` array for objects that exists in the `FetchableSource`
*/
func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T
/**
Fetches the `NSManagedObject` instances in the `FetchableSource`'s context from a list of `NSManagedObjectID`.
- parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the `FetchableSource`'s context
*/
func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID
/**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T?
/**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T?
/**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]?
/**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]?
/**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int?
/**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int?
/**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID?
/**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID?
/**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]?
/**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]?
/**
The internal `NSManagedObjectContext` managed by this `FetchableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
*/
func internalContext() -> NSManagedObjectContext
}

View File

@@ -0,0 +1,89 @@
//
// QueryableSource.swift
// CoreStore
//
// Copyright © 2016 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: - QueryableSource
/**
Encapsulates containers which manages an internal `NSManagedObjectContext`, such as `DataStack`s and transactions, that can be used for querying values. CoreStore provides implementations for this protocol and should be used as a read-only abstraction.
*/
public protocol QueryableSource: class {
/**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
- parameter from: a `From` clause indicating the entity type
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U?
/**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
- parameter from: a `From` clause indicating the entity type
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U?
/**
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
- parameter from: a `From` clause indicating the entity type
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]?
/**
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
- parameter from: a `From` clause indicating the entity type
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]?
/**
The internal `NSManagedObjectContext` managed by this `QueryableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
*/
func internalContext() -> NSManagedObjectContext
}

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.2.0</string>
<string>3.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>

View File

@@ -29,12 +29,12 @@ import CoreData
// MARK: - NSManagedObjectContext
internal extension NSManagedObjectContext {
extension NSManagedObjectContext: FetchableSource, QueryableSource {
// MARK: Internal: Fetch Existing
// MARK: FetchableSource
@nonobjc
internal func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
public func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
if object.objectID.isTemporaryID {
@@ -69,17 +69,40 @@ internal extension NSManagedObjectContext {
}
}
// MARK: Internal: Fetch One
@nonobjc
public func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
do {
return (try self.existingObject(with: objectID) as! T)
}
catch _ {
return nil
}
}
@nonobjc
internal func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
return objects.flatMap { (try? self.existingObject(with: $0.objectID)) as? T }
}
@nonobjc
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
return objectIDs.flatMap { (try? self.existingObject(with: $0)) as? T }
}
@nonobjc
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
return self.fetchOne(from, fetchClauses)
}
@nonobjc
internal func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -96,43 +119,13 @@ internal extension NSManagedObjectContext {
}
@nonobjc
internal func fetchOne<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> T? {
var fetchResults: [T]?
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.fetch(fetchRequest)
}
catch {
fetchError = error
}
}
if fetchResults == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return fetchResults?.first
}
// MARK: Internal: Fetch All
@nonobjc
internal func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
return self.fetchAll(from, fetchClauses)
}
@nonobjc
internal func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -149,43 +142,13 @@ internal extension NSManagedObjectContext {
}
@nonobjc
internal func fetchAll<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> [T]? {
var fetchResults: [T]?
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.fetch(fetchRequest)
}
catch {
fetchError = error
}
}
if fetchResults == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return fetchResults
}
// MARK: Internal: Count
@nonobjc
internal func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
return self.fetchCount(from, fetchClauses)
}
@nonobjc
internal func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -199,43 +162,13 @@ internal extension NSManagedObjectContext {
}
@nonobjc
internal func fetchCount(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Int? {
var count = 0
var countError: Error?
self.performAndWait {
do {
count = try self.count(for: fetchRequest)
}
catch {
countError = error
}
}
if count == NSNotFound {
CoreStore.log(
CoreStoreError(countError),
"Failed executing count request."
)
return nil
}
return count
}
// MARK: Internal: Object ID
@nonobjc
internal func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
return self.fetchObjectID(from, fetchClauses)
}
@nonobjc
internal func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -252,43 +185,13 @@ internal extension NSManagedObjectContext {
}
@nonobjc
internal func fetchObjectID(_ fetchRequest: NSFetchRequest<NSManagedObjectID>) -> NSManagedObjectID? {
var fetchResults: [NSManagedObjectID]?
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.fetch(fetchRequest)
}
catch {
fetchError = error
}
}
if fetchResults == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return fetchResults?.first
}
// MARK: Internal: Object IDs
@nonobjc
internal func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
return self.fetchObjectIDs(from, fetchClauses)
}
@nonobjc
internal func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -332,79 +235,16 @@ internal extension NSManagedObjectContext {
}
// MARK: Internal: Delete All
// MARK: QueryableSource
@nonobjc
internal func deleteAll<T: NSManagedObject>(_ from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
return self.deleteAll(from, deleteClauses)
}
@nonobjc
internal func deleteAll<T: NSManagedObject>(_ from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .managedObjectResultType
fetchRequest.returnsObjectsAsFaults = true
fetchRequest.includesPropertyValues = false
deleteClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.deleteAll(fetchRequest.dynamicCast())
}
@nonobjc
internal func deleteAll<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> Int? {
var numberOfDeletedObjects: Int?
var fetchError: Error?
self.performAndWait {
autoreleasepool {
do {
let fetchResults = try self.fetch(fetchRequest)
for object in fetchResults {
self.delete(object)
}
numberOfDeletedObjects = fetchResults.count
}
catch {
fetchError = error
}
}
}
if numberOfDeletedObjects == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return numberOfDeletedObjects
}
// MARK: Internal: Value
@nonobjc
internal func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
return self.queryValue(from, selectClause, queryClauses)
}
@nonobjc
internal func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -422,6 +262,158 @@ internal extension NSManagedObjectContext {
return self.queryValue(selectTerms, fetchRequest: fetchRequest)
}
@nonobjc
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
return self.queryAttributes(from, selectClause, queryClauses)
}
@nonobjc
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
selectClause.selectTerms.applyToFetchRequest(fetchRequest, owner: selectClause)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.queryAttributes(fetchRequest)
}
// MARK: FetchableSource, QueryableSource
@nonobjc
public func internalContext() -> NSManagedObjectContext {
return self
}
}
// MARK: - NSManagedObjectContext (Internal)
internal extension NSManagedObjectContext {
// MARK: Fetching
@nonobjc
internal func fetchOne<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> T? {
var fetchResults: [T]?
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.fetch(fetchRequest)
}
catch {
fetchError = error
}
}
if fetchResults == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return fetchResults?.first
}
@nonobjc
internal func fetchAll<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> [T]? {
var fetchResults: [T]?
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.fetch(fetchRequest)
}
catch {
fetchError = error
}
}
if fetchResults == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return fetchResults
}
@nonobjc
internal func fetchCount(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Int? {
var count = 0
var countError: Error?
self.performAndWait {
do {
count = try self.count(for: fetchRequest)
}
catch {
countError = error
}
}
if count == NSNotFound {
CoreStore.log(
CoreStoreError(countError),
"Failed executing count request."
)
return nil
}
return count
}
@nonobjc
internal func fetchObjectID(_ fetchRequest: NSFetchRequest<NSManagedObjectID>) -> NSManagedObjectID? {
var fetchResults: [NSManagedObjectID]?
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.fetch(fetchRequest)
}
catch {
fetchError = error
}
}
if fetchResults == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return fetchResults?.first
}
// MARK: Querying
@nonobjc
internal func queryValue<U: SelectValueResultType>(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> U? {
@@ -488,33 +480,6 @@ internal extension NSManagedObjectContext {
return nil
}
// MARK: Internal: Attributes
@nonobjc
internal func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
return self.queryAttributes(from, selectClause, queryClauses)
}
@nonobjc
internal func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
selectClause.selectTerms.applyToFetchRequest(fetchRequest, owner: selectClause)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.queryAttributes(fetchRequest)
}
@nonobjc
internal func queryAttributes(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> [[String: Any]]? {
@@ -542,4 +507,67 @@ internal extension NSManagedObjectContext {
)
return nil
}
// MARK: Deleting
@nonobjc
internal func deleteAll<T: NSManagedObject>(_ from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
return self.deleteAll(from, deleteClauses)
}
@nonobjc
internal func deleteAll<T: NSManagedObject>(_ from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .managedObjectResultType
fetchRequest.returnsObjectsAsFaults = true
fetchRequest.includesPropertyValues = false
deleteClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.deleteAll(fetchRequest.dynamicCast())
}
@nonobjc
internal func deleteAll<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> Int? {
var numberOfDeletedObjects: Int?
var fetchError: Error?
self.performAndWait {
autoreleasepool {
do {
let fetchResults = try self.fetch(fetchRequest)
for object in fetchResults {
self.delete(object)
}
numberOfDeletedObjects = fetchResults.count
}
catch {
fetchError = error
}
}
}
if numberOfDeletedObjects == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return numberOfDeletedObjects
}
}

View File

@@ -74,6 +74,48 @@ internal extension NSManagedObjectContext {
}
}
@nonobjc
internal var isTransactionContext: Bool {
get {
let value: NSNumber? = cs_getAssociatedObjectForKey(
&PropertyKeys.isTransactionContext,
inObject: self
)
return value?.boolValue == true
}
set {
cs_setAssociatedCopiedObject(
NSNumber(value: newValue),
forKey: &PropertyKeys.isTransactionContext,
inObject: self
)
}
}
@nonobjc
internal var isDataStackContext: Bool {
get {
let value: NSNumber? = cs_getAssociatedObjectForKey(
&PropertyKeys.isDataStackContext,
inObject: self
)
return value?.boolValue == true
}
set {
cs_setAssociatedCopiedObject(
NSNumber(value: newValue),
forKey: &PropertyKeys.isDataStackContext,
inObject: self
)
}
}
@nonobjc
internal func isRunningInAllowedQueue() -> Bool {
@@ -214,5 +256,7 @@ internal extension NSManagedObjectContext {
static var parentTransaction: Void?
static var isSavingSynchronously: Void?
static var isTransactionContext: Void?
static var isDataStackContext: Void?
}
}

View File

@@ -40,14 +40,7 @@ public extension CSBaseDataTransaction {
@objc
public func fetchExistingObject(_ object: NSManagedObject) -> Any? {
do {
return try self.bridgeToSwift.context.existingObject(with: object.objectID)
}
catch _ {
return nil
}
return self.bridgeToSwift.context.fetchExisting(object)
}
/**
@@ -59,14 +52,7 @@ public extension CSBaseDataTransaction {
@objc
public func fetchExistingObjectWithID(_ objectID: NSManagedObjectID) -> Any? {
do {
return try self.bridgeToSwift.context.existingObject(with: objectID)
}
catch _ {
return nil
}
return self.bridgeToSwift.context.fetchExisting(objectID)
}
/**
@@ -78,7 +64,7 @@ public extension CSBaseDataTransaction {
@objc
public func fetchExistingObjects(_ objects: [NSManagedObject]) -> [Any] {
return objects.flatMap { try? self.bridgeToSwift.context.existingObject(with: $0.objectID) }
return self.bridgeToSwift.context.fetchExisting(objects)
}
/**
@@ -90,7 +76,7 @@ public extension CSBaseDataTransaction {
@objc
public func fetchExistingObjectsWithIDs(_ objectIDs: [NSManagedObjectID]) -> [Any] {
return objectIDs.flatMap { try? self.bridgeToSwift.context.existingObject(with: $0) }
return self.bridgeToSwift.context.fetchExisting(objectIDs)
}
/**

View File

@@ -40,14 +40,7 @@ public extension CSDataStack {
@objc
public func fetchExistingObject(_ object: NSManagedObject) -> Any? {
do {
return try self.bridgeToSwift.mainContext.existingObject(with: object.objectID)
}
catch _ {
return nil
}
return self.bridgeToSwift.mainContext.fetchExisting(object)
}
/**
@@ -59,14 +52,7 @@ public extension CSDataStack {
@objc
public func fetchExistingObjectWithID(_ objectID: NSManagedObjectID) -> Any? {
do {
return try self.bridgeToSwift.mainContext.existingObject(with: objectID)
}
catch _ {
return nil
}
return self.bridgeToSwift.mainContext.fetchExisting(objectID)
}
/**
@@ -78,7 +64,7 @@ public extension CSDataStack {
@objc
public func fetchExistingObjects(_ objects: [NSManagedObject]) -> [Any] {
return objects.flatMap { try? self.bridgeToSwift.mainContext.existingObject(with: $0.objectID) }
return self.bridgeToSwift.mainContext.fetchExisting(objects)
}
/**
@@ -90,7 +76,7 @@ public extension CSDataStack {
@objc
public func fetchExistingObjectsWithIDs(_ objectIDs: [NSManagedObjectID]) -> [Any] {
return objectIDs.flatMap { try? self.bridgeToSwift.mainContext.existingObject(with: $0) }
return self.bridgeToSwift.mainContext.fetchExisting(objectIDs)
}
/**

View File

@@ -35,6 +35,7 @@ public extension CSDataStack {
/**
Utility for creating an `NSFetchedResultsController` from the `CSDataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `CSListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `-performFetch:` on the created `NSFetchedResultsController`.
- parameter from: a `CSFrom` clause indicating the entity type
- parameter sectionBy: a `CSSectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
@@ -60,6 +61,7 @@ public extension CSUnsafeDataTransaction {
/**
Utility for creating an `NSFetchedResultsController` from the `CSUnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `CSListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `-performFetch:` on the created `NSFetchedResultsController`.
- parameter from: a `CSFrom` clause indicating the entity type
- parameter sectionBy: a `CSSectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections

View File

@@ -49,28 +49,33 @@ public protocol ListObserver: class {
associatedtype ListEntityType: NSManagedObject
/**
Handles processing just before a change to the observed list occurs
Handles processing just before a change to the observed list occurs. (Optional)
The default implementation does nothing.
- parameter monitor: the `ListMonitor` monitoring the list being observed
*/
func listMonitorWillChange(_ monitor: ListMonitor<ListEntityType>)
/**
Handles processing right after a change to the observed list occurs
Handles processing right after a change to the observed list occurs. (Optional)
The default implementation does nothing.
- parameter monitor: the `ListMonitor` monitoring the object being observed
*/
func listMonitorDidChange(_ monitor: ListMonitor<ListEntityType>)
/**
This method is broadcast from within the `ListMonitor`'s `refetch(...)` method to let observers prepare for the internal `NSFetchedResultsController`'s pending change to its predicate, sort descriptors, etc. Note that the actual refetch will happen after the `NSFetchedResultsController`'s last `controllerDidChangeContent(_:)` notification completes.
This method is broadcast from within the `ListMonitor`'s `refetch(...)` method to let observers prepare for the internal `NSFetchedResultsController`'s pending change to its predicate, sort descriptors, etc. (Optional)
The default implementation does nothing.
- Note: The actual refetch will happen after the `NSFetchedResultsController`'s last `controllerDidChangeContent(_:)` notification completes
- parameter monitor: the `ListMonitor` monitoring the object being observed
*/
func listMonitorWillRefetch(_ monitor: ListMonitor<ListEntityType>)
/**
After the `ListMonitor`'s `refetch(...)` method is called, this method is broadcast after the `NSFetchedResultsController`'s last `controllerDidChangeContent(_:)` notification completes.
After the `ListMonitor`'s `refetch(...)` method is called, this method is broadcast after the `NSFetchedResultsController`'s last `controllerDidChangeContent(_:)` notification completes. (Optional)
The default implementation does nothing.
- parameter monitor: the `ListMonitor` monitoring the object being observed
*/
@@ -82,25 +87,13 @@ public protocol ListObserver: class {
public extension ListObserver {
/**
The default implementation does nothing.
*/
func listMonitorWillChange(_ monitor: ListMonitor<ListEntityType>) { }
public func listMonitorWillChange(_ monitor: ListMonitor<ListEntityType>) { }
/**
The default implementation does nothing.
*/
func listMonitorDidChange(_ monitor: ListMonitor<ListEntityType>) { }
public func listMonitorDidChange(_ monitor: ListMonitor<ListEntityType>) { }
/**
The default implementation does nothing.
*/
func listMonitorWillRefetch(_ monitor: ListMonitor<ListEntityType>) { }
public func listMonitorWillRefetch(_ monitor: ListMonitor<ListEntityType>) { }
/**
The default implementation does nothing.
*/
func listMonitorDidRefetch(_ monitor: ListMonitor<ListEntityType>) { }
public func listMonitorDidRefetch(_ monitor: ListMonitor<ListEntityType>) { }
}
@@ -119,7 +112,8 @@ public extension ListObserver {
public protocol ListObjectObserver: ListObserver {
/**
Notifies that an object was inserted to the specified `NSIndexPath` in the list
Notifies that an object was inserted to the specified `NSIndexPath` in the list. (Optional)
The default implementation does nothing.
- parameter monitor: the `ListMonitor` monitoring the list being observed
- parameter object: the entity type for the inserted object
@@ -128,7 +122,8 @@ public protocol ListObjectObserver: ListObserver {
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didInsertObject object: ListEntityType, toIndexPath indexPath: IndexPath)
/**
Notifies that an object was deleted from the specified `NSIndexPath` in the list
Notifies that an object was deleted from the specified `NSIndexPath` in the list. (Optional)
The default implementation does nothing.
- parameter monitor: the `ListMonitor` monitoring the list being observed
- parameter object: the entity type for the deleted object
@@ -137,7 +132,8 @@ public protocol ListObjectObserver: ListObserver {
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didDeleteObject object: ListEntityType, fromIndexPath indexPath: IndexPath)
/**
Notifies that an object at the specified `NSIndexPath` was updated
Notifies that an object at the specified `NSIndexPath` was updated. (Optional)
The default implementation does nothing.
- parameter monitor: the `ListMonitor` monitoring the list being observed
- parameter object: the entity type for the updated object
@@ -146,7 +142,8 @@ public protocol ListObjectObserver: ListObserver {
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didUpdateObject object: ListEntityType, atIndexPath indexPath: IndexPath)
/**
Notifies that an object's index changed
Notifies that an object's index changed. (Optional)
The default implementation does nothing.
- parameter monitor: the `ListMonitor` monitoring the list being observed
- parameter object: the entity type for the moved object
@@ -161,25 +158,13 @@ public protocol ListObjectObserver: ListObserver {
public extension ListObjectObserver {
/**
The default implementation does nothing.
*/
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didInsertObject object: ListEntityType, toIndexPath indexPath: IndexPath) { }
public func listMonitor(_ monitor: ListMonitor<ListEntityType>, didInsertObject object: ListEntityType, toIndexPath indexPath: IndexPath) { }
/**
The default implementation does nothing.
*/
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didDeleteObject object: ListEntityType, fromIndexPath indexPath: IndexPath) { }
public func listMonitor(_ monitor: ListMonitor<ListEntityType>, didDeleteObject object: ListEntityType, fromIndexPath indexPath: IndexPath) { }
/**
The default implementation does nothing.
*/
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didUpdateObject object: ListEntityType, atIndexPath indexPath: IndexPath) { }
public func listMonitor(_ monitor: ListMonitor<ListEntityType>, didUpdateObject object: ListEntityType, atIndexPath indexPath: IndexPath) { }
/**
The default implementation does nothing.
*/
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didMoveObject object: ListEntityType, fromIndexPath: IndexPath, toIndexPath: IndexPath) { }
public func listMonitor(_ monitor: ListMonitor<ListEntityType>, didMoveObject object: ListEntityType, fromIndexPath: IndexPath, toIndexPath: IndexPath) { }
}
@@ -199,7 +184,8 @@ public extension ListObjectObserver {
public protocol ListSectionObserver: ListObjectObserver {
/**
Notifies that a section was inserted at the specified index
Notifies that a section was inserted at the specified index. (Optional)
The default implementation does nothing.
- parameter monitor: the `ListMonitor` monitoring the list being observed
- parameter sectionInfo: the `NSFetchedResultsSectionInfo` for the inserted section
@@ -208,7 +194,8 @@ public protocol ListSectionObserver: ListObjectObserver {
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int)
/**
Notifies that a section was inserted at the specified index
Notifies that a section was inserted at the specified index. (Optional)
The default implementation does nothing.
- parameter monitor: the `ListMonitor` monitoring the list being observed
- parameter sectionInfo: the `NSFetchedResultsSectionInfo` for the deleted section
@@ -222,15 +209,9 @@ public protocol ListSectionObserver: ListObjectObserver {
public extension ListSectionObserver {
/**
The default implementation does nothing.
*/
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) { }
public func listMonitor(_ monitor: ListMonitor<ListEntityType>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) { }
/**
The default implementation does nothing.
*/
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) { }
public func listMonitor(_ monitor: ListMonitor<ListEntityType>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) { }
}
#endif

View File

@@ -46,7 +46,8 @@ public protocol ObjectObserver: class {
associatedtype ObjectEntityType: NSManagedObject
/**
Handles processing just before a change to the observed `object` occurs
Handles processing just before a change to the observed `object` occurs. (Optional)
The default implementation does nothing.
- parameter monitor: the `ObjectMonitor` monitoring the object being observed
- parameter object: the `NSManagedObject` instance being observed
@@ -54,7 +55,8 @@ public protocol ObjectObserver: class {
func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, willUpdateObject object: ObjectEntityType)
/**
Handles processing right after a change to the observed `object` occurs
Handles processing right after a change to the observed `object` occurs. (Optional)
The default implementation does nothing.
- parameter monitor: the `ObjectMonitor` monitoring the object being observed
- parameter object: the `NSManagedObject` instance being observed
@@ -63,7 +65,8 @@ public protocol ObjectObserver: class {
func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didUpdateObject object: ObjectEntityType, changedPersistentKeys: Set<KeyPath>)
/**
Handles processing right after `object` is deleted
Handles processing right after `object` is deleted. (Optional)
The default implementation does nothing.
- parameter monitor: the `ObjectMonitor` monitoring the object being observed
- parameter object: the `NSManagedObject` instance being observed
@@ -76,20 +79,11 @@ public protocol ObjectObserver: class {
public extension ObjectObserver {
/**
The default implementation does nothing.
*/
func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, willUpdateObject object: ObjectEntityType) { }
public func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, willUpdateObject object: ObjectEntityType) { }
/**
The default implementation does nothing.
*/
func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didUpdateObject object: ObjectEntityType, changedPersistentKeys: Set<KeyPath>) { }
public func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didUpdateObject object: ObjectEntityType, changedPersistentKeys: Set<KeyPath>) { }
/**
The default implementation does nothing.
*/
func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didDeleteObject object: ObjectEntityType) { }
public func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didDeleteObject object: ObjectEntityType) { }
}
#endif

View File

@@ -71,6 +71,8 @@ public final class DataStack {
self.migrationChain = migrationChain
self.rootSavingContext.parentStack = self
self.mainContext.isDataStackContext = true
}
/**

View File

@@ -470,6 +470,7 @@ public /*abstract*/ class BaseDataTransaction {
self.bypassesQueueing = bypassesQueueing
context.parentTransaction = self
context.isTransactionContext = true
if !supportsUndo {
context.undoManager = nil

View File

@@ -135,18 +135,6 @@ public final class UnsafeDataTransaction: BaseDataTransaction {
)
}
/**
Returns the `NSManagedObjectContext` for this unsafe transaction. Use only for cases where external frameworks need an `NSManagedObjectContext` instance to work with.
- Important: It is the developer's responsibility to ensure the following:
- that the `UnsafeDataTransaction` that owns this context should be strongly referenced and prevented from being deallocated during the context's lifetime
- that all saves will be done either through the `UnsafeDataTransaction`'s `commit(...)` method, or by calling `save()` manually on the context, its parent, and all other ancestor contexts if there are any.
*/
public var internalContext: NSManagedObjectContext {
return self.context
}
// MARK: Internal
@@ -154,4 +142,13 @@ public final class UnsafeDataTransaction: BaseDataTransaction {
super.init(mainContext: mainContext, queue: queue, supportsUndo: supportsUndo, bypassesQueueing: true)
}
// MARK: Obsolete
@available(*, obsoleted: 3.0.0, message: "Transaction contexts are now exposed through the FetchableSource and QueryableSource protocols.", renamed: "internalContext()")
public var internalContext: NSManagedObjectContext {
fatalError()
}
}