I have two Models which are defined (simplified) as follows:
@Model final class Book {
var id: UUID = UUID()
var title: String = ""
var authors: [Author]? = []
}
@Model final class Author {
var id: UUID = UUID()
var name: String ""
@Relationship(inverse: \Book.authors) var books: [Book]? = []
}
Both Book.authors and Author.books are defined as optionals
to satisfy the requirements of CloudKit, although it is clear
from the above that neither is ever actually nil.
I am trying to write a #Predicate that finds objects of type
Book with a title that matches a specified title and with an
author that matches a specified author. The function I'd like
to write looks something like this:
func find(title: String, author: Author,
with context: ModelContext) -> Book? {
let same = ComparisonResult.orderedSame
let predicate = #Predicate<Book> { book in
book.title.caseInsensitiveCompare(title) == same &&
book.authors!.contains(where: { $0.id == author.id })
}
let descriptor = FetchDescriptor<Book>(predicate: predicate)
return try? context.fetch(descriptor).first
}
This function fails to compile inside the expansion of the
#Predicate macro with a very long error message:
Cannot convert value of type
(a long 'PredicateExpresions....')
(aka
(another log 'PredicateExpressions....'))
to closure result type 'any StandardPredicateExpression<Bool>'
I don't understand. How can I write this predicate so that it will both compile and work? I know how to work around this problem, but would like to both deepen my understanding of Swift and SwiftData and to avoid the (inelegant) workaround.