1use serde_json::{Value, Map, json};
18use crate::errors;
19
20
21pub fn flatten(value: &Value) -> Result<Map<String, Value>, errors::Error> {
32 let mut flattened_json = Map::<String, Value>::new();
33
34 match value {
35 Value::Object(map) => {
36 if map.is_empty() {
37 return Ok(flattened_json);
38 }
39 flatten_object(&mut flattened_json, None, map)?;
40 }
41 _ => return Err(errors::Error::NotAnObject),
42 }
43
44
45 Ok(flattened_json)
46}
47
48fn flatten_object(result: &mut Map<String, Value>, property: Option<&str>, nested_json: &Map<String, Value>) -> Result<(), errors::Error>{
49 for (prop, value) in nested_json {
50 let flattened_prop = property.map_or_else(|| prop.clone(), |parent_key| format!("{}.{}", parent_key, prop));
51
52 match value {
53 Value::Array(array) => flatten_array(result, &flattened_prop, array),
54 Value::Object(sub_json) => flatten_object(result, Some(&flattened_prop), sub_json),
55 _ => flatten_value(result, &flattened_prop, value.clone()),
56 }?
57 }
58
59 Ok(())
60}
61
62fn flatten_array(result: &mut Map<String, Value>, property: &str, array: &Vec<Value>) -> Result<(), errors::Error> {
63 for (i, value) in array.iter().enumerate() {
64 let flattened_prop = format!("{}[{}]", property, i);
65
66 match value {
67 Value::Object(sub_json) => flatten_object(result, Some(&flattened_prop), sub_json),
68 Value::Array(sub_array) => flatten_array(result, &flattened_prop, sub_array),
69 _ => flatten_value(result, &flattened_prop, value.clone()),
70 }?
71 }
72
73 Ok(())
74}
75
76fn flatten_value(result: &mut Map<String, Value>, property: &str, val: Value) -> Result<(), errors::Error> {
77
78 if val.is_object() || val.is_array() {
79 return Err(errors::Error::NotAValue);
80 }
81
82 if let Some(v) = result.get_mut(property) {
83 if let Some(existing_array) = v.as_array_mut() {
84 existing_array.push(val);
85 } else {
86 let v = v.take();
87 result[property] = json!([v, val]);
88 }
89 } else {
90 result.insert(property.to_string(), json!(val));
91 }
92
93 Ok(())
94}
95
96
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102
103 #[test]
104 fn flattening_nested_arrays_and_objects_1() {
105 let json: Value = json!({
106 "x": [
107 ["y", "z"],
108 { "p": "q" },
109 ["r", "s"],
110 [
111 { "u": "v" },
112 { "w": "x" },
113 ],
114 ["y", "z"],
115 ]
116 });
117
118 let flat = flatten(&json).unwrap();
119 let expected = json!({
120 "x[0][0]": "y",
121 "x[0][1]": "z",
122 "x[1].p": "q",
123 "x[2][0]": "r",
124 "x[2][1]": "s",
125 "x[3][0].u": "v",
126 "x[3][1].w": "x",
127 "x[4][0]": "y",
128 "x[4][1]": "z"
129 });
130
131
132 println!(
133 "got:\n{}\nexpected:\n{}\n",
134 serde_json::to_string_pretty(&flat).unwrap(),
135 serde_json::to_string_pretty(&expected).unwrap()
136 );
137
138 assert_eq!(
139 serde_json::to_value(&flat).unwrap(),
140 expected
141 );
142 }
143
144
145 #[test]
146 fn flattening_nested_arrays_and_objects_2() {
147 let json: Value = json!({
148 "x": [
149 "y",
150 ["z", "w"],
151 { "v": ["u", "t"] },
152 [
153 { "s": "r" },
154 { "v": ["q", { "y": "x" }] },
155 ],
156 ["a"],
157 "b",
158 ]
159 });
160
161 let flat = flatten(&json).unwrap();
162 let expected = json!({
163 "x[0]": "y",
164 "x[1][0]": "z",
165 "x[1][1]": "w",
166 "x[2].v[0]": "u",
167 "x[2].v[1]": "t",
168 "x[3][0].s": "r",
169 "x[3][1].v[0]": "q",
170 "x[3][1].v[1].y": "x",
171 "x[4][0]": "a",
172 "x[5]": "b"
173 });
174
175 println!(
176 "got:\n{}\nexpected:\n{}\n",
177 serde_json::to_string_pretty(&flat).unwrap(),
178 serde_json::to_string_pretty(&expected).unwrap()
179 );
180
181
182 assert_eq!(
183 serde_json::to_value(&flat).unwrap(),
184 expected
185 );
186 }
187
188
189 #[test]
190 fn flattening_nested_arrays_and_objects_3() {
191 let json: Value = json!({
192 "a": {
193 "b": "c",
194 "d": [
195 {
196 "e": "f",
197 "g": ["h", "i"]
198 },
199 {
200 "j": "k",
201 "l": ["m", "n"]
202 }
203 ],
204 "o": {
205 "p": "q",
206 "r": ["s", "t"]
207 }
208 },
209 "u": [
210 {
211 "v": "w",
212 "x": ["y", "z"]
213 },
214 {
215 "aa": "ab",
216 "ac": [
217 {
218 "ad": "ae",
219 "af": ["ag", "ah"]
220 },
221 "ai"
222 ]
223 }
224 ],
225 "aj": "ak"
226 });
227
228 let flat = flatten(&json).unwrap();
229 let expected = json!({
230 "a.b": "c",
231 "a.d[0].e": "f",
232 "a.d[0].g[0]": "h",
233 "a.d[0].g[1]": "i",
234 "a.d[1].j": "k",
235 "a.d[1].l[0]": "m",
236 "a.d[1].l[1]": "n",
237 "a.o.p": "q",
238 "a.o.r[0]": "s",
239 "a.o.r[1]": "t",
240 "u[0].v": "w",
241 "u[0].x[0]": "y",
242 "u[0].x[1]": "z",
243 "u[1].aa": "ab",
244 "u[1].ac[0].ad": "ae",
245 "u[1].ac[0].af[0]": "ag",
246 "u[1].ac[0].af[1]": "ah",
247 "u[1].ac[1]": "ai",
248 "aj": "ak"
249 });
250
251 println!(
252 "got:\n{}\nexpected:\n{}\n",
253 serde_json::to_string_pretty(&flat).unwrap(),
254 serde_json::to_string_pretty(&expected).unwrap()
255 );
256
257
258 assert_eq!(
259 serde_json::to_value(&flat).unwrap(),
260 expected
261 );
262 }
263}