1mod spec;
2mod shift;
3mod default;
4mod remove;
5mod pointer;
6mod transform;
7mod error;
8#[cfg(not(feature = "fuzz"))]
9mod dsl;
10#[cfg(feature = "fuzz")]
11pub mod dsl;
12
13use serde_json::{Map, Value};
14use serde_json::map::Entry;
15use transform::Transform;
16
17use crate::default::default;
18use crate::remove::remove;
19use crate::spec::SpecEntry;
20
21pub use spec::TransformSpec;
22use crate::pointer::JsonPointer;
23
24pub use error::{Error, Result};
25
26pub fn transform(input: Value, spec: &TransformSpec) -> Result<Value> {
79 let mut result = input;
80 for entry in spec.entries() {
81 match entry {
82 SpecEntry::Shift(shift) => result = shift.apply(&result)?,
83 SpecEntry::Default(spec) => result = default(result, spec),
84 SpecEntry::Remove(spec) => result = remove(result, spec),
85 }
86 }
87 Ok(result)
88}
89
90pub(crate) fn insert(dest: &mut Value, position: JsonPointer, val: Value) {
91 let elements = position.iter();
92 let folded = elements
93 .skip(1)
94 .try_fold(dest, |target, token| match target {
95 Value::Object(map) => {
96 if let Entry::Vacant(entry) = map.entry(token) {
97 entry.insert(Value::Object(Map::new()));
98 }
99 map.get_mut(token)
100 }
101 _ => None,
102 });
103 if let Some(pointer_mut) = folded {
104 merge(pointer_mut, val);
105 }
106}
107
108fn merge(dest: &mut Value, new_value: Value) {
110 match (dest, new_value) {
111 (Value::Object(dest), Value::Object(new_value)) => {
112 for (key, value) in new_value.into_iter() {
113 dest.insert(key, value);
114 }
115 }
116 (dest, new_value) => *dest = new_value,
117 };
118}
119
120pub(crate) fn delete(dest: &mut Value, position: &JsonPointer) -> Option<()> {
121 if let Some(Value::Object(map)) = dest.pointer_mut(position.parent().join_rfc6901().as_str()) {
122 map.remove(position.leaf_name());
123 }
124 Some(())
125}
126
127#[cfg(test)]
128mod test {
129
130 use serde_json::json;
131 use super::*;
132
133 #[test]
134 fn test_transform() {
135 let spec: TransformSpec = serde_json::from_value(json!(
136 [
137 {
138 "operation": "shift",
139 "spec": {
140 "a": "a_new",
141 "c": "c_new"
142 }
143 }
144 ]
145 ))
146 .expect("parsed spec");
147
148 let source = json!({
149 "a": "b",
150 "c": "d"
151 });
152 let result = transform(source, &spec).unwrap();
153
154 assert_eq!(
155 result,
156 json!({
157 "a_new": "b",
158 "c_new": "d"
159 })
160 );
161 }
162
163 #[test]
164 fn test_insert_object_to_empty() {
165 let mut empty_dest = Value::Object(Map::new());
167 let value = json!({
168 "a": "b",
169 });
170
171 insert(
172 &mut empty_dest,
173 JsonPointer::from_dot_notation("new"),
174 value,
175 );
176
177 assert_eq!(
178 empty_dest,
179 json!({
180 "new": {
181 "a": "b"
182 }
183 })
184 );
185 }
186
187 #[test]
188 fn test_insert_object_to_non_empty() {
189 let mut dest = json!({
191 "b": "bb",
192 "c": "cc",
193 });
194 let value = json!({
195 "a": "b",
196 });
197
198 insert(&mut dest, JsonPointer::from_dot_notation("new"), value);
199
200 assert_eq!(
201 dest,
202 json!({
203 "b": "bb",
204 "c": "cc",
205 "new": {
206 "a": "b"
207 }
208 })
209 );
210 }
211
212 #[test]
213 fn test_insert_object_merged() {
214 let mut dest = json!({
216 "some": {
217 "b": "bb",
218 "c": "cc",
219 }
220 });
221 let value = json!({
222 "a": "b",
223 });
224
225 insert(&mut dest, JsonPointer::from_dot_notation("some"), value);
226
227 assert_eq!(
228 dest,
229 json!({
230 "some": {
231 "a": "b",
232 "b": "bb",
233 "c": "cc",
234 }
235 })
236 );
237 }
238
239 #[test]
240 fn test_insert_object_to_empty_non_root() {
241 let mut empty_dest = Value::Object(Map::new());
243 let value = json!({
244 "a": "b",
245 });
246
247 insert(
248 &mut empty_dest,
249 JsonPointer::from_dot_notation("level1.level2.new"),
250 value,
251 );
252
253 assert_eq!(
254 empty_dest,
255 json!({
256 "level1": {
257 "level2": {
258 "new": {
259 "a": "b"
260 }
261 }
262 }
263 })
264 );
265 }
266
267 #[test]
268 fn test_delete_empty_pointer() {
269 let mut input = json!({
271 "a": "b",
272 });
273
274 let _ = delete(&mut input, &JsonPointer::from_dot_notation(""));
276
277 assert_eq!(
279 input,
280 json!({
281 "a": "b",
282 })
283 );
284 }
285
286 #[test]
287 fn test_delete_not_existing() {
288 let mut input = json!({
290 "a": "b",
291 });
292
293 let _ = delete(&mut input, &JsonPointer::from_dot_notation(".b"));
295
296 assert_eq!(
298 input,
299 json!({
300 "a": "b",
301 })
302 );
303 }
304
305 #[test]
306 fn test_delete() {
307 let mut input1 = json!({
309 "a": "b",
310 });
311 let mut input2 = json!({
312 "a": "b",
313 "b": "c",
314 });
315 let _ = delete(&mut input1, &JsonPointer::from_dot_notation(".a"));
317 let _ = delete(&mut input2, &JsonPointer::from_dot_notation("b"));
318
319 assert_eq!(input1, json!({}));
321 assert_eq!(
322 input2,
323 json!({
324 "a": "b",
325 })
326 );
327 }
328}