Skip to main content

teaql_tool_std/
json.rs

1use json_patch::{Patch, diff, patch};
2use serde_json::{Value, from_str};
3use teaql_tool_core::{MustPurpose, Result, TeaQLToolError};
4
5pub struct JsonTool;
6
7impl JsonTool {
8    pub fn new() -> Self {
9        Self
10    }
11
12    pub fn parse(&self, s: &str) -> Result<MustPurpose<Value>> {
13        from_str(s)
14            .map(MustPurpose::new)
15            .map_err(|e| TeaQLToolError::ParseError(e.to_string()))
16    }
17
18    pub fn stringify(&self, v: &Value) -> Result<MustPurpose<String>> {
19        serde_json::to_string(v)
20            .map(MustPurpose::new)
21            .map_err(|e| TeaQLToolError::ParseError(e.to_string()))
22    }
23
24    pub fn stringify_pretty(&self, v: &Value) -> Result<MustPurpose<String>> {
25        serde_json::to_string_pretty(v)
26            .map(MustPurpose::new)
27            .map_err(|e| TeaQLToolError::ParseError(e.to_string()))
28    }
29
30    pub fn get<'a>(&self, v: &'a Value, pointer: &str) -> MustPurpose<Option<&'a Value>> {
31        MustPurpose::new(v.pointer(pointer))
32    }
33
34    pub fn set(&self, v: &mut Value, pointer: &str, value: Value) -> Result<MustPurpose<()>> {
35        let ptr = v.pointer_mut(pointer);
36        if let Some(target) = ptr {
37            *target = value;
38            Ok(MustPurpose::new(()))
39        } else {
40            // Very naive way, json_patch provides add but pointer_mut requires path to exist
41            let p = format!(
42                r#"[{{"op": "add", "path": "{}", "value": {}}}]"#,
43                pointer, value
44            );
45            let patch_obj = serde_json::from_str::<Patch>(&p).unwrap();
46            self.patch(v, &patch_obj)
47        }
48    }
49
50    pub fn remove(&self, v: &mut Value, pointer: &str) -> Result<MustPurpose<()>> {
51        let p = format!(r#"[{{"op": "remove", "path": "{}"}}]"#, pointer);
52        let patch_obj = serde_json::from_str::<Patch>(&p).unwrap();
53        self.patch(v, &patch_obj)
54    }
55
56    pub fn has(&self, v: &Value, pointer: &str) -> MustPurpose<bool> {
57        MustPurpose::new(v.pointer(pointer).is_some())
58    }
59
60    pub fn merge(&self, a: &Value, b: &Value) -> MustPurpose<Value> {
61        let mut result = a.clone();
62        if let (Value::Object(r), Value::Object(b_obj)) = (&mut result, b) {
63            for (k, v) in b_obj {
64                r.insert(k.clone(), v.clone());
65            }
66        }
67        MustPurpose::new(result)
68    }
69
70    pub fn diff(&self, a: &Value, b: &Value) -> MustPurpose<Patch> {
71        MustPurpose::new(diff(a, b))
72    }
73
74    pub fn patch(&self, v: &mut Value, p: &Patch) -> Result<MustPurpose<()>> {
75        patch(v, p)
76            .map(|_| MustPurpose::new(()))
77            .map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))
78    }
79}
80
81impl Default for JsonTool {
82    fn default() -> Self {
83        Self::new()
84    }
85}