flatten_json/
lib.rs

1#[macro_use]
2extern crate serde_json;
3#[macro_use]
4extern crate error_chain;
5#[macro_use]
6extern crate log;
7
8use serde_json::value::Value;
9use serde_json::map::Map;
10
11error_chain! {
12foreign_links {
13        Json(::serde_json::Error);
14    }
15}
16
17pub fn flatten(nested_value: &Value, flat_value: &mut Value, parent_key: Option<String>, infer_type: bool, separator: Option<&str>) -> Result<()> {
18    // if object
19    if let Some(nested_dict) = nested_value.as_object() {
20        flatten_object(flat_value, &parent_key, nested_dict, infer_type, separator)?;
21    } else if let Some(v_array) = nested_value.as_array() {
22        let new_k = parent_key.unwrap_or_else(||String::from(""));
23        flatten_array(flat_value, &new_k, v_array, infer_type, separator)?;
24    } else {
25        error!("Expected object, found something else: {:?}", nested_value)
26    }
27    Ok(())
28}
29
30
31fn flatten_object(flat_value: &mut Value, parent_key: &Option<String>, nested_dict: &Map<String, Value>, infer_type: bool, separator: Option<&str>) -> Result<()> {
32    let sep = if let Some(sep) = separator {
33        sep
34    } else {
35        "."
36    };
37    
38    for (k, v) in nested_dict.iter() {
39        let new_k = match parent_key {
40            Some(ref key) => format!("{}{}{}", key, sep, k),
41            None => k.clone()
42        };
43        // if nested value is object recurse with parent_key
44        if let Some(obj) = v.as_object() {
45            flatten_object(flat_value, &Some(new_k), obj, infer_type, separator)?;
46            // if array
47        } else if let Some(v_array) = v.as_array() {
48            // if array is not empty
49            if !v_array.is_empty() {
50                // traverse array
51                flatten_array(flat_value, &new_k, v_array, infer_type, separator)?;
52                // if array is empty insert empty array into flat_value
53            } else if let Some(value) = flat_value.as_object_mut() {
54                let empty: Vec<Value> = vec!();
55                value.insert(k.to_string(), json!(empty));
56            }
57            // if no object or array insert value into the flat_value we're building
58        } else if let Some(value) = flat_value.as_object_mut() {
59            infer_type_and_insert(v, new_k, value, infer_type)?;
60        }
61    }
62    Ok(())
63}
64
65fn infer_type_and_insert(v: &Value, new_k: String, value: &mut Map<String, Value>, infer_type: bool) -> Result<()> {
66    let new_val;
67    if infer_type {
68        if let Some(string) = v.as_str() {
69            new_val = match string.parse::<i64>() {
70                Ok(i) => serde_json::to_value(i)?,
71                Err(_) => match string.parse::<f64>() {
72                    Ok(f) => serde_json::to_value(f)?,
73                    Err(_) => match string.parse::<bool>() {
74                        Ok(b) => serde_json::to_value(b)?,
75                        Err(_) => serde_json::to_value(string)?
76                    }
77                }
78            };
79        } else {
80            new_val = v.clone();
81        }
82    } else {
83        new_val = v.clone();
84    };
85    value.insert(new_k, new_val);
86    Ok(())
87}
88
89fn flatten_array(flat_value: &mut Value, new_k: &str, v_array: &[Value], infer_type: bool, separator: Option<&str>) -> Result<()> {
90    for (i, obj) in v_array.iter().enumerate() {
91        let array_key = format!("{}.{}", new_k, i);
92        // if element is object or array recurse
93        if obj.is_object() | obj.is_array() {
94            flatten(obj, flat_value, Some(array_key), infer_type, separator)?;
95            // else insert value in the flat_value we're building
96        } else if let Some(value) = flat_value.as_object_mut() {
97            infer_type_and_insert(obj, array_key, value, infer_type)?;
98        }
99    }
100    Ok(())
101}
102
103#[cfg(test)]
104mod tests {
105    use super::flatten;
106
107    #[test]
108    fn single_key_value() {
109        let obj = json!({"key": "value"});
110
111        let mut flat = json!({});
112        flatten(&obj, &mut flat, None, true, None).unwrap();
113        assert_eq!(obj, json!(flat));
114    }
115
116    #[test]
117    fn single_int_value() {
118        let obj = json!({"key": 1});
119
120        let mut flat = json!({});
121        flatten(&obj, &mut flat, None, true, None).unwrap();
122        assert_eq!(json!({"key": 1}), json!(flat));
123    }
124
125    #[test]
126    fn single_int_as_str_value() {
127        let obj = json!({"key": "1"});
128
129        let mut flat = json!({});
130        flatten(&obj, &mut flat, None, true, None).unwrap();
131        assert_eq!(json!({"key": 1}), json!(flat));
132    }
133
134    #[test]
135    fn single_int_as_str_no_infer_type_value() {
136        let obj = json!({"key": "1"});
137
138        let mut flat = json!({});
139        flatten(&obj, &mut flat, None, false, None).unwrap();
140        assert_eq!(json!({"key": "1"}), json!(flat));
141    }
142
143    #[test]
144    fn single_float_as_str_value() {
145        let obj = json!({"key": "1.0"});
146
147        let mut flat = json!({});
148        flatten(&obj, &mut flat, None, true, None).unwrap();
149        assert_eq!(json!({"key": 1.}), json!(flat));
150    }
151
152    #[test]
153    fn single_bool_as_str_value() {
154        let obj = json!({"key": "true"});
155
156        let mut flat = json!({});
157        flatten(&obj, &mut flat, None, true, None).unwrap();
158        assert_eq!(json!({"key": true}), json!(flat));
159    }
160
161    #[test]
162    fn multi_key_value() {
163        let obj = json!({"key1": "value1", "key2": "value2"});
164
165        let mut flat = json!({});
166        flatten(&obj, &mut flat, None, true, None).unwrap();
167        assert_eq!(obj, json!(flat));
168    }
169
170    #[test]
171    fn nested_single_key_value() {
172        let obj = json!({"key": "value", "nested_key": {"key":"value"}});
173
174        let mut flat = json!({});
175        flatten(&obj, &mut flat, None, true, None).unwrap();
176        assert_eq!(json!({"key": "value", "nested_key.key": "value"}), json!(flat));
177    }
178
179
180    #[test]
181    fn nested_multiple_key_value() {
182        let obj = json!({"key": "value", "nested_key": {"key1":"value1", "key2": "value2"}});
183
184        let mut flat = json!({});
185        flatten(&obj, &mut flat, None, true, None).unwrap();
186        assert_eq!(json!({"key": "value", "nested_key.key1": "value1", "nested_key.key2": "value2"}), json!(flat));
187    }
188
189    #[test]
190    fn top_level_array() {
191        let obj = json!(["value1", "value2"]);
192
193        let mut flat = json!({});
194        flatten(&obj, &mut flat, None, true, None).unwrap();
195        assert_eq!(json!({".0": "value1", ".1": "value2"}), json!(flat));
196    }
197
198    #[test]
199    fn nested_array() {
200        let obj = json!({"key": ["value1", "value2"]});
201
202        let mut flat = json!({});
203        flatten(&obj, &mut flat, None, true, None).unwrap();
204        assert_eq!(json!({"key.0": "value1", "key.1": "value2"}), json!(flat));
205    }
206
207    #[test]
208    fn nested_obj_array() {
209        let obj = json!({"key": ["value1", {"key": "value2"}]});
210
211        let mut flat = json!({});
212        flatten(&obj, &mut flat, None, true, None).unwrap();
213        assert_eq!(json!({"key.0": "value1", "key.1.key": "value2"}), json!(flat));
214    }
215
216    #[test]
217    fn complex_nested_struct() {
218        let obj = json!({"simple_key": "simple_value", "key": ["value1", {"key": "value2"}, {"nested_array": ["nested1", "nested2", ["nested3", "nested4"]]}]});
219
220        let mut flat = json!({});
221        flatten(&obj, &mut flat, None, true, None).unwrap();
222        assert_eq!(json!({"simple_key": "simple_value", "key.0": "value1", "key.1.key": "value2", "key.2.nested_array.0": "nested1", "key.2.nested_array.1": "nested2", "key.2.nested_array.2.0": "nested3", "key.2.nested_array.2.1": "nested4"}), json!(flat));
223    }
224}