1use serde_json::Value;
2
3use super::JsonDiff;
4use super::PatchObject;
5use crate::Changes;
6use crate::Diff;
7use crate::DiffError;
8
9impl Changes for Value {
10 type Replace = Value;
11 type Patch = PatchObject;
12
13 fn diff(&self, new: &Self) -> Result<JsonDiff, DiffError> {
14 if *self == *new {
15 return Ok(Diff::None);
16 }
17 match self {
18 Value::Null => Ok(Diff::Replace(new.clone())),
19 _ => {
20 match new {
21 Value::Null => Ok(Diff::Replace(Value::Null)),
22 Value::Bool(ref _val) => Ok(Diff::Replace(new.clone())), Value::Number(ref _val) => Ok(Diff::Replace(new.clone())),
24 Value::String(ref _val) => Ok(Diff::Replace(new.clone())),
25 Value::Array(ref _val) => Ok(Diff::Replace(new.clone())),
26 Value::Object(ref new_val) => match self {
27 Value::Object(ref old_val) => {
28 let patch = PatchObject::diff(old_val, new_val)?;
29 Ok(Diff::Patch(patch))
30 }
31 _ => Err(DiffError::DiffValue),
32 },
33 }
34 }
35 }
36 }
37}
38
39#[cfg(test)]
40mod test {
41
42 use serde_json::json;
43 use serde_json::Value;
44
45 use super::Changes;
46
47 #[test]
48 fn test_null_comparision() {
49 let n1 = Value::Null;
50 let str1 = Value::String("test".to_owned());
51 let str2 = Value::String("test".to_owned());
52
53 assert!(n1.diff(&str1).expect("diff").is_replace());
54 assert!(str1.diff(&str2).expect("diff").is_none());
55 }
56
57 #[test]
58 fn test_object_comparision() {
59 let old_spec = json!({
60 "replicas": 2,
61 "apple": 5
62 });
63 let new_spec = json!({
64 "replicas": 3,
65 "apple": 5
66 });
67
68 let diff = old_spec.diff(&new_spec).expect("diff");
69 assert!(diff.is_patch());
70 let patch = diff.as_patch_ref().get_inner_ref();
71 assert_eq!(patch.len(), 1);
72 let diff_replicas = patch.get("replicas").unwrap();
73 assert!(diff_replicas.is_replace());
74 assert_eq!(*diff_replicas.as_replace_ref(), 3);
75 }
76
77 #[test]
78 #[allow(clippy::clippy::assertions_on_constants)]
79 fn test_replace_some_with_none() {
80 use serde::Serialize;
81 use serde_json::to_value;
82
83 use crate::Diff;
84
85 #[derive(Serialize)]
86 struct Test {
87 choice: Option<bool>,
88 value: u16,
89 }
90
91 let old_spec = to_value(Test {
92 choice: Some(true),
93 value: 5,
94 })
95 .expect("json");
96 let new_spec = to_value(Test {
97 choice: None,
98 value: 5,
99 })
100 .expect("json");
101
102 let diff = old_spec.diff(&new_spec).expect("diff");
103
104 assert!(diff.is_patch());
105
106 match diff {
107 Diff::Patch(p) => {
108 let json_diff = serde_json::to_value(p).expect("json");
109 println!("json diff: {:#?}", json_diff);
110 assert_eq!(json_diff, json!({ "choice": null }));
111 }
112 _ => assert!(false),
113 }
114 }
115}