pub trait Query:
Clone
+ Send
+ Sync
+ 'static {
type CacheKey: Key;
type Output: Send + Sync + 'static;
// Required methods
fn cache_key(&self) -> Self::CacheKey;
fn query(self, db: &impl Db) -> Result<Arc<Self::Output>, QueryError>;
fn output_eq(old: &Self::Output, new: &Self::Output) -> bool;
}Expand description
A query that can be executed and cached.
Queries are the fundamental unit of computation in query-flow. Each query:
- Has a cache key that uniquely identifies the computation
- Produces an output value
- Can depend on other queries via
db.query()
§Sync by Design
The query method is intentionally synchronous. This avoids the “function
coloring” problem where async infects the entire call stack. For async
operations, use the suspense pattern with AssetLoadingState.
§Error Handling
The query method returns Result<Output, QueryError> where:
QueryErrorrepresents system errors (Suspend, Cycle, Cancelled)- User domain errors should be wrapped in
Output, e.g.,type Output = Result<T, MyError>
This means fallible queries return Ok(Ok(value)) on success and Ok(Err(error)) on user error.
§Example
use query_flow::{Query, Db, QueryError, Key};
// Simple infallible query
struct Add { a: i32, b: i32 }
impl Query for Add {
type CacheKey = (i32, i32);
type Output = i32;
fn cache_key(&self) -> Self::CacheKey {
(self.a, self.b)
}
fn query(self, _db: &impl Db) -> Result<Arc<Self::Output>, QueryError> {
Ok(Arc::new(self.a + self.b))
}
}
// Fallible query with user errors
struct ParseInt { input: String }
impl Query for ParseInt {
type CacheKey = String;
type Output = Result<i32, std::num::ParseIntError>;
fn cache_key(&self) -> Self::CacheKey {
self.input.clone()
}
fn query(self, _db: &impl Db) -> Result<Arc<Self::Output>, QueryError> {
Ok(Arc::new(self.input.parse())) // Ok(Arc(Ok(n))) or Ok(Arc(Err(parse_error)))
}
}Required Associated Types§
Required Methods§
Sourcefn query(self, db: &impl Db) -> Result<Arc<Self::Output>, QueryError>
fn query(self, db: &impl Db) -> Result<Arc<Self::Output>, QueryError>
Execute the query, returning the output wrapped in Arc or a system error.
The result is wrapped in Arc for efficient sharing in the cache.
Use the #[query] macro to automatically handle Arc wrapping.
§Arguments
db- The database for accessing dependencies
§Returns
Ok(arc_output)- Query completed successfullyErr(QueryError::Suspend)- Query is waiting for async loadingErr(QueryError::Cycle)- Dependency cycle detected
Sourcefn output_eq(old: &Self::Output, new: &Self::Output) -> bool
fn output_eq(old: &Self::Output, new: &Self::Output) -> bool
Compare two outputs for equality (for early cutoff optimization).
When a query is recomputed and the output is equal to the previous output, downstream queries can skip recomputation (early cutoff).
The #[query] macro generates this using PartialEq by default.
Use output_eq = custom_fn for types without PartialEq.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.