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.
@FetchableManagedObjectfinalclassUser:NSManagedObject{@NSManagedvarscore=0.0@NSManagedvarname: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)}.nsValueMore 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
NSPredicatedoes 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.