Search code examples
swiftswiftuiswiftdata

The component(_:from:) function is not supported in this predicate


In Swift I have the model class:

@Model
final class Transaction {
    @Attribute(.unique)
    let id: UUID
    let title: String
    let amount: Decimal
    let transactionType: TransactionType
    let transactionCategory: TransactionCategory?
    let date: Date
    
    init(
        title: String,
        amount: Decimal,
        transactionType: TransactionType,
        transactionCategory: TransactionCategory?,
        date: Date
    ) {
        self.id = UUID()
        self.title = title
        self.amount = amount
        self.transactionType = transactionType
        self.transactionCategory = transactionCategory
        self.date = date
    }
}

and a view:

struct YearDetailsView: View {
    private let year: Int
    
    @Query
    private let transactions: [Transaction]
    
    init(year: Int) {
        self.year = year
        
        _transactions = Query(filter: #Predicate<Transaction> {
            Calendar.current.component(.year, from: $0.date) == year
        })
    }
    
    var body: some View {
        ScrollView {
            ...
        }
        .navigationTitle("\(year)")
    }
}

I want to get all transactions in given year but unfortunately I got the following error:

The component(_:from:) function is not supported in this predicate

The error is clear but is there a way to filter data by date in Query instead of query all the data and filter it later?


Solution

  • Find the start of the year, and the start of the next year. Then you can check if the date is between them.

    // get the current calendar using "@Environment(\.calendar) var calendar"!
    let startOfYear = calendar.date(from: .init(year: year)) ?? .distantPast
    let nextYear = DateComponents(year: year + 1)
    let startOfNextYear = calendar.date(from: nextYear) ?? .distantFuture
    _transactions = Query(filter: #Predicate<Transaction> {
        $0.date >= startOfYear && $0.date < startOfNextYear
    })