jql_runner/
errors.rs

1use jql_parser::errors::JqlParserError;
2use serde_json::Value;
3use thiserror::Error;
4
5static SLICE_SEP: &str = " ... ";
6static SLICE_LEN: usize = 7;
7static SEP: &str = ", ";
8
9/// Joins multiple `String`.
10fn join(values: &[String]) -> String {
11    values.join(SEP)
12}
13
14/// Shortens a JSON `Value` for error injection.
15fn shorten(json: &Value) -> String {
16    let full_json_string = json.to_string();
17
18    if full_json_string.len() < SLICE_LEN * 2 + SLICE_SEP.len() {
19        return full_json_string;
20    }
21
22    let start_slice = &full_json_string[..SLICE_LEN];
23    let end_slice = &full_json_string[full_json_string.len() - SLICE_LEN..];
24
25    [start_slice, end_slice].join(SLICE_SEP)
26}
27
28/// Returns the type of a JSON `Value`.
29fn get_json_type(json: &Value) -> &str {
30    match json {
31        Value::Array(_) => "array",
32        Value::Bool(_) => "boolean",
33        Value::Null => "null",
34        Value::Number(_) => "number",
35        Value::Object(_) => "object",
36        Value::String(_) => "string",
37    }
38}
39
40/// Error type returned by the runner.
41#[derive(Debug, Error, PartialEq)]
42pub enum JqlRunnerError {
43    /// Empty query error.
44    #[error("Query is empty")]
45    EmptyQueryError,
46
47    /// Flatten error.
48    #[error("Value {0} is neither an array nor an object and can't be flattened")]
49    FlattenError(Value),
50
51    /// Index out of bounds error.
52    #[error("Index {index} in parent {parent} is out of bounds")]
53    IndexOutOfBoundsError {
54        /// Index.
55        index: usize,
56        /// Parent value.
57        parent: Value,
58    },
59
60    /// Invalid array error.
61    #[error("Value {} is not a JSON array ({})", .0, get_json_type(.0))]
62    InvalidArrayError(Value),
63
64    /// Invalid object error.
65    #[error("Value {} is not a JSON object ({})", .0, get_json_type(.0))]
66    InvalidObjectError(Value),
67
68    /// Key not found error.
69    #[error(r#"Key "{key}" doesn't exist in parent {}"#, shorten(parent))]
70    KeyNotFoundError {
71        /// Key not found.
72        key: String,
73        /// Parent value.
74        parent: Value,
75    },
76
77    /// Keys not found error.
78    #[error("Keys {} don't exist in parent {}", join(keys), shorten(parent))]
79    MultiKeyNotFoundError {
80        /// Keys not found.
81        keys: Vec<String>,
82        /// Parent value.
83        parent: Value,
84    },
85
86    /// Parsing error.
87    #[error(transparent)]
88    ParsingError(#[from] JqlParserError),
89
90    /// Pipe in error.
91    #[error("Pipe in operator used on {0} which is not an array")]
92    PipeInError(Value),
93
94    /// Pipe in error.
95    #[error("Pipe out operator used without a preceding pipe in operator")]
96    PipeOutError,
97
98    /// Range out of bounds error.
99    #[error("Range [{start}:{end}] in parent {parent} is out of bounds")]
100    RangeOutOfBoundsError {
101        /// Start range.
102        start: usize,
103        /// End range.
104        end: usize,
105        /// parent value.
106        parent: Value,
107    },
108
109    /// Unknown error.
110    #[error("Unknown error")]
111    UnknownError,
112}
113
114#[cfg(test)]
115mod tests {
116
117    use serde_json::json;
118
119    use super::{
120        get_json_type,
121        join,
122        shorten,
123    };
124
125    #[test]
126    fn check_get_json_type() {
127        assert_eq!(get_json_type(&json!([])), "array");
128        assert_eq!(get_json_type(&json!(true)), "boolean");
129        assert_eq!(get_json_type(&json!(null)), "null");
130        assert_eq!(get_json_type(&json!(1)), "number");
131        assert_eq!(get_json_type(&json!({})), "object");
132        assert_eq!(get_json_type(&json!("a")), "string");
133    }
134
135    #[test]
136    fn check_join() {
137        assert_eq!(
138            join(&["a".to_string(), "b".to_string(), "c".to_string()]),
139            "a, b, c".to_string()
140        );
141    }
142
143    #[test]
144    fn check_shorten() {
145        assert_eq!(shorten(&json!("thismakesnosense")), r#""thismakesnosense""#);
146        assert_eq!(
147            shorten(&json!({ "a": { "b": { "c": [1, 2 ,3, 4, 5, 6, 7, 8, 9] } } })),
148            r#"{"a":{" ... 8,9]}}}"#.to_string()
149        );
150    }
151}