pub(crate) fn merge_patch_object_into(
target: &mut serde_json::Value,
patch: &serde_json::Value,
) -> Result<(), String> {
let patch_obj = patch
.as_object()
.ok_or_else(|| "PATCH request body must be a JSON object".to_string())?;
let target_obj = target
.as_object_mut()
.ok_or_else(|| "Existing object is not a JSON object".to_string())?;
for (key, value) in patch_obj {
target_obj.insert(key.clone(), value.clone());
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
use serde_json::json;
#[rstest]
fn test_merge_patch_overwrites_existing_fields() {
let mut target = json!({"name": "Alice", "age": 30});
let patch = json!({"age": 31});
merge_patch_object_into(&mut target, &patch).unwrap();
assert_eq!(target, json!({"name": "Alice", "age": 31}));
}
#[rstest]
fn test_merge_patch_adds_new_fields() {
let mut target = json!({"name": "Alice"});
let patch = json!({"email": "alice@example.com"});
merge_patch_object_into(&mut target, &patch).unwrap();
assert_eq!(
target,
json!({"name": "Alice", "email": "alice@example.com"})
);
}
#[rstest]
fn test_merge_patch_rejects_non_object_patch() {
let mut target = json!({"name": "Alice"});
let patch = json!("not an object");
let result = merge_patch_object_into(&mut target, &patch);
assert_eq!(
result.unwrap_err(),
"PATCH request body must be a JSON object"
);
}
#[rstest]
fn test_merge_patch_rejects_non_object_target() {
let mut target = json!("not an object");
let patch = json!({"name": "Alice"});
let result = merge_patch_object_into(&mut target, &patch);
assert_eq!(result.unwrap_err(), "Existing object is not a JSON object");
}
}