Search code examples
swiftdata

Where to put complex or shared SwiftData queries?


https://developer.apple.com/documentation/swiftdata/filtering-and-sorting-persistent-data provides instructions for using @Query inside a View.

But, what do I do if the query is complex or I want to share it b/w multiple Views?

Can I define it on the @Model class itself? Somewhere else other than the View? Or, is it best practice to specify all queries and subsequent data processing within each View and duplicate it for any other Views that depend on the same query?


Solution

  • Since each query is for a specific model class it feels only natural to define them on the model itself. Now a @Query can't be used outside of a view so it's better to work with a Predicate or a FetchDescriptor.

    I use the latter so that is what my examples below returns a FetchDescriptor.

    I declare my static queries as static variable and the dynamic ones as static functions

    For instance

    @Model
    final class MyModel {
        var isActive: Bool
        //...
    }
    

    I prefer to move the queries to a separate extension

    extension MyModel {
    
        static var activeModels: FetchDescriptor<MyModel> {
            FetchDescriptor(predicate: #Predicate<MyModel> { $0.isActive }) 
        }
    
        static func fetch(active: Bool) -> FetchDescriptor<MyModel> {
            FetchDescriptor(predicate: #Predicate<MyModel> { $0.isActive == active }) 
        }
    }
    

    And a solution like this can then be used in a view or when fetching outside a view in the same manner

    @Query(MyModel.activeModels) private var allActive: [MyModel]
    

    or

    let active = modelContext.fetch(MyModel.activeModels)