1use std::collections::HashMap;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Serialize, Deserialize)]
5#[serde(rename_all = "camelCase")]
6pub struct JsonValue {
7 data_format_name: String,
8
9 value: serde_json::Value,
10
11 string: bool,
12
13 object: bool,
14
15 boolean: bool,
16
17 number: bool,
18
19 array: bool,
20
21 #[serde(rename = "null")]
22 null_val: bool,
23
24 node_type: String,
25}
26
27#[derive(Debug, Serialize, Deserialize)]
28pub struct JsonVar {
29 #[serde(rename = "value")]
30 pub json_value: JsonValue,
31
32 #[serde(rename = "valueInfo")]
33 pub value_info: HashMap<String, serde_json::Value>,
34}
35
36#[derive(Debug, Serialize, Deserialize)]
37pub struct BoolVar {
38 pub value: bool,
39
40 #[serde(rename = "valueInfo")]
41 pub value_info: HashMap<String, serde_json::Value>,
42}
43
44#[derive(Debug, Serialize, Deserialize)]
45pub struct StringVar {
46 pub value: String,
47
48 #[serde(rename = "valueInfo")]
49 pub value_info: HashMap<String, serde_json::Value>,
50}
51
52#[derive(Debug)]
53pub enum ProcessInstanceVariable {
54 Json(JsonVar),
55 Boolean(BoolVar),
56 String(StringVar),
57}
58
59impl ProcessInstanceVariable {
60 pub fn as_bool(&self) -> Option<bool> {
61 match self {
62 ProcessInstanceVariable::Boolean(b) => Some(b.value),
63 _ => None,
64 }
65 }
66 pub fn as_str(&self) -> Option<&str> {
67 match self {
68 ProcessInstanceVariable::String(s) => Some(&s.value),
69 _ => None,
70 }
71 }
72 pub fn as_json(&self) -> Option<&serde_json::Value> {
73 match self {
74 ProcessInstanceVariable::Json(j) => Some(&j.json_value.value),
75 _ => None,
76 }
77 }
78}
79
80#[derive(Deserialize)]
82pub struct Entry {
83 #[serde(rename = "type")]
84 typ: String,
85
86 #[serde(default)]
87 #[allow(dead_code)]
88 name: String,
89
90 value: serde_json::Value,
91
92 #[serde(rename = "valueInfo")]
93 value_info: HashMap<String, serde_json::Value>,
94}
95
96impl<'de> Deserialize<'de> for ProcessInstanceVariable {
97 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
98 where
99 D: serde::Deserializer<'de>,
100 {
101 let map = HashMap::<String, Entry>::deserialize(deserializer)?;
102
103 for (_, entry) in map {
106 return match entry.typ.as_str() {
107 "Json" => {
108 let json_var = JsonVar {
109 json_value: serde_json::from_value(entry.value).map_err(serde::de::Error::custom)?,
110 value_info: entry.value_info,
111 };
112 Ok(ProcessInstanceVariable::Json(json_var))
113 }
114 "Boolean" => {
115 let bool_var = BoolVar {
116 value: serde_json::from_value(entry.value).map_err(serde::de::Error::custom)?,
117 value_info: entry.value_info,
118 };
119 Ok(ProcessInstanceVariable::Boolean(bool_var))
120 },
121 "String" => {
122 let string_var = StringVar {
123 value: serde_json::from_value(entry.value).map_err(serde::de::Error::custom)?,
124 value_info: entry.value_info,
125 };
126 Ok(ProcessInstanceVariable::String(string_var))
127 },
128 _ => Err(serde::de::Error::custom(format!("unknown type: {}", entry.typ))),
129 };
130 }
131
132 Err(serde::de::Error::custom("no valid entries found"))
133 }
134}
135
136pub fn parse_process_instance_variables(json_str: &str) -> HashMap<String, ProcessInstanceVariable> {
137 fn insert_entry(result: &mut HashMap<String, ProcessInstanceVariable>, name: String, entry: Entry) {
147 let parsed_var = match entry.typ.as_str() {
148 "Json" => ProcessInstanceVariable::Json(JsonVar {
149 json_value: serde_json::from_value(entry.value).unwrap_or_else(|e| {
150 println!("Failed to parse JsonVar value for {}: {:#?}", name, e);
151 JsonValue {
153 data_format_name: String::new(),
154 value: serde_json::Value::Null,
155 string: false,
156 object: false,
157 boolean: false,
158 number: false,
159 array: false,
160 null_val: true,
161 node_type: String::new(),
162 }
163 }),
164 value_info: entry.value_info,
165 }),
166 "Boolean" => ProcessInstanceVariable::Boolean(BoolVar {
167 value: serde_json::from_value(entry.value).unwrap_or(false),
168 value_info: entry.value_info,
169 }),
170 "String" => ProcessInstanceVariable::String(StringVar {
171 value: serde_json::from_value(entry.value).unwrap_or_default(),
172 value_info: entry.value_info,
173 }),
174 _ => return,
175 };
176 result.insert(name, parsed_var);
177 }
178
179 let mut result: HashMap<String, ProcessInstanceVariable> = HashMap::new();
180
181 if let Ok(parsed_map) = serde_json::from_str::<HashMap<String, Entry>>(json_str) {
183 for (name, entry) in parsed_map {
184 insert_entry(&mut result, name, entry);
185 }
186 return result;
187 }
188
189 if let Ok(entries) = serde_json::from_str::<Vec<Entry>>(json_str) {
191 for entry in entries.into_iter() {
192 let name = if !entry.name.is_empty() { entry.name.clone() } else { continue };
193 insert_entry(&mut result, name, entry);
194 }
195 return result;
196 }
197
198 if let Ok(parsed_vec) = serde_json::from_str::<Vec<HashMap<String, Entry>>>(json_str) {
200 for map in parsed_vec.into_iter() {
201 for (name, entry) in map {
202 insert_entry(&mut result, name, entry);
203 }
204 }
205 return result;
206 }
207
208 let deser_entries = serde_json::Deserializer::from_str(json_str);
210 let mut stream_entries = deser_entries.into_iter::<Entry>();
211 let mut any_parsed = false;
212 while let Some(next) = stream_entries.next() {
213 match next {
214 Ok(entry) => {
215 if !entry.name.is_empty() {
216 let name = entry.name.clone();
217 insert_entry(&mut result, name, entry);
218 any_parsed = true;
219 }
220 }
221 Err(e) => {
222 println!("Error while parsing JSON Entry sequence chunk: {:#?}", e);
223 break;
224 }
225 }
226 }
227 if any_parsed {
228 return result;
229 }
230
231 let deser_maps = serde_json::Deserializer::from_str(json_str);
233 let mut stream_maps = deser_maps.into_iter::<HashMap<String, Entry>>();
234 while let Some(next) = stream_maps.next() {
235 match next {
236 Ok(map) => {
237 any_parsed = true;
238 for (name, entry) in map {
239 insert_entry(&mut result, name, entry);
240 }
241 }
242 Err(e) => {
243 println!("Error while parsing JSON map sequence chunk: {:#?}", e);
245 break;
246 }
247 }
248 }
249
250 if !any_parsed {
251 println!("Error while parsing \"{}\", ignoring it for now.", json_str);
252 }
253
254 result
255}
256
257#[cfg(test)]
258mod test {
259 use crate::structures::process_variables::parse_process_instance_variables;
260
261 #[test]
262 fn test_module_parsing() {
263 let response_string: &str = "{\"checklist_vj3ler\":{\"type\":\"Json\",\"value\":{\"dataFormatName\":\"application/json\",\"value\":false,\"string\":false,\"object\":false,\"boolean\":false,\"number\":false,\"array\":true,\"null\":false,\"nodeType\":\"ARRAY\"},\"valueInfo\":{}},\"checkbox_6ow5yg\":{\"type\":\"Boolean\",\"value\":true,\"valueInfo\":{}}}";
264 let variables = parse_process_instance_variables(response_string);
265 dbg!(&variables);
266 assert!(!variables.is_empty())
267 }
268
269 #[test]
270 fn test_module_parsing_complex_json_sequence() {
271 let response_string: &str = "[{\"type\":\"String\",\"value\":\"5x Vier Jahreszeiten\",\"valueInfo\":{},\"id\":\"f9bac09f-c5df-11f0-94e9-0242c0a80103\",\"name\":\"pizza_wishlist\",\"processDefinitionId\":\"OrderPizza:3:f2d157ce-c5df-11f0-94e9-0242c0a80103\",\"processInstanceId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"executionId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"caseInstanceId\":null,\"caseExecutionId\":null,\"taskId\":null,\"batchId\":null,\"activityInstanceId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"errorMessage\":null,\"tenantId\":null},{\"type\":\"String\",\"value\":\"JA\",\"valueInfo\":{},\"id\":\"f9bac0a2-c5df-11f0-94e9-0242c0a80103\",\"name\":\"mehrheit_will_pizza\",\"processDefinitionId\":\"OrderPizza:3:f2d157ce-c5df-11f0-94e9-0242c0a80103\",\"processInstanceId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"executionId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"caseInstanceId\":null,\"caseExecutionId\":null,\"taskId\":null,\"batchId\":null,\"activityInstanceId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"errorMessage\":null,\"tenantId\":null},{\"type\":\"String\",\"value\":\"JA\",\"valueInfo\":{},\"id\":\"f9bae7b5-c5df-11f0-94e9-0242c0a80103\",\"name\":\"MehrheitWillPizza\",\"processDefinitionId\":\"OrderPizza:3:f2d157ce-c5df-11f0-94e9-0242c0a80103\",\"processInstanceId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"executionId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"caseInstanceId\":null,\"caseExecutionId\":null,\"taskId\":null,\"batchId\":null,\"activityInstanceId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"errorMessage\":null,\"tenantId\":null},{\"type\":\"String\",\"value\":\"5x Vier Jahreszeiten\",\"valueInfo\":{},\"id\":\"f9bae7b7-c5df-11f0-94e9-0242c0a80103\",\"name\":\"Pizzawuensche\",\"processDefinitionId\":\"OrderPizza:3:f2d157ce-c5df-11f0-94e9-0242c0a80103\",\"processInstanceId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"executionId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"caseInstanceId\":null,\"caseExecutionId\":null,\"taskId\":null,\"batchId\":null,\"activityInstanceId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"errorMessage\":null,\"tenantId\":null},{\"type\":\"String\",\"value\":\"5x Vier Jahreszeiten\",\"valueInfo\":{},\"id\":\"f9bb0ecc-c5df-11f0-94e9-0242c0a80103\",\"name\":\"Bestellungen\",\"processDefinitionId\":\"OrderPizza:3:f2d157ce-c5df-11f0-94e9-0242c0a80103\",\"processInstanceId\":\"f2d4da42-c5df-11f0-94e9-0242c0a80103\",\"executionId\":\"f9bb0eca-c5df-11f0-94e9-0242c0a80103\",\"caseInstanceId\":null,\"caseExecutionId\":null,\"taskId\":null,\"batchId\":null,\"activityInstanceId\":\"ServiceTask_OrderPizza:f9bb0ecb-c5df-11f0-94e9-0242c0a80103\",\"errorMessage\":null,\"tenantId\":null}]";
272 let variables = parse_process_instance_variables(response_string);
273 dbg!(&variables);
274 assert!(!(variables.is_empty()))
275
276 }
277
278 #[test]
279 fn test_module_parsing_invalid() {
280 let response_string: &str = "{\"invalid\":}";
281 }
282}