1use serde_json::value::Map;
57use serde_json::value::Value;
58
59pub use error::Error;
60
61mod error;
62
63#[derive(Clone, Debug, Eq, PartialEq)]
65pub enum ArrayFormatting {
66 Plain,
68
69 Surrounded { start: String, end: String },
73}
74
75#[derive(Clone, Debug, Eq, PartialEq)]
78pub struct Flattener {
79 key_separator: String,
81 array_formatting: ArrayFormatting,
83 preserve_empty_arrays: bool,
85 preserve_empty_objects: bool,
87}
88
89impl Default for Flattener {
90 fn default() -> Self {
91 Self::new()
92 }
93}
94
95impl Flattener {
96 #[must_use]
98 pub fn new() -> Self {
99 Flattener {
100 array_formatting: ArrayFormatting::Plain,
101 key_separator: ".".to_string(),
102 preserve_empty_arrays: false,
103 preserve_empty_objects: false,
104 }
105 }
106
107 #[must_use]
109 pub fn set_key_separator(mut self, key_separator: &str) -> Self {
110 self.key_separator = key_separator.to_string();
111 self
112 }
113
114 #[must_use]
117 pub fn set_array_formatting(mut self, array_formatting: ArrayFormatting) -> Self {
118 self.array_formatting = array_formatting;
119 self
120 }
121
122 #[must_use]
124 pub fn set_preserve_empty_arrays(mut self, value: bool) -> Self {
125 self.preserve_empty_arrays = value;
126 self
127 }
128
129 #[must_use]
131 pub fn set_preserve_empty_objects(mut self, value: bool) -> Self {
132 self.preserve_empty_objects = value;
133 self
134 }
135
136 #[must_use]
137 pub fn key_separator(&self) -> &str {
138 &self.key_separator
139 }
140
141 #[must_use]
142 pub fn array_formatting(&self) -> &ArrayFormatting {
143 &self.array_formatting
144 }
145
146 #[must_use]
147 pub fn preserve_empty_arrays(&self) -> bool {
148 self.preserve_empty_arrays
149 }
150
151 #[must_use]
152 pub fn preserve_empty_objects(&self) -> bool {
153 self.preserve_empty_objects
154 }
155
156 pub fn flatten(&self, to_flatten: &Value) -> Result<Value, error::Error> {
165 let mut flat = Map::<String, Value>::new();
166 self.flatten_value(to_flatten, "".to_owned(), 0, &mut flat)
167 .map(|_x| Value::Object(flat))
168 }
169
170 fn flatten_value(
173 &self,
174 current: &Value,
175 parent_key: String,
176 depth: u32,
177 flattened: &mut Map<String, Value>,
178 ) -> Result<(), error::Error> {
179 if depth == 0 {
180 match current {
181 Value::Object(map) => {
182 if map.is_empty() {
183 return Ok(()); }
185 }
186 _ => return Err(error::Error::FirstLevelMustBeAnObject),
187 }
188 }
189
190 if let Some(current) = current.as_object() {
191 if current.is_empty() && self.preserve_empty_objects {
192 flattened.insert(parent_key, serde_json::json!({}));
193 } else {
194 self.flatten_object(current, &parent_key, depth, flattened)?;
195 }
196 } else if let Some(current) = current.as_array() {
197 if current.is_empty() && self.preserve_empty_arrays {
198 flattened.insert(parent_key, serde_json::json!([]));
199 } else {
200 self.flatten_array(current, &parent_key, depth, flattened)?;
201 }
202 } else {
203 if flattened.contains_key(&parent_key) {
204 return Err(error::Error::KeyWillBeOverwritten(parent_key));
205 }
206 flattened.insert(parent_key, current.clone());
207 }
208 Ok(())
209 }
210
211 fn flatten_object(
214 &self,
215 current: &Map<String, Value>,
216 parent_key: &str,
217 depth: u32,
218 flattened: &mut Map<String, Value>,
219 ) -> Result<(), error::Error> {
220 for (k, v) in current.iter() {
221 let parent_key = if depth > 0 {
222 format!("{}{}{}", parent_key, self.key_separator, k)
223 } else {
224 k.to_string()
225 };
226 self.flatten_value(v, parent_key, depth + 1, flattened)?;
227 }
228 Ok(())
229 }
230
231 fn flatten_array(
234 &self,
235 current: &[Value],
236 parent_key: &str,
237 depth: u32,
238 flattened: &mut Map<String, Value>,
239 ) -> Result<(), error::Error> {
240 for (i, obj) in current.iter().enumerate() {
241 let parent_key = match self.array_formatting {
242 ArrayFormatting::Plain => format!("{}{}{}", parent_key, self.key_separator, i),
243 ArrayFormatting::Surrounded { ref start, ref end } => {
244 format!("{}{}{}{}", parent_key, start, i, end)
245 }
246 };
247 self.flatten_value(obj, parent_key, depth + 1, flattened)?;
248 }
249 Ok(())
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::ArrayFormatting;
256 use super::Flattener;
257 use crate::error::Error;
258 use rstest::rstest;
259 use serde_json::json;
260
261 #[rstest]
262 #[case("")]
263 #[case(".")]
264 #[case("-->")]
265 fn object_with_plain_values(#[case] key_separator: &str) {
266 let obj = json!({"int": 1, "float": 2.0, "str": "a", "bool": true, "null": null});
267 assert_eq!(
268 obj,
269 Flattener::new()
270 .set_key_separator(key_separator)
271 .flatten(&obj)
272 .unwrap()
273 );
274 }
275
276 #[rstest]
279 #[case("")]
280 #[case(".")]
281 #[case("aaa")]
282 fn array_formatting_plain(#[case] key_separator: &str) {
283 let obj = json!({"s": {"a": [1, 2.0, "b", null, true]}});
284 assert_eq!(
285 Flattener::new()
286 .set_key_separator(key_separator)
287 .flatten(&obj)
288 .unwrap(),
289 json!({
290 format!("s{k}a{k}0", k = key_separator): 1,
291 format!("s{k}a{k}1", k = key_separator): 2.0,
292 format!("s{k}a{k}2", k = key_separator): "b",
293 format!("s{k}a{k}3", k = key_separator): null,
294 format!("s{k}a{k}4", k = key_separator): true,
295 })
296 );
297 }
298
299 #[rstest]
302 fn array_formatting_surrouded(
303 #[values("", ".", "-->")] key_separator: &str,
304 #[values("", "[", "{{")] array_fmt_start: &str,
305 #[values("", "]", "}}")] array_fmt_end: &str,
306 ) {
307 let obj = json!({"s": {"a": [1, 2.0, "b", null, true]}});
308 assert_eq!(
309 Flattener::new()
310 .set_key_separator(key_separator)
311 .set_array_formatting(ArrayFormatting::Surrounded {
312 start: array_fmt_start.to_string(),
313 end: array_fmt_end.to_string()
314 })
315 .flatten(&obj)
316 .unwrap(),
317 json!({
318 format!("s{}a{}0{}", key_separator, array_fmt_start, array_fmt_end): 1,
319 format!("s{}a{}1{}", key_separator, array_fmt_start, array_fmt_end): 2.0,
320 format!("s{}a{}2{}", key_separator, array_fmt_start, array_fmt_end): "b",
321 format!("s{}a{}3{}", key_separator, array_fmt_start, array_fmt_end): null,
322 format!("s{}a{}4{}", key_separator, array_fmt_start, array_fmt_end): true,
323 })
324 );
325 }
326
327 #[test]
328 fn nested_single_key_value() {
329 let obj = json!({"key": "value", "nested_key": {"key": "value"}});
330 assert_eq!(
331 Flattener::new().flatten(&obj).unwrap(),
332 json!({"key": "value", "nested_key.key": "value"}),
333 );
334 }
335
336 #[test]
337 fn nested_multiple_key_value() {
338 let obj = json!({"key": "value", "nested_key": {"key1": "value1", "key2": "value2"}});
339 assert_eq!(
340 Flattener::new().flatten(&obj).unwrap(),
341 json!({"key": "value", "nested_key.key1": "value1", "nested_key.key2": "value2"}),
342 );
343 }
344
345 #[test]
346 fn complex_nested_struct() {
347 let obj = json!({
348 "simple_key": "simple_value",
349 "key": [
350 "value1",
351 {"key": "value2"},
352 {"nested_array": [
353 "nested1",
354 "nested2",
355 ["nested3", "nested4"]
356 ]}
357 ]
358 });
359 assert_eq!(
360 Flattener::new().flatten(&obj).unwrap(),
361 json!({"simple_key": "simple_value", "key.0": "value1", "key.1.key": "value2",
362 "key.2.nested_array.0": "nested1", "key.2.nested_array.1": "nested2",
363 "key.2.nested_array.2.0": "nested3", "key.2.nested_array.2.1": "nested4"}),
364 );
365 }
366
367 #[test]
368 fn overlapping_after_flattening_array() {
369 let obj = json!({"key": ["value1", "value2"], "key.0": "Oopsy"});
370 let res = Flattener::new().flatten(&obj);
371 assert!(res.is_err());
372 match res {
373 Err(Error::KeyWillBeOverwritten(key)) => assert_eq!(key, "key.0"),
374 Ok(_) => panic!("This should have failed"),
375 _ => panic!("Wrong kind of error"),
376 }
377 }
378
379 #[test]
381 fn empty_array() {
382 let obj = json!({"key": []});
383 assert_eq!(Flattener::new().flatten(&obj).unwrap(), json!({}));
384 }
385
386 #[test]
388 fn empty_object() {
389 let obj = json!({"key": {}});
390 assert_eq!(Flattener::new().flatten(&obj).unwrap(), json!({}));
391 }
392
393 #[rstest]
394 fn empty_top_object(#[values(true, false)] preserve_empty_objects: bool) {
395 let obj = json!({});
396 assert_eq!(
397 Flattener::new()
398 .set_preserve_empty_objects(preserve_empty_objects)
399 .flatten(&obj)
400 .unwrap(),
401 json!({})
402 );
403 }
404
405 #[test]
408 fn empty_complex_object() {
409 let obj = json!({"key": {"key2": {}, "key3": [[], {}, {"k": {}, "q": []}]}});
410 assert_eq!(Flattener::new().flatten(&obj).unwrap(), json!({}));
411 }
412
413 #[test]
415 fn empty_array_preserved() {
416 let obj = json!({"key": [], "a": {}});
417 assert_eq!(
418 Flattener::new()
419 .set_preserve_empty_arrays(true)
420 .flatten(&obj)
421 .unwrap(),
422 json!({"key": []})
423 );
424 }
425
426 #[test]
428 fn empty_object_preserved() {
429 let obj = json!({"key": {}, "a": []});
430 assert_eq!(
431 Flattener::new()
432 .set_preserve_empty_objects(true)
433 .flatten(&obj)
434 .unwrap(),
435 json!({"key": {}})
436 );
437 }
438
439 #[test]
442 fn empty_objects_and_arrays_preserved() {
443 let obj = json!({
444 "key": {
445 "key2": {},
446 "key3": [[], {}, {"k": {}, "q": []}]
447 }
448 });
449 assert_eq!(
450 Flattener::new()
451 .set_preserve_empty_arrays(true)
452 .set_preserve_empty_objects(true)
453 .flatten(&obj)
454 .unwrap(),
455 json!({
456 "key.key2": {},
457 "key.key3.0": [],
458 "key.key3.1": {},
459 "key.key3.2.k": {},
460 "key.key3.2.q": [],
461 })
462 );
463 }
464
465 #[test]
466 fn nested_object_with_empty_array_and_string() {
467 let obj = json!({"key": {"key2": [], "key3": "a"}});
468 assert_eq!(
469 Flattener::new().flatten(&obj).unwrap(),
470 json!({"key.key3": "a"})
471 );
472 }
473
474 #[test]
475 fn nested_object_with_empty_object_and_string() {
476 let obj = json!({"key": {"key2": {}, "key3": "a"}});
477 assert_eq!(
478 Flattener::new().flatten(&obj).unwrap(),
479 json!({"key.key3": "a"})
480 );
481 }
482
483 #[test]
484 fn empty_string_as_key() {
485 let obj = json!({"key": {"": "a"}});
486 assert_eq!(
487 Flattener::new().flatten(&obj).unwrap(),
488 json!({"key.": "a"})
489 );
490 }
491
492 #[test]
493 fn empty_string_as_key_multiple_times() {
494 let obj = json!({"key": {"": {"": {"": "a"}}}});
495 assert_eq!(
496 Flattener::new().flatten(&obj).unwrap(),
497 json!({"key...": "a"})
498 );
499 }
500
501 #[test]
504 fn first_level_must_be_an_object() {
505 let integer = json!(3);
506 let string = json!("");
507 let boolean = json!(false);
508 let null = json!(null);
509 let array = json!([1, 2, 3]);
510
511 for j in [integer, string, boolean, null, array] {
512 let res = Flattener::new().flatten(&j);
513 match res {
514 Err(Error::FirstLevelMustBeAnObject) => return, Ok(_) => panic!("This should have failed"),
516 _ => panic!("Wrong kind of error"),
517 }
518 }
519 }
520
521 #[test]
522 fn complex_array() {
523 let obj = json!({"a": [1, [2, [3, 4], 5], 6]});
524 assert_eq!(
525 Flattener::new().flatten(&obj).unwrap(),
526 json!({"a.0": 1, "a.2": 6, "a.1.0": 2, "a.1.1.0": 3, "a.1.1.1": 4, "a.1.2": 5}),
527 );
528 }
529}