{"id":24868520,"url":"https://github.com/ftchirou/predicatekit","last_synced_at":"2025-04-05T05:08:30.975Z","repository":{"id":39889558,"uuid":"309217433","full_name":"ftchirou/PredicateKit","owner":"ftchirou","description":"🎯 PredicateKit allows Swift developers to write expressive and type-safe predicates for CoreData using key-paths, comparisons and logical operators, literal values, and functions.","archived":false,"fork":false,"pushed_at":"2024-04-05T18:16:50.000Z","size":96,"stargazers_count":406,"open_issues_count":4,"forks_count":19,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-09-22T14:45:22.776Z","etag":null,"topics":["coredata","keypaths","nspredicate","predicates","swift","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ftchirou.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-02T00:25:32.000Z","updated_at":"2024-09-14T13:27:15.000Z","dependencies_parsed_at":"2022-07-07T15:28:05.311Z","dependency_job_id":"0addcef8-7eff-4ebf-bd2c-f99e37e79c6e","html_url":"https://github.com/ftchirou/PredicateKit","commit_stats":{"total_commits":40,"total_committers":6,"mean_commits":6.666666666666667,"dds":0.125,"last_synced_commit":"783867f4225fbe3e8bd93f3ead4a5dce13b2d521"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ftchirou%2FPredicateKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ftchirou%2FPredicateKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ftchirou%2FPredicateKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ftchirou%2FPredicateKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ftchirou","download_url":"https://codeload.github.com/ftchirou/PredicateKit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247289428,"owners_count":20914464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["coredata","keypaths","nspredicate","predicates","swift","swiftui"],"created_at":"2025-02-01T02:20:28.525Z","updated_at":"2025-04-05T05:08:30.924Z","avatar_url":"https://github.com/ftchirou.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🎯 PredicateKit\n![GitHub Workflow Status (branch)](https://img.shields.io/github/actions/workflow/status/ftchirou/PredicateKit/unit-tests.yml?branch=main) \u003cimg src=\"https://img.shields.io/badge/coverage-100%25-green\"\u003e ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/ftchirou/PredicateKit) \u003cimg src=\"https://img.shields.io/badge/platforms-iOS%2011%2B%20%7C%20macOS%2010.15%2B%20%7C%20watchOS%205%2B%20%7C%20tvOS%2011%2B-lightgrey\"\u003e \u003cimg src=\"https://img.shields.io/badge/swift-%3E%3D%205.1-orange\"\u003e\n\n**PredicateKit** is an alternative to [`NSPredicate`](https://developer.apple.com/documentation/foundation/nspredicate) allowing you to \nwrite expressive and type-safe predicates for [CoreData](https://developer.apple.com/documentation/coredata) using [key-paths](https://developer.apple.com/documentation/swift/keypath),\ncomparisons and logical operators, literal values, and functions.\n\n\u003cimg src=\"https://dl.dropboxusercontent.com/s/h8yeg34jb68vxfy/predicate-kit.png\"\u003e\n\n## Contents\n- [Motivation](#motivation)\n- [Installation](#installation)\n  - [Carthage](#carthage)\n  - [CocoaPods](#cocoapods)\n  - [Swift Package Manager](#swift-package-manager)\n- [Quick start](#quick-start)\n  - [Fetching objects](#fetching-objects)\n  - [Configuring the fetch](#configuring-the-fetch)\n  - [Fetching objects with the @FetchRequest property wrapper](#fetching-objects-with-the-fetchrequest-property-wrapper)\n  - [Fetching objects with the @SectionedFetchRequest property wrapper](#fetching-objects-with-the-sectionedfetchrequest-property-wrapper)\n  - [Fetching objects with an NSFetchedResultsController](#fetching-objects-with-an-nsfetchedresultscontroller)\n  - [Counting objects](#counting-objects)\n- [Documentation](#documentation)\n  - [Writing predicates](#writing-predicates)\n    - [Comparisons](#comparisons)\n      - [Basic comparisons](#basic-comparisons)\n      - [String comparisons](#string-comparisons)\n      - [Membership checks](#membership-checks)\n    - [Compound predicates](#compound-predicates)\n      - [AND](#and-predicates)\n      - [OR](#or-predicates)\n      - [NOT](#not-predicates)\n    - [Array operations](#array-operations)\n      - [`first`](#first)\n      - [`last`](#last)\n      - [`at(index:)`](#atindex)\n      - [`count` / `size`](#count)\n      - [`sum`](#sum)\n      - [`average`](#average)\n      - [`min`](#min)\n      - [`max`](#max)\n      - [`all`](#all)\n      - [`any`](#any)\n      - [`none`](#none)\n    - [Predicates with one-to-one relationships](#predicates-with-one-to-one-relationships)\n    - [Predicates with one-to-many relationships](#predicates-with-one-to-many-relationships)\n    - [Sub-predicates](#sub-predicates)\n  - [Request modifiers](#request-modifiers)\n    - [`limit`](#limit)\n    - [`offset`](#offset)\n    - [`batchSize`](#batchsize)\n    - [`prefetchingRelationships`](#prefetchingrelationships)\n    - [`includingPendingChanges`](#includingPendingChanges)\n    - [`fromStores`](#fromstores)\n    - [`fetchingOnly`](#fetchingonly)\n    - [`returningDistinctResults`](#returningDistinctResults)\n    - [`groupBy`](#groupby)\n    - [`refreshingRefetchedObjects`](#refreshingrefetchedobjects)\n    - [`having`](#having)\n    - [`includingSubentities`](#includingsubentities)\n    - [`returningObjectsAsFaults`](#returningobjectsasfaults)\n    - [`sorted`](#sorted)\n  - [Debugging](#debugging)\n\n# Motivation\n\nCoreData is a formidable piece of technology, however not all of its API has caught up with the modern Swift world. Specifically, fetching and filtering objects from\nCoreData relies heavily on `NSPredicate` and `NSExpression`. Unfortunately, a whole range of bugs and runtime errors can easily be introduced using those APIs.\nFor instance, we can compare a property of type `String` to a value of type `Int` or even use a non-existant property in a predicate; these mistakes will go un-noticed\nat compile time but can cause important errors at runtime that may not be obvious to diagnose. This is where **PredicateKit** comes in by making it virtually impossible to\nintroduce these types of errors.\n\nConcretely, **PredicateKit** provides\n\n- **a type-safe and expressive API** for writing predicates. When using PredicateKit, all properties involved in your predicates are expressed\nusing [key-paths](https://developer.apple.com/documentation/swift/keypath). This ensures that the usage of inexistant properties or typos are\ncaught at compile time. Additionally, all operations such as comparisons, functions calls, etc. are strongly-typed, making it impossible to write invalid predicates.\n- **an improved developer experience**. Enjoy auto-completion and syntax highlighting when writing your predicates. In addition, PredicateKit\nis just a lightweight replacement for `NSPredicate`, no major change to your codebase is required, no special protocol to conform to, no\nconfiguration, etc. Simply `import PredicateKit`, write your predicates and use the functions [`NSManagedObjectContext.fetch(where:)`](#fetching-objects) or [`NSManagedObjectContext.count(where:)`](#counting-objects) to execute them.\n\n# Installation\n\n## Carthage\n\nAdd the following line to your `Cartfile`.\n\n```\ngithub \"ftchirou/PredicateKit\" ~\u003e 1.0.0\n```\n\n## CocoaPods\n\nAdd the following line to your `Podfile`.\n\n```\npod 'PredicateKit', ~\u003e '1.0.0'\n```\n\n## Swift Package Manager\n\nUpdate the `dependencies` array in your `Package.swift`.\n\n```swift\ndependencies: [\n  .package(url: \"https://github.com/ftchirou/PredicateKit\", .upToNextMajor(from: \"1.0.0\"))\n]\n```\n\n# Quick start\n\n## Fetching objects\n\nTo 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.\n\n###### Example\n\n```swift\nlet notes: [Note] = try managedObjectContext\n  .fetch(where: \\Note.text == \"Hello, World!\" \u0026\u0026 \\Note.creationDate \u003c Date())\n  .result()\n```\n\nYou 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.\n\nSee [Writing predicates](#writing-predicates) for more about writing predicates.\n\n### Fetching objects as dictionaries\n\nBy 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]]`)\nsimply by changing the type of the variable storing the result of the fetch.\n\n###### Example\n\n```swift\nlet notes: [[String: Any]] = try managedObjectContext\n  .fetch(where: \\Note.text == \"Hello, World!\" \u0026\u0026 \\Note.creationDate \u003c Date())\n  .result()\n```\n\n## Configuring the fetch\n\n`fetch(where:)` returns an object of type `FetchRequest`. You can apply a series of modifiers on this object to further configure how the objects should be matched and returned.\nFor example, `sorted(by: \\Note.creationDate, .descending)` is a modifier specifying that the objects should be sorted by the creation date in the descending order. A modifier returns a mutated `FetchRequest`; a series\nof modifiers can be chained together to create the final `FetchRequest`.\n\n###### Example\n\n```swift\nlet notes: [Note] = try managedObjectContext\n  .fetch(where: (\\Note.text).contains(\"Hello, World!\") \u0026\u0026 \\Note.creationDate \u003c Date())\n  .limit(50) // Return 50 objects matching the predicate.\n  .offset(100) // Skip the first 100 objects matching the predicate.\n  .sorted(by: \\Note.creationDate) // Sort the matching objects by their creation date.\n  .result()\n```\n\nSee [Request modifiers](#request-modifiers) for more about modifiers.\n\n## Fetching objects with the @FetchRequest property wrapper\n\nPredicateKit extends the SwiftUI [ `@FetchRequest`](https://developer.apple.com/documentation/swiftui/fetchrequest) property wrapper to support type-safe predicates. To use, simply initialize a `@FetchRequest` with a predicate.\n\n###### Example\n\n```swift\nimport PredicateKit\nimport SwiftUI\n\nstruct ContentView: View {\n\n  @SwiftUI.FetchRequest(predicate: \\Note.text == \"Hello, World!\")\n  var notes: FetchedResults\u003cNote\u003e\n\n  var body: some View {\n    List(notes, id: \\.self) {\n      Text($0.text)\n    }\n  }\n}\n```\n\nYou can also initialize a `@FetchRequest` with a full-fledged request with modifiers and sort descriptors.\n\n###### Example\n\n```swift\nimport PredicateKit\nimport SwiftUI\n\nstruct ContentView: View {\n\n  @SwiftUI.FetchRequest(\n    fetchRequest: FetchRequest(predicate: (\\Note.text).contains(\"Hello, World!\"))\n      .limit(50)\n      .offset(100)\n      .sorted(by: \\Note.creationDate)\n  )\n  var notes: FetchedResults\u003cNote\u003e\n\n  var body: some View {\n    List(notes, id: \\.self) {\n      Text($0.text)\n    }\n  }\n}\n```\n\nBoth initializers accept an optional parameter [`animation`](https://developer.apple.com/documentation/swiftui/animation) that will be used to animate changes in the fetched results.\n\n###### Example\n\n```swift\nimport PredicateKit\nimport SwiftUI\n\nstruct ContentView: View {\n\n  @SwiftUI.FetchRequest(\n    predicate: (\\Note.text).contains(\"Hello, World!\"),\n    animation: .easeInOut\n  )\n  var notes: FetchedResults\u003cNote\u003e\n\n  var body: some View {\n    List(notes, id: \\.self) {\n      Text($0.text)\n    }\n  }\n}\n```\n\nYou can update the predicate associated with your `FetchedResults` using `updatePredicate`.\n\n###### Example\n\n```swift\nimport PredicateKit\nimport SwiftUI\n\nstruct ContentView: View {\n\n  @SwiftUI.FetchRequest(predicate: \\Note.text == \"Hello, World!\")\n  var notes: FetchedResults\u003cNote\u003e\n\n  var body: some View {\n    List(notes, id: \\.self) {\n      Text($0.text)\n    }\n    Button(\"Show recents\") {\n      let recentDate: Date = // ...\n      notes.updatePredicate(\\Note.createdAt \u003e= recentDate)\n    }\n  }\n}\n```\n\nThis will cause the associated `FetchRequest` to execute a fetch with the new predicate when the `Show recents` button is tapped.\n\n## Fetching objects with the @SectionedFetchRequest property wrapper\n\nPredicateKit also extends the SwiftUI [`@SectionedFetchRequest`](https://developer.apple.com/documentation/swiftui/sectionedfetchrequest) property wrapper to support type-safe predicates.\n\n###### Example\n\n```swift\nimport PredicateKit\nimport SwiftUI\n\nstruct ContentView: View {\n  @SwiftUI.SectionedFetchRequest(\n    fetchRequest: FetchRequest(predicate: \\User.name == \"John Doe\"),\n    sectionIdentifier: \\.billingInfo.accountType\n  )\n  var users: SectionedFetchResults\u003cString, User\u003e\n  \n  var body: some View {\n    List(users, id: \\.id) { section in\n      Section(section.id) {\n        ForEach(section, id: \\.objectID) { user in\n          Text(user.name)\n        }\n      }\n    }\n  }\n```\n\nYou can update the predicate associated with your `SectionedFetchedResults` using `updatePredicate`.\n\n###### Example\n\n```swift\nimport PredicateKit\nimport SwiftUI\n\nstruct ContentView: View {\n  @SwiftUI.SectionedFetchRequest(\n    fetchRequest: FetchRequest(predicate: \\User.name == \"John Doe\"),\n    sectionIdentifier: \\.billingInfo.accountType\n  )\n  var users: SectionedFetchResults\u003cString, User\u003e\n  \n  var body: some View {\n    List(users, id: \\.id) { section in\n      Section(section.id) {\n        ForEach(section, id: \\.objectID) { user in\n          Text(user.name)\n        }\n      }\n    }\n    Button(\"Search\") {\n      let query: String = // ...\n      users.updatePredicate((\\User.name).contains(query))\n    }\n  }\n}\n```\n\nThis will cause the associated `FetchRequest` to execute a fetch with the new predicate when the `Search` button is tapped.\n\n## Fetching objects with an NSFetchedResultsController\n\nIn UIKit, you can use `fetchedResultsController()` to create an `NSFetchedResultsController` from a configured fetch request. `fetchedResultsController` has two optional parameters: \n\n- `sectionNameKeyPath` is a [key-path](https://developer.apple.com/documentation/swift/keypath) on the returned objects used to compute section info\n- `cacheName` is the name of a file to store pre-computed section info.\n\n###### Example\n\n```swift\nlet controller: NSFetchedResultsController\u003cNote\u003e = managedObjectContext\n  .fetch(where: \\Note.text == \"Hello, World!\" \u0026\u0026 \\Note.creationDate \u003c Date())\n  .sorted(by: \\Note.creationDate, .descending)\n  .fetchedResultsController(sectionNameKeyPath: \\Note.creationDate)\n```\n\n## Counting objects\n\nTo count the number of objects matching a predicate, use the function `count(where:)` on an instance of `NSManagedObjectContext`.\n\n###### Example\n\n```swift\nlet count = try managedObjectContext.count(where: (\\Note.text).beginsWith(\"Hello\"))\n```\n\n# Documentation\n\n## Writing predicates\n\nPredicates are expressed using a combination of comparison operators and logical operators, literal values, and functions.\n\n### Comparisons\n\n#### Basic comparisons\n\nA comparison can be expressed using one of the basic comparison operators `\u003c`, `\u003c=`, `==`, `\u003e=`, and `\u003e` where the left hand side of\nthe operator is a [key-path](https://developer.apple.com/documentation/swift/keypath) and the right hand side\nof the operator is a value whose type matches the value type of the key-path on the left hand side.\n\n###### Example\n\n```swift\nclass Note: NSManagedObject {\n  @NSManaged var text: String\n  @NSManaged var creationDate: Date\n  @NSManaged var numberOfViews: Int\n  @NSManaged var tags: [String]\n  @NSManaged var attachment: Attachment\n  @NSManaged var type: NoteType\n}\n\nclass Attachment: NSManagedObject, Identifiable {\n  // ...\n}\n\n@objc enum NoteType: Int {\n  case freeForm\n  // ...\n}\n\n// Matches all notes where the text is equal to \"Hello, World!\".\nlet predicate = \\Note.text == \"Hello, World!\"\n\n// Matches all notes created before the current date.\nlet predicate = \\Note.creationDate \u003c Date()\n\n// Matches all notes where the number of views is at least 120.\nlet predicate = \\Note.numberOfViews \u003e= 120\n\n// Matches all notes having the specified attachment (`Attachment` must conform to `Identifiable`).\nlet predicate = \\Note.attachment == attachment\n\n// Matches all free form notes (assuming `NoteType` is an enumeration whose `RawValue` conforms to `Equatable`).\nlet predicate = \\Note.type == .freeForm\n```\n\n#### String comparisons\n\nIf the property to compare is of type `String`, comparisons can be additionally expressed with special functions such as `beginsWith`,\n`contains`, or `endsWith`.\n\n```swift\n// Matches all notes where the text begins with the string \"Hello\".\nlet predicate = (\\Note.text).beginsWith(\"Hello\")\n\n// Matches all notes where the text contains the string \"Hello\".\nlet predicate = (\\Note.text).contains(\"Hello\")\n\n// Matches all notes where the text matches the specified regular expression.\nlet predicate = (\\Note.text).matches(NSRegularExpression(...))\n```\nAny of the following functions can be used in a string comparison predicate.\n\n- `beginsWith`\n- `contains`\n- `endsWith`\n- `like`\n- `matches`\n\nThese functions accept a second optional parameter specifying how the string comparison should be performed.\n\n```swift\n// Case-insensitive comparison.\nlet predicate = (\\Note.text).beginsWith(\"Hello, World!\", .caseInsensitive)\n\n// Diacritic-insensitive comparison.\nlet predicate = (\\Note.text).beginsWith(\"Hello, World!\", .diacriticInsensitive)\n\n// Normalized comparison.\nlet predicate = (\\Note.text).beginsWith(\"Hello, World!\", .normalized)\n```\n\n#### Membership checks\n\n###### between\n\nYou can use the `between` function or the `~=` operator to determine whether a property's value is within a specified range.\n\n```swift\n// Matches all notes where the number of views is between 100 and 200.\nlet predicate = (\\Note.numberOfViews).between(100...200)\n\n// Or\nlet predicate = \\Note.numberOfViews ~= 100...200\n```\n\n###### in\n\nYou can use the `in` function to determine whether a property's value is one of the values in a variadic list of arguments, an array, or a set.\n\n```swift\n// Matches all notes where the text is one of the elements in the specified variadic arguments list.\nlet predicate = (\\Note.numberOfViews).in(100, 200, 300, 400)\n\n// Matches all notes where the text is one of the elements in the specified array.\nlet predicate = (\\Note.text).in([100, 200, 300, 400])\n\n// Matches all notes where the text is one of the elements in the specified set.\nlet predicate = (\\Note.text).in(Set([100, 200, 300, 400]))\n```\n\nWhen the property type is a `String`, `in` accepts a second parameter that determines how the string should be compared to the elements in the list.\n\n```swift\n// Case-insensitive comparison.\nlet predicate = (\\Note.text).in([\"a\", \"b\", \"c\", \"d\"], .caseInsensitive)\n```\n\n### Compound predicates\n\nCompound predicates are predicates that logically combine one, two or more predicates.\n\n#### AND predicates\n\nAND predicates are expressed with the `\u0026\u0026` operator where the operands are predicates. An AND predicate\nmatches objects where both its operands match.\n\n```swift\n// Matches all notes where the text begins with 'hello' and the number of views is at least 120.\nlet predicate = (\\Note.text).beginsWith(\"hello\") \u0026\u0026 \\Note.numberOfViews \u003e= 120\n```\n\n#### OR Predicates\n\nOR predicates are expressed with the `||` operator where the operands are predicates. An OR predicate matches\nobjects where at least one of its operands matches.\n\n```swift\n// Matches all notes with the text containing 'hello' or created before the current date.\nlet predicate = (\\Note.text).contains(\"hello\") || \\Note.creationDate \u003c Date()\n```\n\n#### NOT Predicates\n\nNOT predicates are expressed with the unary `!` operator with a predicate operand. A NOT predicate matches all objects\nwhere its operand does not match.\n\n```swift\n// Matches all notes where the text is not equal to 'Hello, World!'\nlet predicate = !(\\Note.text == \"Hello, World!\")\n```\n\n### Array operations\n\nYou can perform operations on properties of type `Array` (or expressions that evaluate to values of type `Array`) and use the result in a predicate.\n\n#### Select an element in an array\n\n###### first\n\n```swift\n// Matches all notes where the first tag is 'To Do'..\nlet predicate = (\\Note.tags).first == \"To Do\"\n```\n\n###### last\n\n```swift\n// Matches all notes where the last tag is 'To Do'..\nlet predicate = (\\Note.tags).last == \"To Do\"\n```\n\n###### at(index:)\n\n```swift\n// Matches all notes where the third tag contains 'To Do'.\nlet predicate = (\\Note.tags).at(index: 2).contains(\"To Do\")\n```\n\n#### Count the number of elements in an array\n\n###### count\n\n```swift\n// Matches all notes where the number of elements in the `tags` array is less than 5.\nlet predicate = (\\Note.tags).count \u003c 5\n\n// or\n\nlet predicate = (\\Note.tags).size \u003c 5\n```\n\n#### Combine the elements in an array\n\nIf the elements of an array are numbers, you can combine or reduce them into a single number and use the result in a predicate.\n\n```swift\nclass Account: NSManagedObject {\n  @NSManaged var purchases: [Double]\n}\n```\n\n###### sum\n\n```swift\n// Matches all accounts where the sum of the purchases is less than 2000.\nlet predicate = (\\Account.purchases).sum \u003c 2000\n```\n\n###### average\n\n```swift\n// Matches all accounts where the average purchase is 120.0\nlet predicate = (\\Account.purchases).average == 120.0\n```\n\n###### min\n\n```swift\n// Matches all accounts where the minimum purchase is 98.5.\nlet predicate = (\\Account.purchases).min == 98.5\n```\n\n###### max\n\n```swift\n// Matches all accounts where the maximum purchase is at least 110.5.\nlet predicate = (\\Account.purchases).max \u003e= 110.5\n```\n\n#### Aggregate comparisons\n\nYou can also express predicates matching all, any, or none of the elements of an array.\n\n###### all\n\n```swift\n// Matches all accounts where every purchase is at least 95.0\nlet predicate = (\\Account.purchases).all \u003e= 95.0\n```\n\n###### any\n\n```swift\n// Matches all accounts having at least one purchase of 20.0\nlet predicate = (\\Account.purchases).any == 20.0\n```\n\n###### none\n\n```swift\n// Matches all accounts where no purchase is less than 50.\nlet predicate = (\\Account.purchases).none \u003c= 50\n```\n\n### Predicates with one-to-one relationships\n\nIf your object has a one-to-one relationship with another one, you can target any property of the relationship simply by\nusing the appropriate key-path.\n\n###### Example\n\n```swift\nclass User: NSManagedObject {\n  @NSManaged var name: String\n  @NSManaged var billingInfo: BillingInfo\n}\n\nclass BillingInfo: NSManagedObject {\n  @NSManaged var accountType: String\n  @NSManaged var purchases: [Double]\n}\n\n// Matches all users with the billing account type 'Pro'\nlet predicate = \\User.billingInfo.accountType == \"Pro\"\n\n// Matches all users with an average purchase of 120\nlet predicate = (\\User.billingInfo.purchases).average == 120.0\n```\n\n### Predicates with one-to-many relationships\n\nYou can run aggregate operations on a set of relationships using the `all(_:)`, `any(_:)`, or `none(_:)` functions.\n\n###### Example\n\n```swift\nclass Account: NSManagedObject {\n  @NSManaged var name: String\n  @NSManaged var profiles: Set\u003cProfile\u003e\n}\n\nclass Profile: NSManagedObject {\n  @NSManaged var name: String\n  @NSManaged var creationDate: String\n}\n\n// Matches all accounts where all the profiles have the creation date equal to the specified one.\nlet predicate = (\\Account.profiles).all(\\.creationDate) == date\n\n// Matches all accounts where any of the associated profiles has a name containing 'John'.\nlet predicate = (\\Account.profiles).any(\\.name).contains(\"John\"))\n\n// Matches all accounts where no profile has the name 'John Doe'\nlet predicate = (\\Account.profiles).none(\\.name) == \"John Doe\"\n```\n\n### Sub-predicates\n\nWhen your object has one-to-many relationships, you can create a sub-predicate that filters the \"many\" relationships and use the\nresult of the sub-predicate in a more complex predicate. Sub-predicates are created using the global `all(_:where:)` function. The first\nparameter is the key-path of the collection to filter and the second parameter is a predicate that filters the collection.\n\n`all(_:where:)` evaluates to an array; that means you can perform any valid [array operation](#array-operations) on its result such as `size`, `first`, etc.\n\n###### Example\n\n```swift\n// Matches all the accounts where the name contains 'Account' and where the number of profiles whose\n// name contains 'Doe' is exactly 2.\nlet predicate = (\\Account.name).contains(\"Account\") \n  \u0026\u0026 all(\\.profiles, where: (\\Profile.name).contains(\"Doe\")).size == 2)\n```\n\n## Request modifiers\n\nYou can configure how matching objects are returned by applying a chain of modifiers to the object returned by `NSManagedObjectContext.fetch(where:)`.\n\n###### Example\n\n```swift\nlet notes: [Note] = try managedObjectContext\n  .fetch(where: (\\Note.text).contains(\"Hello, World!\") \u0026\u0026 \\Note.creationDate \u003c Date())\n  .limit(50) // Return 50 objects matching the predicate.\n  .offset(100) // Skip the first 100 objects matching the predicate.\n  .sorted(by: \\Note.creationDate) // Sort the matching objects by their creation date.\n  .result()\n```\n\n### limit\n\nSpecifies the number of objects returned by the fetch request.\n\n###### Usage\n\n```swift\nmanagedObjectContext.fetch(where: ...)\n  .limit(50)\n```\n\n###### `NSFetchRequest` equivalent\n\n[`fetchLimit`](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506622-fetchlimit)\n\n### offset\n\nSpecifies the number of initial matching objects to skip.\n\n###### Usage\n\n```swift\nmanagedObjectContext.fetch(where: ...)\n  .offset(100)\n```\n\n###### `NSFetchRequest` equivalent\n\n[`fetchOffset`](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506770-fetchoffset)\n\n### batchSize\n\nSpecifies the batch size of the objects in the fetch request.\n\n###### Usage\n\n```swift\nmanagedObjectContext.fetch(where: ...)\n  .batchSize(80)\n```\n\n###### `NSFetchRequest` equivalent\n\n[`fetchBatchSize`](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506558-fetchbatchsize)\n\n### prefetchingRelationships\n\nSpecifies the key-paths of the relationships to prefetch along with objects of the fetch request.\n\n###### Usage\n\n```swift\nmanagedObjectContext.fetch(where: ...)\n  .prefetchingRelationships(\\.billingInfo, \\.profiles)\n```\n\n###### `NSFetchRequest` equivalent\n\n[`relationshipKeyPathsForPrefetching`](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506813-relationshipkeypathsforprefetchi)\n\n### includingPendingChanges\n\nSpecifies whether changes unsaved in the managed object context are included in the result of the fetch request.\n\n###### Usage\n\n```swift\nmanagedObjectContext.fetch(where: ...)\n  .includingPendingChanges(true)\n```\n\n###### `NSFetchRequest` equivalent\n\n[`includesPendingChanges`](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506724-includespendingchanges)\n\n### fromStores\n\nSpecifies the persistent stores to be searched when the fetch request is executed.\n\n###### Usage\n\n```swift\nlet store1: NSPersistentStore = ...\nlet store2: NSPersistentStore = ...\n\nmanagedObjectContext.fetch(where: ...)\n  .fromStores(store1, store2)\n```\n\n###### `NSFetchRequest` equivalent\n\n[`affectedStores`](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506518-affectedstores)\n\n### fetchingOnly\n\nSpecifies the key-paths to fetch.\n\n###### Usage\n\n```swift\nmanagedObjectContext.fetch(where: ...)\n  .fetchingOnly(\\.text, \\.creationDate)\n```\n\n###### `NSFetchRequest` equivalent\n\n[propertiesToFetch](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506851-propertiestofetch)\n\n### returningDistinctResults\n\nSpecifies whether the fetch request returns only distinct values for the key-paths specified by [`fetchingOnly(_:)`](#fetchingonly).\n\n###### Usage\n\n```swift\nmanagedObjectContext.fetch(where: ...)\n  .fetchingOnly(\\.text, \\.creationDate)\n  .returningDistinctResults(true)\n```\n\n###### `NSFetchRequest` equivalent\n\n[returnsDistinctResults](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506344-returnsdistinctresults)\n\n### groupBy\n\nSpecifies the key-paths of the properties to group the result by, when the result of the request is of type `[[String: Any]]`.\n\n###### Usage\n\n```swift\nlet result: [[String: Any]] = managedObjectContext.fetch(where: ...)\n  .groupBy(\\.creationDate)\n```\n\n###### `NSFetchRequest` equivalent\n\n[propertiesToGroupBy](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506191-propertiestogroupby)\n\n### refreshingRefetchedObjects\n\nSpecifies whether the property values of fetched objects will be updated with the current values in the persistent store.\n\n###### Usage\n\n```swift\nmanagedObjectContext.fetch(where: ...)\n  .shouldRefreshRefetchedObjects(false)\n```\n\n###### `NSFetchRequest` equivalent\n\n[shouldRefreshRefetchedObjects](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506440-shouldrefreshrefetchedobjects)\n\n### having\n\nSpecifies the predicate to use to filter objects returned by a request with a [`groupBy(_:)`](#groupby) modifier applied.\n\n###### Usage\n\n```swift\nlet result: [[String: Any]] = managedObjectContext.fetch(where: ...)\n  .groupBy(\\.creationDate)\n  .having((\\Note.text).contains(\"Hello, World!\"))\n```\n\n###### `NSFetchRequest` equivalent\n\n[havingPredicate](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506429-havingpredicate)\n\n### includingSubentities\n\nSpecifies whether subentities are included in the result.\n\n###### Usage\n\n```swift\nmanagedObjectContext.fetch(where: ...)\n  .includingSubentities(true)\n```\n\n###### `NSFetchRequest` equivalent\n\n[includesSubentities](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506366-includessubentities)\n\n### returningObjectsAsFaults\n\nSpecifies whether objects returned from the fetch request are faults.\n\n###### Usage\n\n```swift\nmanagedObjectContext.fetch(where: ...)\n  .returningObjectsAsFaults(true)\n```\n\n###### `NSFetchRequest` equivalent\n\n[returnsObjectsAsFaults](https://developer.apple.com/documentation/coredata/nsfetchrequest/1506756-returnsobjectsasfaults)\n\n### sorted\n\nSpecifies how the objects returned by the request should be sorted. This modifier takes one required parameter and 2 optional ones:\n\n- `by`: the key-path by which to sort the objects. (Required)\n- `order`: the order in which to sort the objects. (Optional, defaults to `.ascending`)\n- `comparator`: a custom comparator to use to sort the objects. (Optional, defaults to `nil`)\n\n###### Usage\n\n```swift\nmanagedObjectContext.fetch(where: ...)\n  .sorted(by: \\.text)\n  .sorted(by: \\.creationDate, .descending)\n```\n\n## Debugging\n\nIn `DEBUG` mode, you can inspect the actual `NSFetchRequest`s that are being executed by using the modifier `inspect(on:)` on a `FetchRequest`.\n\n###### Example\n\n```swift\nstruct Inspector: NSFetchRequestInspector {\n  func inspect\u003cResult\u003e(_ request: NSFetchRequest\u003cResult\u003e) {\n    // Log or print the request here.\n  }\n}\n\nlet notes: [Note] = try managedObjectContext\n  .fetch(where: \\Note.text == \"Hello, World!\")\n  .sorted(by: \\Note.creationDate, .descending)\n  .inspect(on: Inspector())\n  .result()\n```\n\nHappy coding! ⚡️\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fftchirou%2Fpredicatekit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fftchirou%2Fpredicatekit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fftchirou%2Fpredicatekit/lists"}