routee_compass/plugin/input/
input_plugin_ops.rs1use indoc::indoc;
2use serde_json::{json, Value};
3use std::rc::Rc;
4
5use super::InputPluginError;
6
7pub fn package_error<E: ToString>(query: &mut Value, error: E) -> Value {
10 json!({
11 "request": query,
12 "error": error.to_string()
13 })
14}
15
16pub fn package_invariant_error(query: Option<&mut Value>, sub_section: Option<&Value>) -> Value {
17 let intro = indoc! {r#"
18 an input plugin has broken the invariant of the query state which requires
19 that the query's JSON representation has a top-level JSON Array ([]) whose only
20 elements are JSON objects ({}). please confirm that all included InputPlugin
21 instances do not break this invariant.
22 "#
23 };
24
25 let json_msg = match query {
26 None => String::from(
27 "unable to display query state as it may have been modified during this process.",
28 ),
29 Some(ref q) => {
30 let json_intro = "here is the invalid query state that was found:";
31 let json = serde_json::to_string_pretty(q).unwrap_or_else(|e| {
32 format!("oops, i can't even serialize that query because of an error: {e}")
33 });
34 format!("{json_intro}\n\n{json}")
35 }
36 };
37
38 let msg = match sub_section {
39 None => format!("{intro}\n{json_msg}"),
40 Some(ss) => {
41 let ss_msg = "error triggered by the following sub-section:";
42 let ss_json = serde_json::to_string_pretty(&ss).unwrap_or_else(|e| {
43 format!("oops, i can't even serialize that sub-section because of an error: {e}")
44 });
45
46 format!("{intro}\n\n{json_msg}\n\n{ss_msg}\n\n{ss_json}")
47 }
48 };
49
50 match query {
51 Some(q) => package_error(q, msg),
52 None => package_error(&mut json![{"error": "unable to display query"}], msg),
53 }
54}
55
56pub type InputArrayOp<'a> = Rc<dyn Fn(&mut Value) -> Result<(), InputPluginError> + 'a>;
57
58pub fn json_array_op<'a>(query: &'a mut Value, op: InputArrayOp<'a>) -> Result<(), Value> {
63 match query {
64 Value::Array(queries) => {
65 for q in queries.iter_mut() {
66 op(q).map_err(|e| package_error(q, e))?;
67 }
68 json_array_flatten_in_place(query)
69 }
70 other => {
71 let error = package_invariant_error(None, Some(other));
72 Err(error)
73 }
74 }
75}
76
77pub fn json_array_flatten_in_place(result: &mut Value) -> Result<(), Value> {
81 if let Value::Array(top_array) = result {
82 if top_array.iter().all(|v| !v.is_array()) {
83 return Ok(());
85 }
86
87 let mut flattened: Vec<&mut Value> = vec![];
89 for v1 in top_array.iter_mut() {
90 match v1 {
91 Value::Array(sub_array) => {
92 for v2 in sub_array.iter_mut() {
93 flattened.push(v2)
94 }
95 }
96 other => flattened.push(other),
97 }
98 }
99 let mut flat_result = json![flattened];
100 std::mem::swap(result, &mut flat_result);
101 Ok(())
102 } else {
103 let error_response = package_invariant_error(Some(result), None);
104 Err(error_response)
105 }
106}
107
108pub fn json_array_flatten(result: &mut Value) -> Result<Vec<Value>, Value> {
112 let mut flattened: Vec<Value> = vec![];
113 if !result.is_array() {
114 let error_response = package_invariant_error(Some(result), None);
115 return Err(error_response);
116 }
117 let mut error: Option<&mut Value> = None;
118 match result {
119 Value::Array(sub_array) => {
120 for sub_obj in sub_array.iter_mut() {
121 match sub_obj {
122 Value::Object(obj) => {
123 flattened.push(json![obj]);
124 }
125 other => {
126 error = Some(other);
127 }
128 }
129 }
130 }
131 other => {
132 error = Some(other);
133 }
134 }
135
136 match error {
137 Some(err) => {
138 let error_response = package_invariant_error(None, Some(err));
139 Err(error_response)?
140 }
141 None => Ok(flattened),
142 }
143}
144
145pub fn unpack_json_array_as_vec(result: &Value) -> Vec<Value> {
149 let mut error: Option<&Value> = None;
150 match result {
151 Value::Array(sub_array) => {
152 let mut flattened: Vec<Value> = vec![];
153 for sub_obj in sub_array.iter() {
154 match sub_obj {
155 Value::Object(obj) => {
156 flattened.push(json![obj]);
157 }
158 other => {
159 error = Some(other);
160 }
161 }
162 }
163 match error {
164 Some(_) => {
165 let error_response = package_invariant_error(None, error);
166 vec![error_response]
167 }
168 None => flattened,
169 }
170 }
171 _ => vec![result.clone()],
172 }
173}