Query

Trait Query 

Source
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,
        ctx: &mut QueryContext<'_>,
    ) -> Result<Self::Output, QueryError>;
    fn output_eq(old: &Self::Output, new: &Self::Output) -> bool;

    // Provided method
    fn durability(&self) -> u8 { ... }
}
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 QueryContext::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 LoadingState.

§Error Handling

The query method returns Result<Output, QueryError> where:

  • QueryError represents 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, QueryContext, 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, _ctx: &mut QueryContext) -> Result<Self::Output, QueryError> {
        Ok(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, _ctx: &mut QueryContext) -> Result<Self::Output, QueryError> {
        Ok(self.input.parse())  // Ok(Ok(n)) or Ok(Err(parse_error))
    }
}

Required Associated Types§

Source

type CacheKey: Key

The cache key type for this query.

Two queries with the same cache key are considered equivalent and will share cached results.

Source

type Output: Send + Sync + 'static

The output type of this query.

For fallible queries, use Result<T, E> here.

Required Methods§

Source

fn cache_key(&self) -> Self::CacheKey

Get the cache key for this query instance.

Source

fn query(&self, ctx: &mut QueryContext<'_>) -> Result<Self::Output, QueryError>

Execute the query, returning the output or a system error.

§Arguments
  • ctx - The query context for accessing dependencies
§Returns
  • Ok(output) - Query completed successfully
  • Err(QueryError::Suspend) - Query is waiting for async loading
  • Err(QueryError::Cycle) - Dependency cycle detected
Source

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.

Provided Methods§

Source

fn durability(&self) -> u8

Durability hint for this query.

Higher values indicate the query’s output changes less frequently. This is used for optimization in the dependency tracking layer.

  • 0: Volatile (changes frequently)
  • Higher: More stable

Default: 0 (volatile)

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.

Implementors§