Reputation: 984
Swift 5.9 and the new SwiftData framework introduce the @Model
and #Predicate
macros. We can now use custom enums and structs in our our models, like so:
@Model
final class Item {
var name: Name
var nature: Nature
struct Name: Codable {
let base: String
let suffix: String?
}
enum Nature: Int, Codable {
case foo = 0
case bar = 1
case baz = 2
}
init(name: Name, nature: Nature) {
self.name = name
self.nature = nature
}
}
But how can we use them in a Predicate
? All of these examples fail:
// Member access without an explicit base is not allowed in this predicate (from macro 'Predicate')
let predicate = #Predicate<Item> { $0.nature == .foo }
// Cannot infer key path type from context; consider explicitly specifying a root type.
let predicate = #Predicate<Item> { $0.nature.rawValue == Item.Nature.foo.rawValue }
// No compile error, but causes the Xcode Preview to crash when used inside a @Query.
let predicate = #Predicate<Item> { $0.name.base.contains("Hello, world!") }
// Optional chaining is not supported here in this predicate. Use the flatMap(_:) function explicitly instead. (from macro 'Predicate').
let predicate = #Predicate<Item> { $0.name.suffix?.contains("Hello, world!") ?? false }
Upvotes: 14
Views: 3065
Reputation: 17787
You need to capture/freeze the comparison value outside of the predicate closure:
let foo = Item.Nature.foo
let predicate = #Predicate<Item> { $0.nature == foo }
Not sure about the name
issue, but it'd probably be easier if Name
was a @Model itself and a @Relationship instead of a Codable.
Upvotes: 9
Reputation: 6253
// Optional chaining is not supported here in this predicate. Use the flatMap(_:) function explicitly instead. (from macro 'Predicate').
let predicate = #Predicate<Item> { $0.name.suffix?.contains("Hello, world!") ?? false }
-->
let predicate = #Predicate<Item> { $0.name.suffix.flatMap { $0.contains("Hello, world!") } == true }
Upvotes: 1