I'm trying to combine multiple Predicates of the Type with and / or. Previously with CoreData and NSPredicate I'd just do this:
let predicate = NSPredicate(value: true)
let predicate2 = NSPredicate(value: false)
let combinedPred = NSCompoundPredicate(type: .or, subpredicates: [predicate, predicate2])
Is there a comparable way to do this using SwiftData and #Predicate? And if not, how could I implement a way to create partial conditions beforehand and combine them in a predicate later?
The only way I've found of doing this as an expression is like this, but this would make my predicate hundredths of lines long
let includeOnlyFavorites = true
#Predicate { includeOnlyFavorites ? $0.isFavorite : true }
Context:
I'm developing an App that allows users to save and query items using shortcut actions. The items are stored using SwiftData and queried using EntityPropertyQuery
Apple implements the Query properties like this:
static var properties = QueryProperties {
Property(\BookEntity.$title) {
EqualToComparator { NSPredicate(format: "title = %@", $0) }
ContainsComparator { NSPredicate(format: "title CONTAINS %@", $0) }
}
}
and later combines the predicates with NSCompoundPredicate.
Tried and failed:
Closure with Bool return:
let isFavorite = { (item: Item) in item.isFavorite }
let predicate = #Predicate<Item> { isFavorite($0) }
- won't work because Predicate does not allow global functions
- i also tried creating an object IsFavoriteFilter with an
evaluate(Item) -> Boolmethod but I also can't use that
I also thought i might be able to use StandardPredicateExpression in another predicate because in the documentation it reads:
"A component expression that makes up part of a predicate, and that's supported by the standard predicate type." but there are no further explanations on this type
Building on the answer by @orgtre
TLDR: This Gist implements two methods
conjunction()anddisjunction()onArray<Predicate<T>>the reason for the error and subsequent crash is that the
PredicateExpressions.Variableis used to resolve the Predicate input.This is how Predicate Variable reolving works internally:
The Predicate you create looks something like this (when expanded):
The closure takes parameters of
PredicateExpressions.Variable<Input>which you need to pass as an argument to your expression$0This variable will be unique for every predicate you created, meaning when you combine them using just the
predicate.expressionproperty, each expression has a distinct Variable leading to aunresolved Variableerror.I created a custom
StandardPredicateExpressionthat takes a predicate and a variable and will do the following in it's evaluate method:Extending the excellent work by @orgtre to create a solution that takes an array of predicates and a closure for combining them
Check this Gist for an implementation