serde_filter/
flatten.rs

1pub use self::Flattener as Flatten;
2use serde_json::{Map, Value};
3
4pub struct Flattener {
5    delimiter: char,
6}
7
8impl Default for Flattener {
9    fn default() -> Self {
10        Self { delimiter: '.' }
11    }
12}
13
14impl Flattener {
15    pub fn new(delimiter: char) -> Self {
16        Self { delimiter }
17    }
18    fn flatten_map(&self, map: &Map<String, Value>, prefix: &str, result: &mut Map<String, Value>) {
19        for (k, v) in map.iter() {
20            let new_pref = if prefix.is_empty() {
21                k.clone()
22            } else {
23                format!("{}{}{}", prefix, self.delimiter, k)
24            };
25            match v {
26                serde_json::Value::Object(inner) => {
27                    self.flatten_map(inner, &new_pref, result);
28                }
29                serde_json::Value::Array(arr) => {
30                    self.flatten_array(arr, &new_pref, result);
31                }
32                _ => {
33                    result.insert(new_pref, v.clone());
34                }
35            }
36        }
37    }
38    fn flatten_array(
39        &self,
40        array: &[serde_json::Value],
41        prefix: &str,
42        result: &mut Map<String, Value>,
43    ) {
44        for (index, value) in array.iter().enumerate() {
45            let new_prefix = format!("{}{}{}", prefix, self.delimiter, index);
46            match value {
47                serde_json::Value::Object(inner_map) => {
48                    self.flatten_map(inner_map, &new_prefix, result);
49                }
50                serde_json::Value::Array(inner_array) => {
51                    self.flatten_array(inner_array, &new_prefix, result);
52                }
53                _ => {
54                    result.insert(new_prefix, value.clone());
55                }
56            }
57        }
58    }
59}
60
61impl crate::filter::Filter for Flattener {
62    type Output = Value;
63
64    fn filter(&self, json: Value) -> Result<Self::Output, anyhow::Error> {
65        let mut result = Map::new();
66        match json {
67            Value::Object(map) => {
68                self.flatten_map(&map, "", &mut result);
69            }
70            Value::Array(arr) => {
71                self.flatten_array(&arr, "", &mut result);
72            }
73            _ => {
74                return Err(anyhow::anyhow!(
75                    "Flattener can only be used on objects or arrays"
76                ))
77            }
78        }
79        return Ok(Value::Object(result));
80    }
81}
82
83#[cfg(test)]
84mod flatten_test {
85    use super::*;
86    use crate::prelude::{filter, Filter};
87
88    #[test]
89    fn test_flatten() {
90        let json = serde_json::json!({
91          "a": {
92            "b": {
93              "c": {
94                "d": "value"
95              }
96            }
97          },
98          "e": "value"
99        });
100
101        let expected = serde_json::json!({
102          "a.b.c.d": "value",
103          "e": "value"
104        });
105
106        let result = filter::<Flatten>(json, &Flatten::default()).unwrap();
107        println!("{:?}", result);
108        assert_eq!(result, expected);
109    }
110}