1use crate::{
4 parsers::flat_key::{self, KeyPart, KeyParts, StringKeyParts},
5 value::ValueExt,
6};
7use rayon::prelude::*;
8use serde_json::{Map, Value};
9use std::collections::BTreeMap;
10use std::iter;
11
12pub fn flatten_keys<P>(value: Value, prefix: P) -> Value
73where
74 P: AsRef<str>,
75{
76 let mut flattener = KeyFlattener::new(prefix.as_ref());
77 Value::Object(Map::from_iter(flattener.flatten(value)))
78}
79
80pub fn expand_keys(value: Value) -> Value {
93 match value {
94 Value::Object(object) => object
95 .into_iter()
96 .collect::<Vec<(String, Value)>>()
97 .into_par_iter()
98 .map(|(key, value)| match flat_key::parse(&key).ok() {
99 Some(mut parts) => {
100 parts.reverse();
101 expand_key_parts(&mut parts, value)
102 }
103 None => Value::Object(Map::from_iter(iter::once((key, value)))),
104 })
105 .reduce(
106 || Value::Null,
107 |mut a, mut b| {
108 a.deep_merge(&mut b);
109 a
110 },
111 ),
112 Value::Array(array) => Value::Array(array.into_iter().map(expand_keys).collect()),
113 value => value,
114 }
115}
116
117fn expand_key_parts(parts: &mut KeyParts, value: Value) -> Value {
118 match parts.pop() {
119 Some(key) => match key {
120 KeyPart::Ident(ident) => {
121 let mut object = Map::with_capacity(1);
122 object.insert(ident, expand_key_parts(parts, value));
123 Value::Object(object)
124 }
125 KeyPart::Index(index) => {
126 let mut array = vec![Value::Null; index + 1];
127 array[index] = expand_key_parts(parts, value);
128 Value::Array(array)
129 }
130 },
131 None => value,
132 }
133}
134
135struct KeyFlattener<'a> {
136 prefix: &'a str,
137 stack: StringKeyParts,
138}
139
140impl<'a> KeyFlattener<'a> {
141 fn new(prefix: &'a str) -> Self {
142 Self {
143 prefix,
144 stack: StringKeyParts::new(),
145 }
146 }
147
148 fn flatten(&mut self, value: Value) -> BTreeMap<String, Value> {
149 let mut map = BTreeMap::new();
150 self.stack.push_ident(self.prefix);
151 self.flatten_value(&mut map, value);
152 self.stack.pop();
153 map
154 }
155
156 fn flatten_value(&mut self, map: &mut BTreeMap<String, Value>, value: Value) {
157 match value {
158 Value::Array(array) => {
159 map.insert(self.key(), Value::Array(Vec::new()));
160 for (index, value) in array.into_iter().enumerate() {
161 self.stack.push_index(index);
162 self.flatten_value(map, value);
163 self.stack.pop();
164 }
165 }
166 Value::Object(object) => {
167 map.insert(self.key(), Value::Object(Map::new()));
168 for (key, value) in object.into_iter() {
169 self.stack.push_ident(&key);
170 self.flatten_value(map, value);
171 self.stack.pop();
172 }
173 }
174 value => {
175 map.insert(self.key(), value);
176 }
177 }
178 }
179
180 fn key(&self) -> String {
181 self.stack.to_string()
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use pretty_assertions::assert_eq;
189 use serde_json::json;
190
191 #[test]
192 fn test_expand_keys() {
193 let value = json!({
194 "data": {},
195 "data.foo": {},
196 "data.foo.bar": [],
197 "data.foo.bar[0]": "baz",
198 "data.foo.bar[1]": "qux"
199 });
200
201 assert_eq!(
202 expand_keys(value),
203 json!({"data": {"foo": {"bar": ["baz", "qux"]}}})
204 );
205 }
206
207 #[test]
208 fn test_flatten_keys() {
209 let value = json!({"foo": {"bar": ["baz", "qux"]}});
210
211 assert_eq!(
212 flatten_keys(value, "data"),
213 json!({
214 "data": {},
215 "data.foo": {},
216 "data.foo.bar": [],
217 "data.foo.bar[0]": "baz",
218 "data.foo.bar[1]": "qux"
219 })
220 );
221 }
222}