use super::Formatter;
use crate::{Change, Diff, FormatError};
use serde_json::json;
#[derive(Debug)]
pub struct JsonPatchFormatter;
impl JsonPatchFormatter {
pub fn new() -> Self {
Self
}
}
impl Default for JsonPatchFormatter {
fn default() -> Self {
Self::new()
}
}
impl Formatter for JsonPatchFormatter {
fn format(&self, diff: &Diff) -> Result<String, FormatError> {
let mut patches = vec![];
for (path, change) in diff.changes() {
let json_path = path.to_json_pointer();
match change {
Change::Added(val) => {
patches.push(json!({
"op": "add",
"path": json_path,
"value": val,
}));
}
Change::Removed(_) => {
patches.push(json!({
"op": "remove",
"path": json_path,
}));
}
Change::Modified { to, .. } => {
patches.push(json!({
"op": "replace",
"path": json_path,
"value": to,
}));
}
Change::Elided { .. } => {
}
}
}
serde_json::to_string_pretty(&patches).map_err(FormatError::Json)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Path;
use serde_value::Value;
#[test]
fn test_json_patch_add() {
let mut diff = Diff::new();
diff.insert(Path::root().field("x"), Change::Added(Value::I64(42)));
let formatter = JsonPatchFormatter::new();
let output = formatter.format(&diff).unwrap();
assert!(output.contains("\"op\": \"add\""));
assert!(output.contains("\"/x\""));
}
}