mod spec;
mod shift;
mod default;
mod remove;
mod pointer;
mod transform;
mod error;
#[cfg(not(feature = "fuzz"))]
mod dsl;
#[cfg(feature = "fuzz")]
pub mod dsl;
use serde_json::{Map, Value};
use serde_json::map::Entry;
use transform::Transform;
use crate::default::default;
use crate::remove::remove;
use crate::spec::SpecEntry;
pub use spec::TransformSpec;
use crate::pointer::JsonPointer;
pub use error::{Error, Result};
pub fn transform(input: Value, spec: &TransformSpec) -> Result<Value> {
let mut result = input;
for entry in spec.entries() {
match entry {
SpecEntry::Shift(shift) => result = shift.apply(&result)?,
SpecEntry::Default(spec) => result = default(result, spec),
SpecEntry::Remove(spec) => result = remove(result, spec),
}
}
Ok(result)
}
pub(crate) fn insert(dest: &mut Value, position: JsonPointer, val: Value) {
let elements = position.iter();
let folded = elements
.skip(1)
.try_fold(dest, |target, token| match target {
Value::Object(map) => {
if let Entry::Vacant(entry) = map.entry(token) {
entry.insert(Value::Object(Map::new()));
}
map.get_mut(token)
}
_ => None,
});
if let Some(pointer_mut) = folded {
merge(pointer_mut, val);
}
}
fn merge(dest: &mut Value, new_value: Value) {
match (dest, new_value) {
(Value::Object(dest), Value::Object(new_value)) => {
for (key, value) in new_value.into_iter() {
dest.insert(key, value);
}
}
(dest, new_value) => *dest = new_value,
};
}
pub(crate) fn delete(dest: &mut Value, position: &JsonPointer) -> Option<()> {
if let Some(Value::Object(map)) = dest.pointer_mut(position.parent().join_rfc6901().as_str()) {
map.remove(position.leaf_name());
}
Some(())
}
#[cfg(test)]
mod test {
use serde_json::json;
use super::*;
#[test]
fn test_transform() {
let spec: TransformSpec = serde_json::from_value(json!(
[
{
"operation": "shift",
"spec": {
"a": "a_new",
"c": "c_new"
}
}
]
))
.expect("parsed spec");
let source = json!({
"a": "b",
"c": "d"
});
let result = transform(source, &spec).unwrap();
assert_eq!(
result,
json!({
"a_new": "b",
"c_new": "d"
})
);
}
#[test]
fn test_insert_object_to_empty() {
let mut empty_dest = Value::Object(Map::new());
let value = json!({
"a": "b",
});
insert(
&mut empty_dest,
JsonPointer::from_dot_notation("new"),
value,
);
assert_eq!(
empty_dest,
json!({
"new": {
"a": "b"
}
})
);
}
#[test]
fn test_insert_object_to_non_empty() {
let mut dest = json!({
"b": "bb",
"c": "cc",
});
let value = json!({
"a": "b",
});
insert(&mut dest, JsonPointer::from_dot_notation("new"), value);
assert_eq!(
dest,
json!({
"b": "bb",
"c": "cc",
"new": {
"a": "b"
}
})
);
}
#[test]
fn test_insert_object_merged() {
let mut dest = json!({
"some": {
"b": "bb",
"c": "cc",
}
});
let value = json!({
"a": "b",
});
insert(&mut dest, JsonPointer::from_dot_notation("some"), value);
assert_eq!(
dest,
json!({
"some": {
"a": "b",
"b": "bb",
"c": "cc",
}
})
);
}
#[test]
fn test_insert_object_to_empty_non_root() {
let mut empty_dest = Value::Object(Map::new());
let value = json!({
"a": "b",
});
insert(
&mut empty_dest,
JsonPointer::from_dot_notation("level1.level2.new"),
value,
);
assert_eq!(
empty_dest,
json!({
"level1": {
"level2": {
"new": {
"a": "b"
}
}
}
})
);
}
#[test]
fn test_delete_empty_pointer() {
let mut input = json!({
"a": "b",
});
let _ = delete(&mut input, &JsonPointer::from_dot_notation(""));
assert_eq!(
input,
json!({
"a": "b",
})
);
}
#[test]
fn test_delete_not_existing() {
let mut input = json!({
"a": "b",
});
let _ = delete(&mut input, &JsonPointer::from_dot_notation(".b"));
assert_eq!(
input,
json!({
"a": "b",
})
);
}
#[test]
fn test_delete() {
let mut input1 = json!({
"a": "b",
});
let mut input2 = json!({
"a": "b",
"b": "c",
});
let _ = delete(&mut input1, &JsonPointer::from_dot_notation(".a"));
let _ = delete(&mut input2, &JsonPointer::from_dot_notation("b"));
assert_eq!(input1, json!({}));
assert_eq!(
input2,
json!({
"a": "b",
})
);
}
}