This library offers a DSL (Domain Specific Language) to safely build predicates and requests to fetch a CoreData store.
The documentation is built with docC. You can read it online or locally by running Product → Build Documentation or hitting ⇧⌃⌘D.
The library requires to manually define the entity class. Then the macro FetchableManagedObject
can be used.
@FetchableManagedObject
final class User: NSManagedObject {
@NSManaged var score = 0.0
@NSManaged var name: String? = ""
}
This makes User
conform to Fetchable
and ready to be used with the SafeFetching API.
Then it's possible to use the DSL to build a request. The last step can either get the built request as NSFetchRequest<User>
or execute the request in the provided context.
User.request()
.all(after: 10)
.where { $0.score >= 15 || $0.name != "Joe" }
.sorted(by: .ascending(\.score), .descending(\.name))
.setting(\.returnsDistinctResults, to: true)
.nsValue // returns NSFetchRequest<User>
User.request()
.all(after: 10)
.where { $0.score >= 15 || $0.name != "Joe" }
.sorted(by: .ascending(\.score), .descending(\.name))
.setting(\.returnsDistinctResults, to: true)
.fetch(in: context) // returns [User]
Advanced NSPredicate
operators are also available like BEGINSWITH
(hasPrefix
).
User.request()
.all()
.where { $0.name.hasPrefix("Do", options: .caseInsensitive) }
.nsValue
More about predicates in the documentation.
The library also offers convenience functions to set a predicate of a NSFetchRequest
.
request.predicate = .safe(on: User.self) { $0.score.isIn(10...20 }
// or
request.predicate = .safe(on: User.self) { (10...20).contains($0.score) }
Why not using the Predicate
macro? Two reasons.
- It works only with SwiftData as of today (so iOS 17+, macOS 14+ ...). It doesn't work with CoreData.
- It doesn't support everything that
NSPredicate
does when fetching a CoreData store.
Meanwhile, NSPredicate
requires to write everything in a String
, which is very error-prone.
Whereas this library tries to cover three objectives:
- Use compiler-checking to evaluate predicates and avoid runtime errors.
- Writing a request and especially a predicate should feel as natural as possible in Swift.
- No feature of NSPredicate to fetch a CoreData store should be left behind.