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}