1#![allow(unknown_lints)]
2#![deny(missing_docs)]
3#![deny(rustdoc::missing_doc_code_examples)]
4
5use serde_json::json;
14use serde_json::Map;
15use serde_json::Value;
16
17pub struct Flattener<'a> {
25 pub separator: &'a str,
32 pub alt_array_flattening: bool,
39 pub preserve_arrays: bool,
46}
47
48impl<'a> Default for Flattener<'a> {
49 fn default() -> Self {
50 Flattener {
51 separator: ".",
52 alt_array_flattening: false,
53 preserve_arrays: false,
54 }
55 }
56}
57
58impl<'a> Flattener<'a> {
74 pub fn new() -> Self {
82 Flattener {
83 ..Default::default()
84 }
85 }
86
87 pub fn flatten(&self, json: &Value) -> Value {
115 let mut flattened_val = Map::<String, Value>::new();
116 match json {
117 Value::Array(obj_arr) => {
118 self.flatten_array(&mut flattened_val, &"".to_string(), obj_arr)
119 }
120 Value::Object(obj_val) => self.flatten_object(&mut flattened_val, None, obj_val, false),
121 _ => self.flatten_value(&mut flattened_val, &"".to_string(), json, false),
122 }
123 Value::Object(flattened_val)
124 }
125
126 fn flatten_object(
127 &self,
128 builder: &mut Map<String, Value>,
129 identifier: Option<&String>,
130 obj: &Map<String, Value>,
131 arr: bool,
132 ) {
133 for (k, v) in obj {
134 let expanded_identifier = identifier.map_or_else(
135 || k.clone(),
136 |identifier| format!("{identifier}{}{k}", self.separator),
137 );
138
139 match v {
140 Value::Object(obj_val) => {
141 self.flatten_object(builder, Some(&expanded_identifier), obj_val, arr)
142 }
143 Value::Array(obj_arr) => self.flatten_array(builder, &expanded_identifier, obj_arr),
144 _ => self.flatten_value(builder, &expanded_identifier, v, arr),
145 }
146 }
147 }
148
149 fn flatten_array(
150 &self,
151 builder: &mut Map<String, Value>,
152 identifier: &String,
153 obj: &Vec<Value>,
154 ) {
155 for (k, v) in obj.iter().enumerate() {
156 let with_key = format!("{identifier}{}{k}", self.separator);
157 match v {
158 Value::Object(obj_val) => self.flatten_object(
159 builder,
160 Some(if self.preserve_arrays {
161 &with_key
162 } else {
163 identifier
164 }),
165 obj_val,
166 self.alt_array_flattening,
167 ),
168 Value::Array(obj_arr) => self.flatten_array(
169 builder,
170 if self.preserve_arrays {
171 &with_key
172 } else {
173 identifier
174 },
175 obj_arr,
176 ),
177 _ => self.flatten_value(
178 builder,
179 if self.preserve_arrays {
180 &with_key
181 } else {
182 identifier
183 },
184 v,
185 self.alt_array_flattening,
186 ),
187 }
188 }
189 }
190
191 fn flatten_value(
192 &self,
193 builder: &mut Map<String, Value>,
194 identifier: &String,
195 obj: &Value,
196 arr: bool,
197 ) {
198 if let Some(v) = builder.get_mut(identifier) {
199 if let Some(arr) = v.as_array_mut() {
200 arr.push(obj.clone());
201 } else {
202 let new_val = json!(vec![v, obj]);
203 builder.remove(identifier);
204 builder.insert(identifier.to_string(), new_val);
205 }
206 } else {
207 builder.insert(
208 identifier.to_string(),
209 if arr {
210 json!(vec![obj.clone()])
211 } else {
212 obj.clone()
213 },
214 );
215 }
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222
223 use serde_json::json;
224
225 #[test]
226 fn serde_example() {
227 let flattener = Flattener::new();
228 let base: Value = json!({
229 "name": "John Doe",
230 "age": 43,
231 "address": {
232 "street": "10 Downing Street",
233 "city": "London"
234 },
235 "phones": [
236 "+44 1234567",
237 "+44 2345678"
238 ]
239 });
240
241 let flat = flattener.flatten(&base);
242
243 assert_eq!(
244 flat,
245 json!({
246 "name": "John Doe",
247 "age": 43,
248 "address.street": "10 Downing Street",
249 "address.city": "London",
250 "phones": [
251 "+44 1234567",
252 "+44 2345678"
253 ]
254 })
255 );
256 }
257
258 #[test]
259 fn collision_object() {
260 let flattener = Flattener::new();
261 let base: Value = json!({
262 "a": {
263 "b": "c",
264 },
265 "a.b": "d",
266 });
267 let flat = flattener.flatten(&base);
268
269 assert_eq!(
270 flat,
271 json!({
272 "a.b": ["c", "d"],
273 })
274 );
275 }
276
277 #[test]
278 fn collision_array() {
279 let flattener = Flattener::new();
280 let flattener_alt = Flattener {
281 alt_array_flattening: true,
282 ..Default::default()
283 };
284
285 let base: Value = json!({
286 "a": [
287 { "b": "c" },
288 { "b": "d", "c": "e" },
289 [35],
290 ],
291 "a.b": "f",
292 });
293
294 let flat = flattener.flatten(&base);
295 let flat_alt = flattener_alt.flatten(&base);
296
297 assert_eq!(
298 flat,
299 json!({
300 "a.b": ["c", "d", "f"],
301 "a.c": "e",
302 "a": 35,
303 })
304 );
305
306 assert_eq!(
307 flat_alt,
308 json!({
309 "a.b": ["c", "d", "f"],
310 "a.c": ["e"],
311 "a": [35],
312 })
313 );
314 }
315
316 #[test]
317 fn nested_arrays() {
318 let flattener = Flattener::new();
319 let flattener_alt = Flattener {
320 alt_array_flattening: true,
321 ..Default::default()
322 };
323
324 let base: Value = json!({
325 "a": [
326 ["b", "c"],
327 { "d": "e" },
328 ["f", "g"],
329 [
330 { "h": "i" },
331 { "d": "j" },
332 ],
333 ["k", "l"],
334 ]
335 });
336 let flat = flattener.flatten(&base);
337 let flat_alt = flattener_alt.flatten(&base);
338
339 assert_eq!(
340 flat,
341 json!({
342 "a": ["b", "c", "f", "g", "k", "l"],
343 "a.d": ["e", "j"],
344 "a.h": "i",
345 })
346 );
347
348 assert_eq!(
349 flat_alt,
350 json!({
351 "a": ["b", "c", "f", "g", "k", "l"],
352 "a.d": ["e", "j"],
353 "a.h": ["i"],
354 })
355 );
356 }
357
358 #[test]
359 fn nested_arrays_and_objects() {
360 let flattener = Flattener::new();
361 let flattener_alt = Flattener {
362 alt_array_flattening: true,
363 ..Default::default()
364 };
365
366 let base: Value = json!({
367 "a": [
368 "b",
369 ["c", "d"],
370 { "e": ["f", "g"] },
371 [
372 { "h": "i" },
373 { "e": ["j", { "z": "y" }] },
374 ],
375 ["l"],
376 "m",
377 ]
378 });
379 let flat = flattener.flatten(&base);
380 let flat_alt = flattener_alt.flatten(&base);
381
382 assert_eq!(
383 flat,
384 json!({
385 "a": ["b", "c", "d", "l", "m"],
386 "a.e": ["f", "g", "j"],
387 "a.h": "i",
388 "a.e.z": "y",
389 })
390 );
391
392 assert_eq!(
393 flat_alt,
394 json!({
395 "a": ["b", "c", "d", "l", "m"],
396 "a.e": ["f", "g", "j"],
397 "a.h": ["i"],
398 "a.e.z": ["y"],
399 })
400 )
401 }
402
403 #[test]
404 fn custom_separator() {
405 let flattener = Flattener {
406 separator: "$",
407 ..Default::default()
408 };
409
410 let input: Value = json!({
411 "a": {
412 "b": 1
413 }});
414
415 let result: Value = flattener.flatten(&input);
416 assert_eq!(
417 result,
418 json!({
419 "a$b": 1
420 })
421 );
422 }
423 #[test]
424 fn object() {
425 let flattener = Flattener::new();
426
427 let input: Value = json!({
428 "a": {
429 "b": "1",
430 "c": "2",
431 "d": "3"
432 }
433 });
434
435 let result: Value = flattener.flatten(&input);
436 assert_eq!(
437 result,
438 json!({
439 "a.b": "1",
440 "a.c": "2",
441 "a.d": "3"
442 })
443 );
444 }
445
446 #[test]
447 fn array() {
448 let flattener = Flattener::new();
449
450 let input: Value = json!({
451 "a": [
452 {"b": "1"},
453 {"b": "2"},
454 {"b": "3"},
455 ]
456 });
457
458 let result: Value = flattener.flatten(&input);
459 assert_eq!(
460 result,
461 json!({
462 "a.b": ["1", "2", "3"]
463 })
464 );
465 }
466
467 #[test]
468 fn array_preserve() {
469 let flattener = Flattener {
470 preserve_arrays: true,
471 ..Default::default()
472 };
473
474 let input: Value = json!({
475 "a": [
476 {"b": "1"},
477 {"b": "2"},
478 {"b": "3"},
479 ]
480 });
481
482 let result: Value = flattener.flatten(&input);
483 assert_eq!(
484 result,
485 json!({
486 "a.0.b": "1",
487 "a.1.b": "2",
488 "a.2.b": "3"
489 })
490 );
491 }
492
493 #[test]
494 fn array_no_collision() {
495 let flattener = Flattener::new();
496 let flattener_alt = Flattener {
497 alt_array_flattening: true,
498 ..Default::default()
499 };
500
501 let input: Value = json!({
502 "a": [
503 {"b": ["1"]}
504 ]
505 });
506
507 let flat: Value = flattener.flatten(&input);
508 let flat_alt = flattener_alt.flatten(&input);
509
510 assert_eq!(
511 flat,
512 json!({
513 "a.b": "1"
514 })
515 );
516
517 assert_eq!(
518 flat_alt,
519 json!({
520 "a.b": ["1"]
521 })
522 );
523 }
524
525 #[test]
527 fn arr_no_key() {
528 let flattener = Flattener::new();
529
530 let input: Value = json!(["a", "b"]);
531
532 let result: Value = flattener.flatten(&input);
533
534 assert_eq!(result, json!({"": ["a", "b"]}));
535 }
536
537 #[test]
539 fn arr_empty_key() {
540 let flattener = Flattener::new();
541
542 let input: Value = json!({
543 "": [
544 "a",
545 "b",
546 {"b": ["1"]}
547 ],
548 });
549 let result: Value = flattener.flatten(&input);
550
551 assert_eq!(result, json!({"": ["a", "b"], ".b": "1"}));
552 }
553
554 #[test]
555 fn only_value() {
556 let flattener = Flattener::new();
557
558 let input: Value = json!("abc");
559 let result: Value = flattener.flatten(&input);
560
561 assert_eq!(result, json!({"": "abc"}));
562 }
563
564 #[test]
565 fn nested_array_preserve() {
566 let flattener = Flattener {
567 preserve_arrays: true,
568 ..Default::default()
569 };
570
571 let input: Value = json!({
572 "a": [
573 "b",
574 ["c", "d"],
575 { "e": ["f", "g"] },
576 [
577 { "h": "i" },
578 { "e": ["j", { "z": "y" }] }
579 ],
580 ["l"],
581 "m"
582 ]
583 });
584
585 let result: Value = flattener.flatten(&input);
586
587 assert_eq!(
588 result,
589 json!({
590 "a.0": "b",
591 "a.1.0": "c",
592 "a.1.1": "d",
593 "a.2.e.0": "f",
594 "a.2.e.1": "g",
595 "a.3.0.h": "i",
596 "a.3.1.e.0": "j",
597 "a.3.1.e.1.z": "y",
598 "a.4.0": "l",
599 "a.5": "m"
600 })
601 )
602 }
603}