diff --git a/serde_json_path/src/path.rs b/serde_json_path/src/path.rs index c957370..756dd49 100644 --- a/serde_json_path/src/path.rs +++ b/serde_json_path/src/path.rs @@ -4,7 +4,10 @@ use serde::{de::Visitor, Deserialize, Serialize}; use serde_json::Value; use serde_json_path_core::{ node::NodeList, - spec::query::{Query, Queryable}, + spec::{ + path::NormalizedPath, + query::{Query, Queryable}, + }, }; use crate::{parser::parse_query_main, ParseError}; @@ -75,6 +78,10 @@ impl JsonPath { pub fn query<'b>(&self, value: &'b Value) -> NodeList<'b> { self.0.query(value, value).into() } + + pub fn query_paths<'b>(&self, value: &'b Value) -> Vec<(NormalizedPath<'b>, &'b Value)> { + self.0.query_paths_init(value, value) + } } impl FromStr for JsonPath { @@ -153,4 +160,16 @@ mod tests { .expect("round trip"); assert_eq!(p1, p2); } + + #[test] + fn norm_paths() { + let j = json!({"foo": { + "bar": [1, 2, 3] + }}); + let p = JsonPath::parse("$.foo.bar.*").unwrap(); + let r = p.query_paths(&j); + for (np, _) in r { + println!("{pointer}", pointer = np.as_json_pointer()); + } + } } diff --git a/serde_json_path_core/src/spec/path.rs b/serde_json_path_core/src/spec/path.rs index 40792df..6aad4cd 100644 --- a/serde_json_path_core/src/spec/path.rs +++ b/serde_json_path_core/src/spec/path.rs @@ -1,9 +1,17 @@ -use std::ops::{Deref, DerefMut}; - -#[derive(Clone)] +#[derive(Debug, Clone, Default)] pub struct NormalizedPath<'a>(Vec>); impl<'a> NormalizedPath<'a> { + pub(crate) fn push>>(&mut self, elem: T) { + self.0.push(elem.into()) + } + + pub(crate) fn clone_and_push>>(&self, elem: T) -> Self { + let mut new_path = self.clone(); + new_path.push(elem.into()); + new_path + } + pub fn as_json_pointer(&self) -> String { self.0 .iter() @@ -16,21 +24,7 @@ impl<'a> NormalizedPath<'a> { } } -impl<'a> Deref for NormalizedPath<'a> { - type Target = Vec>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl<'a> DerefMut for NormalizedPath<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -#[derive(Clone, Copy)] +#[derive(Debug, Clone, Copy)] pub enum PathElement<'a> { Name(&'a str), Index(usize), diff --git a/serde_json_path_core/src/spec/query.rs b/serde_json_path_core/src/spec/query.rs index c3e73c2..9a71fae 100644 --- a/serde_json_path_core/src/spec/query.rs +++ b/serde_json_path_core/src/spec/query.rs @@ -36,9 +36,16 @@ pub trait Queryable: sealed::Sealed { fn query_paths<'b>( &self, current: &'b Value, - _root: &'b Value, + root: &'b Value, parent: NormalizedPath<'b>, - ) -> Vec>; + ) -> Vec<(NormalizedPath<'b>, &'b Value)>; + fn query_paths_init<'b>( + &self, + current: &'b Value, + root: &'b Value, + ) -> Vec<(NormalizedPath<'b>, &'b Value)> { + self.query_paths(current, root, Default::default()) + } } /// Represents a JSONPath expression @@ -107,9 +114,20 @@ impl Queryable for Query { fn query_paths<'b>( &self, current: &'b Value, - _root: &'b Value, - parent: NormalizedPath<'b>, - ) -> Vec> { - todo!() + root: &'b Value, + _parent: NormalizedPath<'b>, + ) -> Vec<(NormalizedPath<'b>, &'b Value)> { + let mut result: Vec<(NormalizedPath<'b>, &Value)> = match self.kind { + QueryKind::Root => vec![(Default::default(), root)], + QueryKind::Current => vec![(Default::default(), current)], + }; + for s in &self.segments { + let mut r = vec![]; + for (ref np, v) in result { + r.append(&mut s.query_paths(v, root, np.clone())); + } + result = r; + } + result } } diff --git a/serde_json_path_core/src/spec/segment.rs b/serde_json_path_core/src/spec/segment.rs index 5671c7b..f35d81f 100644 --- a/serde_json_path_core/src/spec/segment.rs +++ b/serde_json_path_core/src/spec/segment.rs @@ -1,7 +1,7 @@ //! Types representing segments in JSONPath use serde_json::Value; -use super::{query::Queryable, selector::Selector}; +use super::{path::NormalizedPath, query::Queryable, selector::Selector}; /// A segment of a JSONPath query #[derive(Debug, PartialEq, Eq, Clone)] @@ -59,10 +59,16 @@ impl Queryable for QuerySegment { fn query_paths<'b>( &self, current: &'b Value, - _root: &'b Value, - parent: super::path::NormalizedPath<'b>, - ) -> Vec> { - todo!() + root: &'b Value, + parent: NormalizedPath<'b>, + ) -> Vec<(NormalizedPath<'b>, &'b Value)> { + if matches!(self.kind, QuerySegmentKind::Descendant) { + let mut result = self.segment.query_paths(current, root, parent.clone()); + result.append(&mut descend_paths(self, current, root, parent)); + result + } else { + self.segment.query_paths(current, root, parent) + } } } @@ -81,6 +87,25 @@ fn descend<'b>(segment: &QuerySegment, current: &'b Value, root: &'b Value) -> V query } +fn descend_paths<'b>( + segment: &QuerySegment, + current: &'b Value, + root: &'b Value, + parent: NormalizedPath<'b>, +) -> Vec<(NormalizedPath<'b>, &'b Value)> { + let mut result = Vec::new(); + if let Some(list) = current.as_array() { + for (i, v) in list.iter().enumerate() { + result.append(&mut segment.query_paths(v, root, parent.clone_and_push(i))); + } + } else if let Some(obj) = current.as_object() { + for (k, v) in obj { + result.append(&mut segment.query_paths(v, root, parent.clone_and_push(k))); + } + } + result +} + /// Represents the different forms of JSONPath segment #[derive(Debug, PartialEq, Eq, Clone)] pub enum Segment { @@ -187,9 +212,34 @@ impl Queryable for Segment { fn query_paths<'b>( &self, current: &'b Value, - _root: &'b Value, - parent: super::path::NormalizedPath<'b>, - ) -> Vec> { - todo!() + root: &'b Value, + mut parent: NormalizedPath<'b>, + ) -> Vec<(NormalizedPath<'b>, &'b Value)> { + let mut result = vec![]; + match self { + Segment::LongHand(selectors) => { + for s in selectors { + result.append(&mut s.query_paths(current, root, parent.clone())); + } + } + Segment::DotName(name) => { + if let Some((k, v)) = current.as_object().and_then(|o| o.get_key_value(name)) { + parent.push(k); + result.push((parent, v)); + } + } + Segment::Wildcard => { + if let Some(list) = current.as_array() { + for (i, v) in list.iter().enumerate() { + result.push((parent.clone_and_push(i), v)); + } + } else if let Some(obj) = current.as_object() { + for (k, v) in obj { + result.push((parent.clone_and_push(k), v)); + } + } + } + } + result } } diff --git a/serde_json_path_core/src/spec/selector/filter.rs b/serde_json_path_core/src/spec/selector/filter.rs index bf1394f..cb5e30e 100644 --- a/serde_json_path_core/src/spec/selector/filter.rs +++ b/serde_json_path_core/src/spec/selector/filter.rs @@ -3,6 +3,7 @@ use serde_json::{Number, Value}; use crate::spec::{ functions::{FunctionExpr, JsonPathValue, Validated}, + path::NormalizedPath, query::{Query, QueryKind, Queryable}, segment::{QuerySegment, Segment}, }; @@ -73,10 +74,23 @@ impl Queryable for Filter { fn query_paths<'b>( &self, current: &'b Value, - _root: &'b Value, - parent: crate::spec::path::NormalizedPath<'b>, - ) -> Vec> { - todo!() + root: &'b Value, + parent: NormalizedPath<'b>, + ) -> Vec<(NormalizedPath<'b>, &'b Value)> { + if let Some(list) = current.as_array() { + list.iter() + .enumerate() + .filter(|(_, v)| self.0.test_filter(v, root)) + .map(|(i, v)| (parent.clone_and_push(i), v)) + .collect() + } else if let Some(obj) = current.as_object() { + obj.iter() + .filter(|(_, v)| self.0.test_filter(v, root)) + .map(|(k, v)| (parent.clone_and_push(k), v)) + .collect() + } else { + vec![] + } } } @@ -567,24 +581,6 @@ impl TryFrom for SingularQuery { } } -impl Queryable for SingularQuery { - fn query<'b>(&self, current: &'b Value, root: &'b Value) -> Vec<&'b Value> { - match self.eval_query(current, root) { - Some(v) => vec![v], - None => vec![], - } - } - - fn query_paths<'b>( - &self, - current: &'b Value, - _root: &'b Value, - parent: crate::spec::path::NormalizedPath<'b>, - ) -> Vec> { - todo!() - } -} - impl std::fmt::Display for SingularQuery { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self.kind { diff --git a/serde_json_path_core/src/spec/selector/index.rs b/serde_json_path_core/src/spec/selector/index.rs index 3a2c6a6..55d5a4a 100644 --- a/serde_json_path_core/src/spec/selector/index.rs +++ b/serde_json_path_core/src/spec/selector/index.rs @@ -44,21 +44,22 @@ impl Queryable for Index { current: &'b Value, _root: &'b Value, mut parent: NormalizedPath<'b>, - ) -> Vec> { - if let Some(index) = current.as_array().and_then(|list| { + ) -> Vec<(NormalizedPath<'b>, &'b Value)> { + if let Some((index, value)) = current.as_array().and_then(|list| { if self.0 < 0 { self.0 .checked_abs() .and_then(|i| usize::try_from(i).ok()) .and_then(|i| list.len().checked_sub(i)) + .and_then(|i| list.get(i).map(|v| (i, v))) } else { usize::try_from(self.0) .ok() - .and_then(|i| (list.len() >= i).then_some(i)) + .and_then(|i| list.get(i).map(|v| (i, v))) } }) { - parent.push(index.into()); - vec![parent] + parent.push(index); + vec![(parent, value)] } else { vec![] } diff --git a/serde_json_path_core/src/spec/selector/mod.rs b/serde_json_path_core/src/spec/selector/mod.rs index a88f7b1..1c0dac3 100644 --- a/serde_json_path_core/src/spec/selector/mod.rs +++ b/serde_json_path_core/src/spec/selector/mod.rs @@ -79,25 +79,25 @@ impl Queryable for Selector { current: &'b Value, root: &'b Value, parent: NormalizedPath<'b>, - ) -> Vec> { + ) -> Vec<(NormalizedPath<'b>, &'b Value)> { match self { Selector::Name(name) => name.query_paths(current, root, parent), Selector::Wildcard => { if let Some(list) = current.as_array() { list.iter() .enumerate() - .map(|(i, _)| { + .map(|(i, v)| { let mut new_path = parent.clone(); new_path.push(PathElement::from(i)); - new_path + (new_path, v) }) .collect() } else if let Some(obj) = current.as_object() { - obj.keys() - .map(|k| { + obj.iter() + .map(|(k, v)| { let mut new_path = parent.clone(); new_path.push(PathElement::from(k)); - new_path + (new_path, v) }) .collect() } else { diff --git a/serde_json_path_core/src/spec/selector/name.rs b/serde_json_path_core/src/spec/selector/name.rs index 0f116b0..b47dc3c 100644 --- a/serde_json_path_core/src/spec/selector/name.rs +++ b/serde_json_path_core/src/spec/selector/name.rs @@ -35,10 +35,10 @@ impl Queryable for Name { current: &'b Value, _root: &'b Value, mut parent: NormalizedPath<'b>, - ) -> Vec> { - if let Some((s, _)) = current.as_object().and_then(|o| o.get_key_value(&self.0)) { - parent.push(s.into()); - vec![parent] + ) -> Vec<(NormalizedPath<'b>, &'b Value)> { + if let Some((s, v)) = current.as_object().and_then(|o| o.get_key_value(&self.0)) { + parent.push(s); + vec![(parent, v)] } else { vec![] } diff --git a/serde_json_path_core/src/spec/selector/slice.rs b/serde_json_path_core/src/spec/selector/slice.rs index 551f14d..1e44bfb 100644 --- a/serde_json_path_core/src/spec/selector/slice.rs +++ b/serde_json_path_core/src/spec/selector/slice.rs @@ -1,7 +1,7 @@ //! Slice selectors for selecting array slices in JSONPath use serde_json::Value; -use crate::spec::query::Queryable; +use crate::spec::{path::NormalizedPath, query::Queryable}; /// A slice selector #[derive(Debug, PartialEq, Eq, Default, Clone, Copy)] @@ -59,6 +59,34 @@ impl Slice { self.step = Some(step); self } + + #[inline] + fn bounds_on_forward_slice(&self, len: isize) -> (isize, isize) { + let start_default = self.start.unwrap_or(0); + let end_default = self.end.unwrap_or(len); + let start = normalize_slice_index(start_default, len) + .unwrap_or(0) + .max(0); + let end = normalize_slice_index(end_default, len).unwrap_or(0).max(0); + let lower = start.min(len); + let upper = end.min(len); + (lower, upper) + } + + #[inline] + fn bounds_on_reverse_slice(&self, len: isize) -> Option<(isize, isize)> { + let start_default = self.start.or_else(|| len.checked_sub(1))?; + let end_default = self + .end + .or_else(|| len.checked_mul(-1).and_then(|l| l.checked_sub(1)))?; + let start = normalize_slice_index(start_default, len) + .unwrap_or(0) + .max(-1); + let end = normalize_slice_index(end_default, len).unwrap_or(0).max(-1); + let lower = end.min(len.checked_sub(1).unwrap_or(len)); + let upper = start.min(len.checked_sub(1).unwrap_or(len)); + Some((lower, upper)) + } } impl Queryable for Slice { @@ -74,14 +102,7 @@ impl Queryable for Slice { return vec![]; }; if step > 0 { - let start_default = self.start.unwrap_or(0); - let end_default = self.end.unwrap_or(len); - let start = normalize_slice_index(start_default, len) - .unwrap_or(0) - .max(0); - let end = normalize_slice_index(end_default, len).unwrap_or(0).max(0); - let lower = start.min(len); - let upper = end.min(len); + let (lower, upper) = self.bounds_on_forward_slice(len); let mut i = lower; while i < upper { if let Some(v) = usize::try_from(i).ok().and_then(|i| list.get(i)) { @@ -90,21 +111,9 @@ impl Queryable for Slice { i += step; } } else { - let Some(start_default) = self.start.or_else(|| len.checked_sub(1)) else { + let Some((lower, upper)) = self.bounds_on_reverse_slice(len) else { return vec![]; }; - let Some(end_default) = self - .end - .or_else(|| len.checked_mul(-1).and_then(|l| l.checked_sub(1))) - else { - return vec![]; - }; - let start = normalize_slice_index(start_default, len) - .unwrap_or(0) - .max(-1); - let end = normalize_slice_index(end_default, len).unwrap_or(0).max(-1); - let lower = end.min(len.checked_sub(1).unwrap_or(len)); - let upper = start.min(len.checked_sub(1).unwrap_or(len)); let mut i = upper; while lower < i { if let Some(v) = usize::try_from(i).ok().and_then(|i| list.get(i)) { @@ -123,9 +132,48 @@ impl Queryable for Slice { &self, current: &'b Value, _root: &'b Value, - parent: crate::spec::path::NormalizedPath<'b>, - ) -> Vec> { - todo!() + parent: NormalizedPath<'b>, + ) -> Vec<(NormalizedPath<'b>, &'b Value)> { + if let Some(list) = current.as_array() { + let mut result = Vec::new(); + let step = self.step.unwrap_or(1); + if step == 0 { + return vec![]; + } + let Ok(len) = isize::try_from(list.len()) else { + return vec![]; + }; + if step > 0 { + let (lower, upper) = self.bounds_on_forward_slice(len); + let mut i = lower; + while i < upper { + if let Some((i, v)) = usize::try_from(i) + .ok() + .and_then(|i| list.get(i).map(|v| (i, v))) + { + result.push((parent.clone_and_push(i), v)); + } + i += step; + } + } else { + let Some((lower, upper)) = self.bounds_on_reverse_slice(len) else { + return vec![]; + }; + let mut i = upper; + while lower < i { + if let Some((i, v)) = usize::try_from(i) + .ok() + .and_then(|i| list.get(i).map(|v| (i, v))) + { + result.push((parent.clone_and_push(i), v)); + } + i += step; + } + } + result + } else { + vec![] + } } }