Modify flatten_serde_json to keep dummy value for all object keys

Example:
```json
{
    "id": 0,
    "colour" : { "green": 1 }
}
```
becomes:
```json
{
    "id": 0,
    "colour" : [],
    "colour.green": 1
}
```
to retain the information the key "colour" exists in the original
json value.
This commit is contained in:
Loïc Lecrenier 2022-06-14 15:05:49 +02:00
parent 453d593ce8
commit a8641b42a7

View File

@ -4,7 +4,11 @@ use serde_json::{Map, Value};
pub fn flatten(json: &Map<String, Value>) -> Map<String, Value> { pub fn flatten(json: &Map<String, Value>) -> Map<String, Value> {
let mut obj = Map::new(); let mut obj = Map::new();
insert_object(&mut obj, None, json); let mut all_keys = vec![];
insert_object(&mut obj, None, json, &mut all_keys);
for key in all_keys {
obj.entry(key).or_insert(Value::Array(vec![]));
}
obj obj
} }
@ -12,26 +16,32 @@ fn insert_object(
base_json: &mut Map<String, Value>, base_json: &mut Map<String, Value>,
base_key: Option<&str>, base_key: Option<&str>,
object: &Map<String, Value>, object: &Map<String, Value>,
all_keys: &mut Vec<String>,
) { ) {
for (key, value) in object { for (key, value) in object {
let new_key = base_key.map_or_else(|| key.clone(), |base_key| format!("{base_key}.{key}")); let new_key = base_key.map_or_else(|| key.clone(), |base_key| format!("{base_key}.{key}"));
all_keys.push(new_key.clone());
if let Some(array) = value.as_array() { if let Some(array) = value.as_array() {
insert_array(base_json, &new_key, array); insert_array(base_json, &new_key, array, all_keys);
} else if let Some(object) = value.as_object() { } else if let Some(object) = value.as_object() {
insert_object(base_json, Some(&new_key), object); insert_object(base_json, Some(&new_key), object, all_keys);
} else { } else {
insert_value(base_json, &new_key, value.clone()); insert_value(base_json, &new_key, value.clone());
} }
} }
} }
fn insert_array(base_json: &mut Map<String, Value>, base_key: &str, array: &Vec<Value>) { fn insert_array(
base_json: &mut Map<String, Value>,
base_key: &str,
array: &Vec<Value>,
all_keys: &mut Vec<String>,
) {
for value in array { for value in array {
if let Some(object) = value.as_object() { if let Some(object) = value.as_object() {
insert_object(base_json, Some(base_key), object); insert_object(base_json, Some(base_key), object, all_keys);
} else if let Some(sub_array) = value.as_array() { } else if let Some(sub_array) = value.as_array() {
insert_array(base_json, base_key, sub_array); insert_array(base_json, base_key, sub_array, all_keys);
} else { } else {
insert_value(base_json, base_key, value.clone()); insert_value(base_json, base_key, value.clone());
} }
@ -103,6 +113,7 @@ mod tests {
assert_eq!( assert_eq!(
&flat, &flat,
json!({ json!({
"a": [],
"a.b": "c", "a.b": "c",
"a.d": "e", "a.d": "e",
"a.f": "g" "a.f": "g"
@ -116,6 +127,10 @@ mod tests {
fn flatten_array() { fn flatten_array() {
let mut base: Value = json!({ let mut base: Value = json!({
"a": [ "a": [
1,
"b",
[],
[{}],
{ "b": "c" }, { "b": "c" },
{ "b": "d" }, { "b": "d" },
{ "b": "e" }, { "b": "e" },
@ -127,6 +142,7 @@ mod tests {
assert_eq!( assert_eq!(
&flat, &flat,
json!({ json!({
"a": [1, "b"],
"a.b": ["c", "d", "e"], "a.b": ["c", "d", "e"],
}) })
.as_object() .as_object()
@ -154,6 +170,28 @@ mod tests {
.as_object() .as_object()
.unwrap() .unwrap()
); );
// here we must keep 42 in "a"
let mut base: Value = json!({
"a": [
{ "b": "c" },
{ "b": "d" },
{ "b": "e" },
null,
]
});
let json = std::mem::take(base.as_object_mut().unwrap());
let flat = flatten(&json);
assert_eq!(
&flat,
json!({
"a": null,
"a.b": ["c", "d", "e"],
})
.as_object()
.unwrap()
);
} }
#[test] #[test]
@ -170,6 +208,7 @@ mod tests {
assert_eq!( assert_eq!(
&flat, &flat,
json!({ json!({
"a": [],
"a.b": ["c", "d"], "a.b": ["c", "d"],
}) })
.as_object() .as_object()