formatting
This commit is contained in:
+164
-135
@@ -39,7 +39,7 @@ impl From<serde_json::Error> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::Error::{BadPathElement, InvalidKey, BadIndex};
|
use crate::Error::{BadIndex, BadPathElement, InvalidKey};
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
@@ -92,8 +92,8 @@ pub trait DotPaths {
|
|||||||
/// - `>` ... last element of an array
|
/// - `>` ... last element of an array
|
||||||
/// - `<` ... first element of an array (same as `0`)
|
/// - `<` ... first element of an array (same as `0`)
|
||||||
fn dot_get<T>(&self, path: &str) -> Result<Option<T>>
|
fn dot_get<T>(&self, path: &str) -> Result<Option<T>>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned;
|
T: DeserializeOwned;
|
||||||
|
|
||||||
/// Get an item by path, or a default value if it does not exist.
|
/// Get an item by path, or a default value if it does not exist.
|
||||||
///
|
///
|
||||||
@@ -101,11 +101,10 @@ pub trait DotPaths {
|
|||||||
///
|
///
|
||||||
/// See `dot_get()` for more details.
|
/// See `dot_get()` for more details.
|
||||||
fn dot_get_or<T>(&self, path: &str, def: T) -> Result<T>
|
fn dot_get_or<T>(&self, path: &str, def: T) -> Result<T>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
{
|
{
|
||||||
self.dot_get(path)
|
self.dot_get(path).map(|o| o.unwrap_or(def))
|
||||||
.map(|o| o.unwrap_or(def))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an item, or a default value using the Default trait
|
/// Get an item, or a default value using the Default trait
|
||||||
@@ -114,8 +113,8 @@ pub trait DotPaths {
|
|||||||
///
|
///
|
||||||
/// See `dot_get()` for more details.
|
/// See `dot_get()` for more details.
|
||||||
fn dot_get_or_default<T>(&self, path: &str) -> Result<T>
|
fn dot_get_or_default<T>(&self, path: &str) -> Result<T>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned + Default,
|
T: DeserializeOwned + Default,
|
||||||
{
|
{
|
||||||
self.dot_get_or(path, T::default())
|
self.dot_get_or(path, T::default())
|
||||||
}
|
}
|
||||||
@@ -145,9 +144,9 @@ pub trait DotPaths {
|
|||||||
/// - `>` ... last element of an array
|
/// - `>` ... last element of an array
|
||||||
/// - `<` ... first element of an array (same as `0`)
|
/// - `<` ... first element of an array (same as `0`)
|
||||||
fn dot_set<T>(&mut self, path: &str, value: T) -> Result<()>
|
fn dot_set<T>(&mut self, path: &str, value: T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: Serialize {
|
T: Serialize,
|
||||||
|
{
|
||||||
// This is a default implementation.
|
// This is a default implementation.
|
||||||
// Vec uses a custom implementation to support the special syntax.
|
// Vec uses a custom implementation to support the special syntax.
|
||||||
|
|
||||||
@@ -164,9 +163,9 @@ pub trait DotPaths {
|
|||||||
/// - `>` ... last element of an array
|
/// - `>` ... last element of an array
|
||||||
/// - `<` ... first element of an array (same as `0`)
|
/// - `<` ... first element of an array (same as `0`)
|
||||||
fn dot_replace<NEW, OLD>(&mut self, path: &str, value: NEW) -> Result<Option<OLD>>
|
fn dot_replace<NEW, OLD>(&mut self, path: &str, value: NEW) -> Result<Option<OLD>>
|
||||||
where
|
where
|
||||||
NEW: Serialize,
|
NEW: Serialize,
|
||||||
OLD: DeserializeOwned;
|
OLD: DeserializeOwned;
|
||||||
|
|
||||||
/// Get an item using a path, removing it from the object.
|
/// Get an item using a path, removing it from the object.
|
||||||
///
|
///
|
||||||
@@ -179,8 +178,8 @@ pub trait DotPaths {
|
|||||||
/// - `>` ... last element of an array
|
/// - `>` ... last element of an array
|
||||||
/// - `<` ... first element of an array (same as `0`)
|
/// - `<` ... first element of an array (same as `0`)
|
||||||
fn dot_take<T>(&mut self, path: &str) -> Result<Option<T>>
|
fn dot_take<T>(&mut self, path: &str) -> Result<Option<T>>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned;
|
T: DeserializeOwned;
|
||||||
|
|
||||||
/// Remove and drop an item matching a key.
|
/// Remove and drop an item matching a key.
|
||||||
/// Returns true if any item was removed.
|
/// Returns true if any item was removed.
|
||||||
@@ -224,8 +223,8 @@ fn path_split(path: &str) -> (String, Option<&str>) {
|
|||||||
|
|
||||||
impl DotPaths for serde_json::Value {
|
impl DotPaths for serde_json::Value {
|
||||||
fn dot_get<T>(&self, path: &str) -> Result<Option<T>>
|
fn dot_get<T>(&self, path: &str) -> Result<Option<T>>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Value::Array(vec) => vec.dot_get(path),
|
Value::Array(vec) => vec.dot_get(path),
|
||||||
@@ -267,9 +266,9 @@ impl DotPaths for serde_json::Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dot_replace<NEW, OLD>(&mut self, path: &str, value: NEW) -> Result<Option<OLD>>
|
fn dot_replace<NEW, OLD>(&mut self, path: &str, value: NEW) -> Result<Option<OLD>>
|
||||||
where
|
where
|
||||||
NEW: Serialize,
|
NEW: Serialize,
|
||||||
OLD: DeserializeOwned,
|
OLD: DeserializeOwned,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Value::Array(vec) => vec.dot_replace(path, value),
|
Value::Array(vec) => vec.dot_replace(path, value),
|
||||||
@@ -293,8 +292,8 @@ impl DotPaths for serde_json::Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dot_take<T>(&mut self, path: &str) -> Result<Option<T>>
|
fn dot_take<T>(&mut self, path: &str) -> Result<Option<T>>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Value::Array(vec) => vec.dot_take(path),
|
Value::Array(vec) => vec.dot_take(path),
|
||||||
@@ -316,13 +315,12 @@ impl DotPaths for serde_json::Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dot_set<T>(&mut self, path: &str, value: T) -> Result<()>
|
fn dot_set<T>(&mut self, path: &str, value: T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: Serialize {
|
T: Serialize,
|
||||||
|
{
|
||||||
match self {
|
match self {
|
||||||
// Special case for Vec, which implements additional path symbols
|
// Special case for Vec, which implements additional path symbols
|
||||||
Value::Array(a) => {
|
Value::Array(a) => a.dot_set(path, value),
|
||||||
a.dot_set(path, value)
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
let _ = self.dot_replace::<T, Value>(path, value)?; // Original value is dropped
|
let _ = self.dot_replace::<T, Value>(path, value)?; // Original value is dropped
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -334,10 +332,9 @@ impl DotPaths for serde_json::Value {
|
|||||||
/// Create a Value::Object or Value::Array based on a nested path.
|
/// Create a Value::Object or Value::Array based on a nested path.
|
||||||
///
|
///
|
||||||
/// Builds the parent path to a non-existent key in set-type operations.
|
/// Builds the parent path to a non-existent key in set-type operations.
|
||||||
#[must_use]
|
|
||||||
fn new_by_path_root<T>(path: &str, value: T) -> Result<Value>
|
fn new_by_path_root<T>(path: &str, value: T) -> Result<Value>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
return Ok(serde_json::to_value(value)?);
|
return Ok(serde_json::to_value(value)?);
|
||||||
@@ -360,8 +357,8 @@ fn new_by_path_root<T>(path: &str, value: T) -> Result<Value>
|
|||||||
|
|
||||||
impl DotPaths for serde_json::Map<String, serde_json::Value> {
|
impl DotPaths for serde_json::Map<String, serde_json::Value> {
|
||||||
fn dot_get<T>(&self, path: &str) -> Result<Option<T>>
|
fn dot_get<T>(&self, path: &str) -> Result<Option<T>>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
{
|
{
|
||||||
let (my, sub) = path_split(path);
|
let (my, sub) = path_split(path);
|
||||||
|
|
||||||
@@ -372,18 +369,17 @@ impl DotPaths for serde_json::Map<String, serde_json::Value> {
|
|||||||
if let Some(sub_path) = sub {
|
if let Some(sub_path) = sub {
|
||||||
match self.get(&my).null_to_none() {
|
match self.get(&my).null_to_none() {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(child) => child.dot_get(sub_path)
|
Some(child) => child.dot_get(sub_path),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match self.get(&my).null_to_none() {
|
match self.get(&my).null_to_none() {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(m) => {
|
Some(m) => Ok(Some(serde_json::from_value::<T>(m.to_owned())?)),
|
||||||
Ok(Some(serde_json::from_value::<T>(m.to_owned())?))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::collapsible_if)]
|
||||||
fn dot_get_mut(&mut self, path: &str) -> Result<&mut Value> {
|
fn dot_get_mut(&mut self, path: &str) -> Result<&mut Value> {
|
||||||
let (my, sub) = path_split(path);
|
let (my, sub) = path_split(path);
|
||||||
|
|
||||||
@@ -417,9 +413,9 @@ impl DotPaths for serde_json::Map<String, serde_json::Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dot_replace<NEW, OLD>(&mut self, path: &str, value: NEW) -> Result<Option<OLD>>
|
fn dot_replace<NEW, OLD>(&mut self, path: &str, value: NEW) -> Result<Option<OLD>>
|
||||||
where
|
where
|
||||||
NEW: Serialize,
|
NEW: Serialize,
|
||||||
OLD: DeserializeOwned,
|
OLD: DeserializeOwned,
|
||||||
{
|
{
|
||||||
let (my, sub) = path_split(path);
|
let (my, sub) = path_split(path);
|
||||||
|
|
||||||
@@ -431,9 +427,7 @@ impl DotPaths for serde_json::Map<String, serde_json::Value> {
|
|||||||
if self.contains_key(&my) {
|
if self.contains_key(&my) {
|
||||||
match self.get_mut(&my) {
|
match self.get_mut(&my) {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(m) => {
|
Some(m) => m.dot_replace(subpath, value),
|
||||||
m.dot_replace(subpath, value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Build new subpath
|
// Build new subpath
|
||||||
@@ -444,16 +438,14 @@ impl DotPaths for serde_json::Map<String, serde_json::Value> {
|
|||||||
let packed = serde_json::to_value(value)?;
|
let packed = serde_json::to_value(value)?;
|
||||||
match self.insert(my, packed).null_to_none() {
|
match self.insert(my, packed).null_to_none() {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(old) => {
|
Some(old) => Ok(serde_json::from_value(old)?),
|
||||||
Ok(serde_json::from_value(old)?)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dot_take<T>(&mut self, path: &str) -> Result<Option<T>>
|
fn dot_take<T>(&mut self, path: &str) -> Result<Option<T>>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
{
|
{
|
||||||
let (my, sub) = path_split(path);
|
let (my, sub) = path_split(path);
|
||||||
|
|
||||||
@@ -471,9 +463,7 @@ impl DotPaths for serde_json::Map<String, serde_json::Value> {
|
|||||||
} else {
|
} else {
|
||||||
match self.remove(&my).null_to_none() {
|
match self.remove(&my).null_to_none() {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(old) => {
|
Some(old) => Ok(serde_json::from_value(old)?),
|
||||||
Ok(serde_json::from_value(old)?)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -481,8 +471,8 @@ impl DotPaths for serde_json::Map<String, serde_json::Value> {
|
|||||||
|
|
||||||
impl DotPaths for Vec<serde_json::Value> {
|
impl DotPaths for Vec<serde_json::Value> {
|
||||||
fn dot_get<T>(&self, path: &str) -> Result<Option<T>>
|
fn dot_get<T>(&self, path: &str) -> Result<Option<T>>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
{
|
{
|
||||||
let (my, sub) = path_split(path);
|
let (my, sub) = path_split(path);
|
||||||
|
|
||||||
@@ -497,8 +487,7 @@ impl DotPaths for Vec<serde_json::Value> {
|
|||||||
let index: usize = match my.as_str() {
|
let index: usize = match my.as_str() {
|
||||||
">" => self.len() - 1, // non-empty checked above
|
">" => self.len() - 1, // non-empty checked above
|
||||||
"<" => 0,
|
"<" => 0,
|
||||||
_ => my.parse()
|
_ => my.parse().map_err(|_| InvalidKey(my))?,
|
||||||
.map_err(|_| InvalidKey(my))?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if index >= self.len() {
|
if index >= self.len() {
|
||||||
@@ -508,20 +497,17 @@ impl DotPaths for Vec<serde_json::Value> {
|
|||||||
if let Some(subpath) = sub {
|
if let Some(subpath) = sub {
|
||||||
match self.get(index).null_to_none() {
|
match self.get(index).null_to_none() {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(child) => {
|
Some(child) => child.dot_get(subpath),
|
||||||
child.dot_get(subpath)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match self.get(index).null_to_none() {
|
match self.get(index).null_to_none() {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(value) => {
|
Some(value) => Ok(serde_json::from_value(value.to_owned())?),
|
||||||
Ok(serde_json::from_value(value.to_owned())?)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::collapsible_if)]
|
||||||
fn dot_get_mut(&mut self, path: &str) -> Result<&mut Value> {
|
fn dot_get_mut(&mut self, path: &str) -> Result<&mut Value> {
|
||||||
let (my, sub) = path_split(path);
|
let (my, sub) = path_split(path);
|
||||||
|
|
||||||
@@ -530,14 +516,15 @@ impl DotPaths for Vec<serde_json::Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let index: usize = match my.as_str() {
|
let index: usize = match my.as_str() {
|
||||||
">" => if self.len() == 0 {
|
">" => {
|
||||||
0
|
if self.is_empty() {
|
||||||
} else {
|
0
|
||||||
self.len() - 1
|
} else {
|
||||||
},
|
self.len() - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
"<" => 0,
|
"<" => 0,
|
||||||
_ => my.parse()
|
_ => my.parse().map_err(|_| InvalidKey(my))?,
|
||||||
.map_err(|_| InvalidKey(my))?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if index > self.len() {
|
if index > self.len() {
|
||||||
@@ -546,17 +533,15 @@ impl DotPaths for Vec<serde_json::Value> {
|
|||||||
|
|
||||||
if let Some(subpath) = sub {
|
if let Some(subpath) = sub {
|
||||||
if index < self.len() {
|
if index < self.len() {
|
||||||
self.get_mut(index)
|
self.get_mut(index).unwrap().dot_get_mut(subpath)
|
||||||
.unwrap()
|
|
||||||
.dot_get_mut(subpath)
|
|
||||||
} else {
|
} else {
|
||||||
// create a subtree
|
// create a subtree
|
||||||
self.push(new_by_path_root(subpath, Value::Null)?);
|
self.push(new_by_path_root(subpath, Value::Null)?);
|
||||||
|
|
||||||
// get reference to the new Null
|
// get reference to the new Null
|
||||||
return self.get_mut(index)
|
self.get_mut(index)
|
||||||
.unwrap() // OK, we just inserted it
|
.unwrap() // we just inserted it
|
||||||
.dot_get_mut(subpath);
|
.dot_get_mut(subpath)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if index < self.len() {
|
if index < self.len() {
|
||||||
@@ -566,16 +551,15 @@ impl DotPaths for Vec<serde_json::Value> {
|
|||||||
self.push(Value::Null);
|
self.push(Value::Null);
|
||||||
|
|
||||||
// get reference to the new Null
|
// get reference to the new Null
|
||||||
return Ok(self.get_mut(index)
|
Ok(self.get_mut(index).unwrap()) // unwrap is safe now
|
||||||
.unwrap()); // OK
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::collapsible_if)]
|
||||||
fn dot_set<T>(&mut self, path: &str, value: T) -> Result<()>
|
fn dot_set<T>(&mut self, path: &str, value: T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
// implemented separately from replace because of the special index handling
|
// implemented separately from replace because of the special index handling
|
||||||
let (my_s, sub) = path_split(path);
|
let (my_s, sub) = path_split(path);
|
||||||
@@ -590,10 +574,12 @@ impl DotPaths for Vec<serde_json::Value> {
|
|||||||
|
|
||||||
let index = match my {
|
let index = match my {
|
||||||
"<" => 0, // first
|
"<" => 0, // first
|
||||||
">" => if self.is_empty() {
|
">" => {
|
||||||
0
|
if self.is_empty() {
|
||||||
} else {
|
0
|
||||||
self.len() - 1
|
} else {
|
||||||
|
self.len() - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"-" | "<<" => {
|
"-" | "<<" => {
|
||||||
// prepend
|
// prepend
|
||||||
@@ -607,17 +593,14 @@ impl DotPaths for Vec<serde_json::Value> {
|
|||||||
_ if my.starts_with('>') => {
|
_ if my.starts_with('>') => {
|
||||||
// insert after
|
// insert after
|
||||||
insert = true;
|
insert = true;
|
||||||
(&my[1..]).parse::<usize>()
|
(&my[1..]).parse::<usize>().map_err(|_| InvalidKey(my_s))? + 1
|
||||||
.map_err(|_| InvalidKey(my_s))? + 1
|
|
||||||
}
|
}
|
||||||
_ if my.starts_with('<') => {
|
_ if my.starts_with('<') => {
|
||||||
// insert before
|
// insert before
|
||||||
insert = true;
|
insert = true;
|
||||||
(&my[1..]).parse::<usize>()
|
(&my[1..]).parse::<usize>().map_err(|_| InvalidKey(my_s))?
|
||||||
.map_err(|_| InvalidKey(my_s))?
|
|
||||||
}
|
}
|
||||||
_ => my.parse::<usize>()
|
_ => my.parse::<usize>().map_err(|_| InvalidKey(my_s))?,
|
||||||
.map_err(|_| InvalidKey(my_s))?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if index > self.len() {
|
if index > self.len() {
|
||||||
@@ -655,9 +638,9 @@ impl DotPaths for Vec<serde_json::Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dot_replace<T, U>(&mut self, path: &str, value: T) -> Result<Option<U>>
|
fn dot_replace<T, U>(&mut self, path: &str, value: T) -> Result<Option<U>>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
U: DeserializeOwned,
|
U: DeserializeOwned,
|
||||||
{
|
{
|
||||||
let (my, sub) = path_split(path);
|
let (my, sub) = path_split(path);
|
||||||
|
|
||||||
@@ -666,14 +649,15 @@ impl DotPaths for Vec<serde_json::Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let index: usize = match my.as_str() {
|
let index: usize = match my.as_str() {
|
||||||
">" => if self.is_empty() {
|
">" => {
|
||||||
0
|
if self.is_empty() {
|
||||||
} else {
|
0
|
||||||
self.len() - 1 // last element
|
} else {
|
||||||
},
|
self.len() - 1 // last element
|
||||||
|
}
|
||||||
|
}
|
||||||
"<" => 0,
|
"<" => 0,
|
||||||
_ => my.parse()
|
_ => my.parse().map_err(|_| InvalidKey(my))?,
|
||||||
.map_err(|_| InvalidKey(my))?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if index >= self.len() {
|
if index >= self.len() {
|
||||||
@@ -682,7 +666,8 @@ impl DotPaths for Vec<serde_json::Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(subpath) = sub {
|
if let Some(subpath) = sub {
|
||||||
self.get_mut(index).unwrap() // Bounds checked above
|
self.get_mut(index)
|
||||||
|
.unwrap() // Bounds checked above
|
||||||
.dot_replace(subpath, value)
|
.dot_replace(subpath, value)
|
||||||
} else {
|
} else {
|
||||||
// No subpath
|
// No subpath
|
||||||
@@ -697,8 +682,8 @@ impl DotPaths for Vec<serde_json::Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dot_take<T>(&mut self, path: &str) -> Result<Option<T>>
|
fn dot_take<T>(&mut self, path: &str) -> Result<Option<T>>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
{
|
{
|
||||||
let (my, sub) = path_split(path);
|
let (my, sub) = path_split(path);
|
||||||
|
|
||||||
@@ -707,14 +692,15 @@ impl DotPaths for Vec<serde_json::Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let index: usize = match my.as_str() {
|
let index: usize = match my.as_str() {
|
||||||
">" => if self.is_empty() {
|
">" => {
|
||||||
0
|
if self.is_empty() {
|
||||||
} else {
|
0
|
||||||
self.len() - 1
|
} else {
|
||||||
},
|
self.len() - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
"<" => 0,
|
"<" => 0,
|
||||||
_ => my.parse()
|
_ => my.parse().map_err(|_| InvalidKey(my))?,
|
||||||
.map_err(|_| InvalidKey(my))?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if index >= self.len() {
|
if index >= self.len() {
|
||||||
@@ -873,7 +859,10 @@ mod tests {
|
|||||||
Some(json!([["first", "second"], "mmm", ["xyz"]])),
|
Some(json!([["first", "second"], "mmm", ["xyz"]])),
|
||||||
vec.dot_get("0").unwrap()
|
vec.dot_get("0").unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(Some(json!(["first", "second"])), vec.dot_get("0.0").unwrap());
|
assert_eq!(
|
||||||
|
Some(json!(["first", "second"])),
|
||||||
|
vec.dot_get("0.0").unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -886,8 +875,14 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
assert_eq!(Some(123), vec.dot_get("foo\\.bar.\\\\slashes\\\\\\\\ya\\.yy").unwrap());
|
assert_eq!(
|
||||||
assert_eq!(Some("<aaa>".to_string()), vec.dot_get("foo\\.bar.\\#hash.foobar").unwrap());
|
Some(123),
|
||||||
|
vec.dot_get("foo\\.bar.\\\\slashes\\\\\\\\ya\\.yy").unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Some("<aaa>".to_string()),
|
||||||
|
vec.dot_get("foo\\.bar.\\#hash.foobar").unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -935,7 +930,10 @@ mod tests {
|
|||||||
assert_eq!(Some("b".to_string()), vec.dot_replace("1", "BBB").unwrap());
|
assert_eq!(Some("b".to_string()), vec.dot_replace("1", "BBB").unwrap());
|
||||||
|
|
||||||
let mut vec = json!([[["a"], "b"], "c"]);
|
let mut vec = json!([[["a"], "b"], "c"]);
|
||||||
assert_eq!(Some("a".to_string()), vec.dot_replace("0.0.0", "AAA").unwrap());
|
assert_eq!(
|
||||||
|
Some("a".to_string()),
|
||||||
|
vec.dot_replace("0.0.0", "AAA").unwrap()
|
||||||
|
);
|
||||||
assert_eq!(json!([[["AAA"], "b"], "c"]), vec);
|
assert_eq!(json!([[["AAA"], "b"], "c"]), vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1007,12 +1005,18 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn replace_in_map() {
|
fn replace_in_map() {
|
||||||
let mut vec = json!({"one": "two", "x": "y"});
|
let mut vec = json!({"one": "two", "x": "y"});
|
||||||
assert_eq!(Some("two".to_string()), vec.dot_replace("one", "fff").unwrap());
|
assert_eq!(
|
||||||
|
Some("two".to_string()),
|
||||||
|
vec.dot_replace("one", "fff").unwrap()
|
||||||
|
);
|
||||||
assert_eq!(json!({"one": "fff", "x": "y"}), vec);
|
assert_eq!(json!({"one": "fff", "x": "y"}), vec);
|
||||||
|
|
||||||
// replace value for string
|
// replace value for string
|
||||||
let mut vec = json!({"one": "two", "x": {"bbb": "y"}});
|
let mut vec = json!({"one": "two", "x": {"bbb": "y"}});
|
||||||
assert_eq!(Some("y".to_string()), vec.dot_replace("x.bbb", "mm").unwrap());
|
assert_eq!(
|
||||||
|
Some("y".to_string()),
|
||||||
|
vec.dot_replace("x.bbb", "mm").unwrap()
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(json!({"bbb": "mm"})),
|
Some(json!({"bbb": "mm"})),
|
||||||
vec.dot_replace("x", "betelgeuze").unwrap()
|
vec.dot_replace("x", "betelgeuze").unwrap()
|
||||||
@@ -1039,7 +1043,7 @@ mod tests {
|
|||||||
// Create a parents path
|
// Create a parents path
|
||||||
let mut obj = Value::Null;
|
let mut obj = Value::Null;
|
||||||
let _ = obj.dot_get_mut("foo.0").unwrap();
|
let _ = obj.dot_get_mut("foo.0").unwrap();
|
||||||
assert_eq!(json!({"foo": [null]}), obj);
|
assert_eq!(json!({ "foo": [null] }), obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1047,14 +1051,17 @@ mod tests {
|
|||||||
// Spawn empty element
|
// Spawn empty element
|
||||||
let mut obj = serde_json::Map::<String, Value>::new();
|
let mut obj = serde_json::Map::<String, Value>::new();
|
||||||
let _ = obj.dot_get_mut("foo").unwrap();
|
let _ = obj.dot_get_mut("foo").unwrap();
|
||||||
assert_eq!(json!({"foo": null}), Value::Object(obj));
|
assert_eq!(json!({ "foo": null }), Value::Object(obj));
|
||||||
|
|
||||||
// Spawn a subtree
|
// Spawn a subtree
|
||||||
let mut obj = serde_json::Map::<String, Value>::new();
|
let mut obj = serde_json::Map::<String, Value>::new();
|
||||||
let m = obj.dot_get_mut("foo.bar.baz").unwrap();
|
let m = obj.dot_get_mut("foo.bar.baz").unwrap();
|
||||||
m.dot_set("dog", "cat").unwrap();
|
m.dot_set("dog", "cat").unwrap();
|
||||||
|
|
||||||
assert_eq!(json!({"foo": {"bar": {"baz": {"dog": "cat"}}}}), Value::Object(obj));
|
assert_eq!(
|
||||||
|
json!({"foo": {"bar": {"baz": {"dog": "cat"}}}}),
|
||||||
|
Value::Object(obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1086,30 +1093,52 @@ mod tests {
|
|||||||
face_value: String,
|
face_value: String,
|
||||||
};
|
};
|
||||||
|
|
||||||
stamps.dot_set("0", json!({
|
stamps
|
||||||
"country": "British Mauritius",
|
.dot_set(
|
||||||
"year": 1847,
|
"0",
|
||||||
"color": "orange",
|
json!({
|
||||||
"face value": "1 penny"
|
"country": "British Mauritius",
|
||||||
})).unwrap();
|
"year": 1847,
|
||||||
|
"color": "orange",
|
||||||
|
"face value": "1 penny"
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// append
|
// append
|
||||||
stamps.dot_set("+", Stamp {
|
stamps
|
||||||
country: "British Mauritius".to_string(),
|
.dot_set(
|
||||||
year: 1847,
|
"+",
|
||||||
color: "blue".to_string(),
|
Stamp {
|
||||||
face_value: "2 pence".to_string(),
|
country: "British Mauritius".to_string(),
|
||||||
}).unwrap();
|
year: 1847,
|
||||||
|
color: "blue".to_string(),
|
||||||
|
face_value: "2 pence".to_string(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!("orange", stamps.dot_get::<String>("0.color").unwrap().unwrap());
|
assert_eq!(
|
||||||
assert_eq!("blue", stamps.dot_get::<String>("1.color").unwrap().unwrap());
|
"orange",
|
||||||
|
stamps.dot_get::<String>("0.color").unwrap().unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"blue",
|
||||||
|
stamps.dot_get::<String>("1.color").unwrap().unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(1847, stamps.dot_get::<Stamp>("1").unwrap().unwrap().year);
|
assert_eq!(1847, stamps.dot_get::<Stamp>("1").unwrap().unwrap().year);
|
||||||
|
|
||||||
// Remove the first stamp's "face value" attribute
|
// Remove the first stamp's "face value" attribute
|
||||||
assert_eq!(Some("1 penny".to_string()), stamps.dot_get("0.face value").unwrap());
|
assert_eq!(
|
||||||
|
Some("1 penny".to_string()),
|
||||||
|
stamps.dot_get("0.face value").unwrap()
|
||||||
|
);
|
||||||
stamps.dot_remove("0.face value").unwrap();
|
stamps.dot_remove("0.face value").unwrap();
|
||||||
assert_eq!(Option::<Value>::None, stamps.dot_get("0.face value").unwrap());
|
assert_eq!(
|
||||||
|
Option::<Value>::None,
|
||||||
|
stamps.dot_get("0.face value").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
// change the second stamp's year
|
// change the second stamp's year
|
||||||
let old_year: u32 = stamps.dot_replace("1.year", 1850).unwrap().unwrap();
|
let old_year: u32 = stamps.dot_replace("1.year", 1850).unwrap().unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user