zen_engine/
error.rs

1use crate::engine::EvaluationTraceKind;
2use crate::handler::graph::DecisionGraphValidationError;
3pub use crate::handler::node::NodeError;
4use crate::loader::LoaderError;
5use jsonschema::{ErrorIterator, ValidationError};
6use serde::ser::SerializeMap;
7use serde::{Serialize, Serializer};
8use serde_json::{Map, Value};
9use std::iter::once;
10use thiserror::Error;
11
12#[derive(Debug, Error)]
13pub enum EvaluationError {
14    #[error("Loader error")]
15    LoaderError(LoaderError),
16
17    #[error("Node error")]
18    NodeError(NodeError),
19
20    #[error("Depth limit exceeded")]
21    DepthLimitExceeded,
22
23    #[error("Invalid graph")]
24    InvalidGraph(DecisionGraphValidationError),
25
26    #[error("Validation failed")]
27    Validation(Value),
28}
29
30impl EvaluationError {
31    pub fn serialize_with_mode<S>(
32        &self,
33        serializer: S,
34        mode: EvaluationTraceKind,
35    ) -> Result<S::Ok, S::Error>
36    where
37        S: Serializer,
38    {
39        let mut map = serializer.serialize_map(None)?;
40
41        match self {
42            EvaluationError::DepthLimitExceeded => {
43                map.serialize_entry("type", "DepthLimitExceeded")?;
44            }
45            EvaluationError::NodeError(err) => {
46                map.serialize_entry("type", "NodeError")?;
47
48                match err {
49                    NodeError::Internal => map.serialize_entry("source", "Internal")?,
50                    NodeError::Other(o) => map.serialize_entry("source", &o.to_string())?,
51                    NodeError::Display(d) => map.serialize_entry("source", d.as_str())?,
52                    NodeError::Node {
53                        node_id,
54                        source,
55                        trace,
56                    } => {
57                        map.serialize_entry("nodeId", node_id.as_str())?;
58                        map.serialize_entry("source", &source.to_string())?;
59                        if let Some(trace) = &trace {
60                            map.serialize_entry("trace", &mode.serialize_trace(trace))?;
61                        }
62                    }
63                    NodeError::PartialTrace { trace, message } => {
64                        map.serialize_entry("source", message.as_str())?;
65                        if let Some(trace) = &trace {
66                            map.serialize_entry("trace", &mode.serialize_trace(trace))?;
67                        }
68                    }
69                }
70            }
71            EvaluationError::LoaderError(err) => {
72                map.serialize_entry("type", "LoaderError")?;
73                match err {
74                    LoaderError::Internal { key, source } => {
75                        map.serialize_entry("key", key)?;
76                        map.serialize_entry("source", &source.to_string())?;
77                    }
78                    LoaderError::NotFound(key) => {
79                        map.serialize_entry("key", key)?;
80                    }
81                }
82            }
83            EvaluationError::InvalidGraph(err) => {
84                map.serialize_entry("type", "InvalidGraph")?;
85                map.serialize_entry("source", err)?;
86            }
87            EvaluationError::Validation(err) => {
88                map.serialize_entry("type", "Validation")?;
89                map.serialize_entry("source", err)?;
90            }
91        }
92
93        map.end()
94    }
95}
96
97impl Serialize for EvaluationError {
98    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
99    where
100        S: Serializer,
101    {
102        self.serialize_with_mode(serializer, Default::default())
103    }
104}
105
106impl From<LoaderError> for Box<EvaluationError> {
107    fn from(error: LoaderError) -> Self {
108        Box::new(EvaluationError::LoaderError(error.into()))
109    }
110}
111
112impl From<NodeError> for Box<EvaluationError> {
113    fn from(value: NodeError) -> Self {
114        Box::new(EvaluationError::NodeError(value))
115    }
116}
117
118impl From<DecisionGraphValidationError> for Box<EvaluationError> {
119    fn from(error: DecisionGraphValidationError) -> Self {
120        Box::new(EvaluationError::InvalidGraph(error.into()))
121    }
122}
123
124#[derive(Serialize)]
125#[serde(rename_all = "camelCase")]
126struct ValidationErrorJson {
127    path: String,
128    message: String,
129}
130
131impl<'a> From<ValidationError<'a>> for ValidationErrorJson {
132    fn from(value: ValidationError<'a>) -> Self {
133        ValidationErrorJson {
134            path: value.instance_path.to_string(),
135            message: format!("{}", value),
136        }
137    }
138}
139
140impl<'a> From<ErrorIterator<'a>> for Box<EvaluationError> {
141    fn from(error_iter: ErrorIterator<'a>) -> Self {
142        let errors: Vec<ValidationErrorJson> = error_iter.into_iter().map(From::from).collect();
143
144        let mut json_map = Map::new();
145        json_map.insert(
146            "errors".to_string(),
147            serde_json::to_value(errors).unwrap_or_default(),
148        );
149
150        Box::new(EvaluationError::Validation(Value::Object(json_map)))
151    }
152}
153
154impl<'a> From<ValidationError<'a>> for Box<EvaluationError> {
155    fn from(value: ValidationError<'a>) -> Self {
156        let iterator: ErrorIterator<'a> = Box::new(once(value));
157        Box::<EvaluationError>::from(iterator)
158    }
159}