Best practice for centralizing SwiftData query logic and actions in an @Observable manager?

I'm building a SwiftUI app with SwiftData and want to centralize both query logic and related actions in a manager class. For example, let's say I have a reading app where I need to track the currently reading book across multiple views.

What I want to achieve:

@Observable
class ReadingManager {
    let modelContext: ModelContext
    
    // Ideally, I'd love to do this:
    @Query(filter: #Predicate<Book> { $0.isCurrentlyReading })
    var currentBooks: [Book]  // ❌ But @Query doesn't work here
    
    var currentBook: Book? {
        currentBooks.first
    }
    
    func startReading(_ book: Book) {
        // Stop current book if any
        if let current = currentBook {
            current.isCurrentlyReading = false
        }
        book.isCurrentlyReading = true
        try? modelContext.save()
    }
    
    func stopReading() {
        currentBook?.isCurrentlyReading = false
        try? modelContext.save()
    }
}

// Then use it cleanly in any view:
struct BookRow: View {
    @Environment(ReadingManager.self) var manager
    let book: Book
    
    var body: some View {
        Text(book.title)
        Button("Start Reading") {
            manager.startReading(book)
        }
        if manager.currentBook == book {
            Text("Currently Reading")
        }
    }
}

The problem is @Query only works in SwiftUI views. Without the manager, I'd need to duplicate the same query in every view just to call these common actions.

Is there a recommended pattern for this? Or should I just accept query duplication across views as the intended SwiftUI/SwiftData approach?

Best practice for centralizing SwiftData query logic and actions in an &#64;Observable manager?
 
 
Q