fix append/prepend not working inside Value::Object/serde_json::Map

master 1.0.2
Ondřej Hruška 4 years ago
parent 82fa955359
commit c8a1166789
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 2
      Cargo.toml
  2. 109
      src/lib.rs

@ -1,6 +1,6 @@
[package]
name = "json_dotpath"
version = "1.0.1"
version = "1.0.2"
authors = ["Ondřej Hruška <ondra@ondrovo.com>"]
edition = "2018"
license = "MIT"

@ -145,14 +145,7 @@ pub trait DotPaths {
/// - `<` ... first element of an array (same as `0`)
fn dot_set<T>(&mut self, path: &str, value: T) -> Result<()>
where
T: Serialize,
{
// This is a default implementation.
// Vec uses a custom implementation to support the special syntax.
let _ = self.dot_replace::<T, Value>(path, value)?; // Original value is dropped
Ok(())
}
T: Serialize;
/// Replace a value by path with a new value.
/// The value types do not have to match.
@ -321,6 +314,7 @@ impl DotPaths for serde_json::Value {
match self {
// Special case for Vec, which implements additional path symbols
Value::Array(a) => a.dot_set(path, value),
Value::Object(m) => m.dot_set(path, value),
_ => {
let _ = self.dot_replace::<T, Value>(path, value)?; // Original value is dropped
Ok(())
@ -412,6 +406,29 @@ impl DotPaths for serde_json::Map<String, serde_json::Value> {
}
}
fn dot_set<T>(&mut self, path: &str, value: T) -> Result<()> where
T: Serialize {
let (my, sub) = path_split(path);
if my.is_empty() {
return Err(InvalidKey(my));
}
if let Some(subpath) = sub {
if self.contains_key(&my) {
self.get_mut(&my).unwrap().dot_set(subpath, value)
} else {
// Build new subpath
let _ = self.insert(my, new_by_path_root(subpath, value)?); // always returns None here
Ok(())
}
} else {
let packed = serde_json::to_value(value)?;
self.insert(my, packed);
Ok(())
}
}
fn dot_replace<NEW, OLD>(&mut self, path: &str, value: NEW) -> Result<Option<OLD>>
where
NEW: Serialize,
@ -425,10 +442,7 @@ impl DotPaths for serde_json::Map<String, serde_json::Value> {
if let Some(subpath) = sub {
if self.contains_key(&my) {
match self.get_mut(&my) {
None => Ok(None),
Some(m) => m.dot_replace(subpath, value),
}
self.get_mut(&my).unwrap().dot_replace(subpath, value)
} else {
// Build new subpath
let _ = self.insert(my, new_by_path_root(subpath, value)?); // always returns None here
@ -487,7 +501,9 @@ impl DotPaths for Vec<serde_json::Value> {
let index: usize = match my.as_str() {
">" => self.len() - 1, // non-empty checked above
"<" => 0,
_ => my.parse().map_err(|_| InvalidKey(my))?,
_ => my.parse().map_err(|_| {
InvalidKey(my)
})?,
};
if index >= self.len() {
@ -524,7 +540,9 @@ impl DotPaths for Vec<serde_json::Value> {
}
}
"<" => 0,
_ => my.parse().map_err(|_| InvalidKey(my))?,
_ => my.parse().map_err(|_| {
InvalidKey(my)
})?,
};
if index > self.len() {
@ -593,14 +611,23 @@ impl DotPaths for Vec<serde_json::Value> {
_ if my.starts_with('>') => {
// insert after
insert = true;
(&my[1..]).parse::<usize>().map_err(|_| InvalidKey(my_s))? + 1
(&my[1..]).parse::<usize>()
.map_err(|_| {
InvalidKey(my_s)
})? + 1
}
_ if my.starts_with('<') => {
// insert before
insert = true;
(&my[1..]).parse::<usize>().map_err(|_| InvalidKey(my_s))?
(&my[1..]).parse::<usize>()
.map_err(|_| {
InvalidKey(my_s)
})?
}
_ => my.parse::<usize>().map_err(|_| InvalidKey(my_s))?,
_ => my.parse::<usize>()
.map_err(|_| {
InvalidKey(my_s)
})?,
};
if index > self.len() {
@ -657,7 +684,9 @@ impl DotPaths for Vec<serde_json::Value> {
}
}
"<" => 0,
_ => my.parse().map_err(|_| InvalidKey(my))?,
_ => my.parse().map_err(|_| {
InvalidKey(my)
})?,
};
if index >= self.len() {
@ -700,7 +729,9 @@ impl DotPaths for Vec<serde_json::Value> {
}
}
"<" => 0,
_ => my.parse().map_err(|_| InvalidKey(my))?,
_ => my.parse().map_err(|_| {
InvalidKey(my)
})?,
};
if index >= self.len() {
@ -838,6 +869,46 @@ mod tests {
assert_eq!(json!([[["first"]], [["second"]]]), vec);
}
#[test]
fn array_append1() {
let mut test_array = Value::Array(vec![]);
test_array.dot_set(">>", Value::String(String::from("Go to class"))).unwrap();
test_array.dot_set(">>", Value::String(String::from("Fish"))).unwrap();
assert_eq!(json!(["Go to class","Fish"]), test_array);
}
#[test]
fn array_append2() {
let mut test_array = Value::Array(vec![]);
test_array.dot_set("+", Value::String(String::from("Go to class"))).unwrap();
test_array.dot_set("+", Value::String(String::from("Fish"))).unwrap();
assert_eq!(json!(["Go to class","Fish"]), test_array);
}
#[test]
fn array_append_in_object1() {
let mut test_inner_array = Value::Null;
test_inner_array.dot_set("todos.+", Value::String(String::from("Go to class"))).unwrap();
assert_eq!(json!({"todos" : ["Go to class"] }), test_inner_array);
test_inner_array.dot_set("todos.+", Value::String(String::from("Fish"))).unwrap();
assert_eq!(json!({"todos" : ["Go to class","Fish"] }), test_inner_array);
}
#[test]
fn array_append_in_object2() {
let mut test_inner_array = Value::Null;
test_inner_array.dot_set("name", Value::String(String::from("Google"))).unwrap();
assert_eq!(json!({"name" : "Google"}), test_inner_array);
test_inner_array.dot_set("todos.+", Value::String(String::from("Go to class"))).unwrap();
assert_eq!(json!({"name" : "Google", "todos" : ["Go to class"] }), test_inner_array);
test_inner_array.dot_set("todos.+", Value::String(String::from("Fish"))).unwrap();
assert_eq!(json!({"name" : "Google", "todos" : ["Go to class","Fish"] }), test_inner_array);
}
#[test]
fn get_vec() {
let vec = json!([

Loading…
Cancel
Save