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}