query_flow/
error.rs

1//! Error types for query execution.
2
3use std::fmt;
4use std::sync::Arc;
5
6/// Query errors including both system-level and user errors.
7///
8/// User errors can be propagated using the `?` operator, which automatically
9/// converts any `Into<anyhow::Error>` type into `QueryError::UserError`.
10#[derive(Debug, Clone)]
11pub enum QueryError {
12    /// Query is waiting for async loading to complete.
13    ///
14    /// This is returned when a dependency is still loading via a background task.
15    /// Use `runtime.query_async()` to wait for loading to complete, or handle
16    /// explicitly in your query logic.
17    Suspend,
18
19    /// Dependency cycle detected.
20    ///
21    /// The query graph contains a cycle, which would cause infinite recursion.
22    /// The `path` contains a debug representation of the cycle.
23    Cycle {
24        /// Debug representation of the queries forming the cycle.
25        path: Vec<String>,
26    },
27
28    /// Query execution was cancelled.
29    Cancelled,
30
31    /// A required dependency is missing.
32    MissingDependency {
33        /// Description of the missing dependency.
34        description: String,
35    },
36
37    /// User-defined error.
38    ///
39    /// This variant allows user errors to be propagated through the query system
40    /// using the `?` operator. Any type implementing `Into<anyhow::Error>` can be
41    /// converted to this variant.
42    ///
43    /// Unlike system errors (Suspend, Cycle, etc.), UserError results are cached
44    /// and participate in early cutoff optimization.
45    UserError(Arc<anyhow::Error>),
46}
47
48impl fmt::Display for QueryError {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        match self {
51            QueryError::Suspend => write!(f, "query suspended: waiting for async loading"),
52            QueryError::Cycle { path } => {
53                write!(f, "dependency cycle detected: {}", path.join(" -> "))
54            }
55            QueryError::Cancelled => write!(f, "query cancelled"),
56            QueryError::MissingDependency { description } => {
57                write!(f, "missing dependency: {}", description)
58            }
59            QueryError::UserError(e) => write!(f, "user error: {}", e),
60        }
61    }
62}
63
64impl<T: Into<anyhow::Error>> From<T> for QueryError {
65    fn from(err: T) -> Self {
66        QueryError::UserError(Arc::new(err.into()))
67    }
68}