How can I filter an item based on an array using a Predicate
I am having the following SwiftData models:
@Model
class Place {
...
@Relationship(inverse: \Tag.places) var tags: [Tag]
...
}
and
@Model
class Tag {
...
@Attribute(.unique) var uuid: UUID
@Relationship(deleteRule: .nullify) private(set) var places: [Place]
...
}
I want to filter the Place model based on its tags to match against any provided tags
for example I want all places that have any of [work, restaurants] tags
what I did is:
let tags: [Tag] = ...
#Predicate<Place> { place in
place.tags.allSatisfy { tag in
tags.contains(where: { $0.uuid == tag.uuid })
}
}
I am getting this error:
Cannot convert value of type 'PredicateExpressions.SequenceAllSatisfy<PredicateExpressions.KeyPath<PredicateExpressions.Variable, [Tag]>, PredicateExpressions.SequenceContainsWhere<PredicateExpressions.Value<[Tag]>, PredicateExpressions.Equal<PredicateExpressions.KeyPath<PredicateExpressions.Variable, UUID>, PredicateExpressions.KeyPath<PredicateExpressions.Variable, UUID>>>>' to closure result type 'any StandardPredicateExpression'
Any thoughts on how can I make it work?
Since Predicate is both Codable and Sendable, it requires that everything the predicate captures (i.e. all instances captured by the closure) are also Codable and Sendable. In your case, your predicate is capturing tags which has the type [Tag], and it looks like from the declaration of Tag that it is neither Codable nor Sendable, which is likely what the compiler is trying to tell you here.
To resolve this, can you capture the list of UUIDs instead (since UUID is Codable & Sendable)? For example:
let tags: [Tag] = ...
let uuids = tags.map(\.uuid)
#Predicate<Place> { place in
place.tags.allSatisfy { tag in
uuids.contains(tag.uuid)
}
}
2 Likes
Whoah I had no Idea Predicate captures should be Codable!
Thank you for your help, this solves the problem 
1 Like