1use serde::Serialize;
2use serde_json::{to_value, Value};
3
4use crate::error::Error;
5
6#[derive(Debug, Clone, PartialEq)]
8pub enum Change {
9 SET { p: String, v: Value },
21
22 #[cfg(feature = "append")]
33 APPEND { p: String, v: Value },
34
35 BATCH { p: String, v: Vec<Self> },
37}
38
39impl Change {
40 pub fn set<P: Into<String>, V: Serialize>(p: P, v: V) -> Result<Self, serde_json::Error> {
42 Ok(Self::SET { p: p.into(), v: to_value(v)? })
43 }
44
45 #[cfg(feature = "append")]
47 pub fn append<P: Into<String>, V: Serialize>(p: P, v: V) -> Result<Self, serde_json::Error> {
48 Ok(Self::APPEND { p: p.into(), v: to_value(v)? })
49 }
50
51 pub fn batch<P: Into<String>>(p: P, v: Vec<Change>) -> Self {
53 Self::BATCH { p: p.into(), v }
54 }
55
56 pub fn path(&self) -> &String {
58 match self {
59 Self::BATCH { p, .. } => p,
60 Self::SET { p, .. } => p,
61 #[cfg(feature = "append")]
62 Self::APPEND { p, .. } => p,
63 }
64 }
65
66 pub fn path_mut(&mut self) -> &mut String {
68 match self {
69 Self::BATCH { p, .. } => p,
70 Self::SET { p, .. } => p,
71 #[cfg(feature = "append")]
72 Self::APPEND { p, .. } => p,
73 }
74 }
75
76 pub fn apply(self, mut value: &mut Value, prefix: &str) -> Result<(), Error> {
78 let mut parts = split_path(self.path());
79 let mut prefix = prefix.to_string();
80 while let Some(key) = parts.pop() {
81 prefix += key;
82 prefix += "/";
83 match json_index(value, key, parts.is_empty() && matches!(self, Self::SET { .. })) {
84 Some(v) => value = v,
85 None => {
86 prefix.pop();
87 return Err(Error::IndexError { path: prefix })
88 },
89 }
90 }
91 match self {
92 Self::SET { v, .. } => {
93 *value = v;
94 },
95 #[cfg(feature = "append")]
96 Self::APPEND { v, .. } => {
97 if !append(value, v) {
98 prefix.pop();
99 return Err(Error::OperationError { path: prefix })
100 }
101 },
102 Self::BATCH { v, .. } => {
103 for delta in v {
104 delta.apply(value, &prefix)?;
105 }
106 },
107 }
108 Ok(())
109 }
110}
111
112fn json_index<'v>(value: &'v mut Value, key: &str, insert: bool) -> Option<&'v mut Value> {
113 match value {
114 Value::Array(vec) => {
115 key.parse::<usize>().ok().and_then(|index| vec.get_mut(index))
116 },
117 Value::Object(map) => {
118 match insert {
119 true => Some(map.entry(key.to_string()).or_insert(Value::Null)),
120 false => map.get_mut(key),
121 }
122 },
123 _ => None,
124 }
125}
126
127#[cfg(feature = "append")]
128pub(crate) fn append(lhs: &mut Value, rhs: Value) -> bool {
129 match (lhs, rhs) {
130 (Value::String(lhs), Value::String(rhs)) => {
131 *lhs += &rhs;
132 },
133 (Value::Array(lhs), Value::Array(rhs)) => {
134 lhs.extend(rhs);
135 },
136 _ => return false,
137 }
138 true
139}
140
141pub(crate) fn split_path(path: &str) -> Vec<&str> {
142 if path.is_empty() {
143 vec![]
144 } else {
145 path.split('/').rev().collect()
146 }
147}
148
149pub(crate) fn concat_path(key: String, path: &str) -> String {
150 if path.is_empty() {
151 key
152 } else {
153 format!("{}/{}", key, path)
154 }
155}
156
157#[cfg(test)]
158mod test {
159 use serde_json::json;
160
161 use super::*;
162
163 #[test]
164 fn apply_set() {
165 let mut value = json!({"a": 1});
166 Change::set("", json!({})).unwrap().apply(&mut value, "").unwrap();
167 assert_eq!(value, json!({}));
168
169 let mut value = json!({});
170 Change::set("a", 1).unwrap().apply(&mut value, "").unwrap();
171 assert_eq!(value, json!({"a": 1}));
172
173 let mut value = json!({"a": 1});
174 Change::set("a", 2).unwrap().apply(&mut value, "").unwrap();
175 assert_eq!(value, json!({"a": 2}));
176
177 let error = Change::set("a/b", 3).unwrap().apply(&mut json!({}), "").unwrap_err();
178 assert_eq!(error, Error::IndexError { path: "a".to_string() });
179
180 let error = Change::set("a/b", 3).unwrap().apply(&mut json!({"a": 1}), "").unwrap_err();
181 assert_eq!(error, Error::IndexError { path: "a/b".to_string() });
182
183 let error = Change::set("a/b", 3).unwrap().apply(&mut json!({"a": []}), "").unwrap_err();
184 assert_eq!(error, Error::IndexError { path: "a/b".to_string() });
185
186 let mut value = json!({"a": {}});
187 Change::set("a/b", 3).unwrap().apply(&mut value, "").unwrap();
188 assert_eq!(value, json!({"a": {"b": 3}}));
189 }
190
191 #[test]
192 fn apply_append() {
193 let mut value = json!("2");
194 Change::append("", "34").unwrap().apply(&mut value, "").unwrap();
195 assert_eq!(value, json!("234"));
196
197 let mut value = json!([2]);
198 Change::append("", ["3", "4"]).unwrap().apply(&mut value, "").unwrap();
199 assert_eq!(value, json!([2, "3", "4"]));
200
201 let error = Change::append("", 3).unwrap().apply(&mut json!(""), "").unwrap_err();
202 assert_eq!(error, Error::OperationError { path: "".to_string() });
203
204 let error = Change::append("", "3").unwrap().apply(&mut json!({}), "").unwrap_err();
205 assert_eq!(error, Error::OperationError { path: "".to_string() });
206
207 let error = Change::append("", "3").unwrap().apply(&mut json!([]), "").unwrap_err();
208 assert_eq!(error, Error::OperationError { path: "".to_string() });
209
210 let error = Change::append("", [3]).unwrap().apply(&mut json!(""), "").unwrap_err();
211 assert_eq!(error, Error::OperationError { path: "".to_string() });
212 }
213
214 #[test]
215 fn apply_batch() {
216 let mut value = json!({"a": {"b": {"c": {}}}});
217 Change::batch("", vec![]).apply(&mut value, "").unwrap();
218 assert_eq!(value, json!({"a": {"b": {"c": {}}}}));
219
220 let mut value = json!({"a": {"b": {"c": "1"}}});
221 let error = Change::batch("a/d", vec![]).apply(&mut value, "").unwrap_err();
222 assert_eq!(error, Error::IndexError { path: "a/d".to_string() });
223
224 let mut value = json!({"a": {"b": {"c": "1"}}});
225 Change::batch("a", vec![
226 Change::append("b/c", "2").unwrap(),
227 Change::set("d", 3).unwrap(),
228 ]).apply(&mut value, "").unwrap();
229 assert_eq!(value, json!({"a": {"b": {"c": "12"}, "d": 3}}));
230 }
231}