diff --git a/PredicateKit/CoreData/NSManagedObjectContextExtensions.swift b/PredicateKit/CoreData/NSManagedObjectContextExtensions.swift index a6edbd8..0f0efb1 100644 --- a/PredicateKit/CoreData/NSManagedObjectContextExtensions.swift +++ b/PredicateKit/CoreData/NSManagedObjectContextExtensions.swift @@ -334,7 +334,24 @@ public struct FetchRequest { #endif return try context.fetch(request) } - + + // MARK: - + + /// Executes the fetch request. + /// + /// - Returns: An array of objects of type `Entity` matching the criteria specified by the fetch request. + /// + /// ## Example + /// + /// let notes: [Note] = try managedObjectContext + /// .fetch(where: (\Note.text).contains("Hello, World!")) + /// .sorted(by: \.creationDate, .descending) + /// .entityResult() + /// + public func entityResult() throws -> [Entity] { + try result() + } + /// Executes the fetch request. /// /// - Returns: An array of `[String: Any]` containing the keys or a subset of the keys of the objects of type `Entity` @@ -356,6 +373,23 @@ public struct FetchRequest { return try context.fetch(request) as! [[String: Any]] } + /// Executes the fetch request. + /// + /// - Returns: An array of `[String: Any]` containing the keys or a subset of the keys of the objects of type `Entity` + /// matching the criteria specified by the fetch request. + /// + /// ## Example + /// + /// let dictionaries: [[String: Any]] = try managedObjectContext + /// .fetch(where: (\Note.text).contains("Hello, World!")) + /// .sorted(by: \.creationDate, .descending) + /// .fetchingOnly(\.text, \.creationDate) + /// .dictionaryResult() + /// + public func dictionaryResult() throws -> [[String: Any]] { + try result() + } + /// Counts the number of objects matching the criteria specified by the fetch request. /// /// - Returns: The number of objects matching the criteria specified by the fetch request. diff --git a/PredicateKitTests/CoreDataTests/NSManagedObjectContextExtensionsTests.swift b/PredicateKitTests/CoreDataTests/NSManagedObjectContextExtensionsTests.swift index a29dce1..14bd8ce 100644 --- a/PredicateKitTests/CoreDataTests/NSManagedObjectContextExtensionsTests.swift +++ b/PredicateKitTests/CoreDataTests/NSManagedObjectContextExtensionsTests.swift @@ -115,6 +115,26 @@ final class NSManagedObjectContextExtensionsTests: XCTestCase { XCTAssertNil(texts.first?["numberOfViews"]) XCTAssertNil(texts.first?["creationDate"]) } + + func testFetchDictionaryResultWithBasicComparison() throws { + try container.viewContext.insertNotes( + (text: "Hello, World!", creationDate: Date(), numberOfViews: 42, tags: ["greeting"]), + (text: "Goodbye!", creationDate: Date(), numberOfViews: 3, tags: ["greeting"]) + ) + + let texts: [[String: Any]] = try container + .viewContext + .fetch(where: \Note.text == "Hello, World!") + .fetchingOnly(\Note.text) + .dictionaryResult() + + XCTAssertEqual(texts.count, 1) + XCTAssertEqual(texts.first?.count, 1) + XCTAssertEqual(texts.first?["text"] as? String, "Hello, World!") + XCTAssertNil(texts.first?["tags"]) + XCTAssertNil(texts.first?["numberOfViews"]) + XCTAssertNil(texts.first?["creationDate"]) + } @available(iOS 13.0, watchOS 6.0, tvOS 13.0, *) func testFetchWithObjectComparison() throws { @@ -204,6 +224,21 @@ final class NSManagedObjectContextExtensionsTests: XCTestCase { XCTAssertTrue(notes.contains(where: { $0.text == "Hello, World!" })) XCTAssertTrue(notes.contains(where: { $0.text == "Goodbye!" })) } + + func testFetchAllEntityResults() throws { + try container.viewContext.insertNotes( + (text: "Hello, World!", creationDate: Date(), numberOfViews: 42, tags: ["greeting"]), + (text: "Goodbye!", creationDate: Date(), numberOfViews: 3, tags: ["greeting"]) + ) + + let notes: [Note] = try container.viewContext + .fetchAll() + .entityResult() + + XCTAssertEqual(notes.count, 2) + XCTAssertTrue(notes.contains(where: { $0.text == "Hello, World!" })) + XCTAssertTrue(notes.contains(where: { $0.text == "Goodbye!" })) + } func testFetchWithStringComparison1() throws { try container.viewContext.insertNotes( diff --git a/README.md b/README.md index a20df97..ea6345a 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ dependencies: [ ## Fetching objects -To fetch objects using PredicateKit, use the function `fetch(where:)` on an instance of `NSManagedObjectContext` passing as argument a predicate. `fetch(where:)` returns an object of type `FetchRequest` on which you call `result()` to execute the request and retrieve the matching objects. +To fetch objects using PredicateKit, use the function `fetch(where:)` on an instance of `NSManagedObjectContext` passing as argument a predicate. `fetch(where:)` returns an object of type `FetchRequest` on which you call `result()` (or `entityResult()` to allow function chaining) to execute the request and retrieve the matching objects. ###### Example @@ -119,6 +119,11 @@ To fetch objects using PredicateKit, use the function `fetch(where:)` on an inst let notes: [Note] = try managedObjectContext .fetch(where: \Note.text == "Hello, World!" && \Note.creationDate < Date()) .result() + +let notes = try managedObjectContext + .fetch(where: \Note.text == "Hello, World!" && \Note.creationDate < Date()) + .entityResult() + .first ``` You write your predicates using the [key-paths](https://developer.apple.com/documentation/swift/keypath) of the entity to filter and a combination of comparison and logical operators, literal values, and functions calls. @@ -127,8 +132,8 @@ See [Writing predicates](#writing-predicates) for more about writing predicates. ### Fetching objects as dictionaries -By default, `fetch(where:)` returns an array of subclasses of `NSManagedObject`. You can specify that the objects be returned as an array of dictionaries (`[[String: Any]]`) -simply by changing the type of the variable storing the result of the fetch. +By default, `fetch(where:)` returns an array of subclasses of `NSManagedObject`. You can specify that the objects be returned as an array of dictionaries `[[String: Any]]` +simply by changing the type of the variable storing the result of the fetch or specifically calling `dictionaryResult()`. ###### Example @@ -136,6 +141,10 @@ simply by changing the type of the variable storing the result of the fetch. let notes: [[String: Any]] = try managedObjectContext .fetch(where: \Note.text == "Hello, World!" && \Note.creationDate < Date()) .result() + +let notes = try managedObjectContext + .fetch(where: \Note.text == "Hello, World!" && \Note.creationDate < Date()) + .dictionaryResult() ``` ## Configuring the fetch