jsonpath_rust/parser/
model.rs

1use crate::parser::errors::JsonPathError;
2use crate::parser::Parsed;
3use std::fmt::{Display, Formatter};
4
5/// Represents a JSONPath query with a list of segments.
6#[derive(Debug, Clone, PartialEq)]
7pub struct JpQuery {
8    pub segments: Vec<Segment>,
9}
10
11impl JpQuery {
12    pub fn new(segments: Vec<Segment>) -> Self {
13        JpQuery { segments }
14    }
15}
16
17impl Display for JpQuery {
18    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
19        write!(
20            f,
21            "${}",
22            self.segments
23                .iter()
24                .map(|s| s.to_string())
25                .collect::<String>()
26        )
27    }
28}
29/// Enum representing different types of segments in a JSONPath query.
30#[derive(Debug, Clone, PartialEq)]
31pub enum Segment {
32    /// Represents a descendant segment.
33    Descendant(Box<Segment>),
34    /// Represents a selector segment.
35    Selector(Selector),
36    /// Represents multiple selectors.
37    Selectors(Vec<Selector>),
38}
39
40impl Segment {
41    pub fn name(name: &str) -> Self {
42        Segment::Selector(Selector::Name(name.to_string()))
43    }
44}
45
46impl Display for Segment {
47    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
48        match self {
49            Segment::Descendant(s) => write!(f, "..{}", s),
50            Segment::Selector(selector) => write!(f, "{}", selector),
51            Segment::Selectors(selectors) => write!(
52                f,
53                "{}",
54                selectors.iter().map(|s| s.to_string()).collect::<String>()
55            ),
56        }
57    }
58}
59/// Enum representing different types of selectors in a JSONPath query.
60#[derive(Debug, Clone, PartialEq)]
61pub enum Selector {
62    /// Represents a name selector.
63    Name(String),
64    /// Represents a wildcard selector.
65    Wildcard,
66    /// Represents an index selector.
67    Index(i64),
68    /// Represents a slice selector.
69    Slice(Option<i64>, Option<i64>, Option<i64>),
70    /// Represents a filter selector.
71    Filter(Filter),
72}
73
74pub fn slice_from((start, end, step): (Option<i64>, Option<i64>, Option<i64>)) -> Selector {
75    Selector::Slice(start, end, step)
76}
77
78impl Display for Selector {
79    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
80        match self {
81            Selector::Name(name) => write!(f, "{}", name),
82            Selector::Wildcard => write!(f, "*"),
83            Selector::Index(index) => write!(f, "{}", index),
84            Selector::Slice(start, end, step) => write!(
85                f,
86                "{}:{}:{}",
87                start.unwrap_or(0),
88                end.unwrap_or(0),
89                step.unwrap_or(1)
90            ),
91            Selector::Filter(filter) => write!(f, "[?{}]", filter),
92        }
93    }
94}
95/// Enum representing different types of filters in a JSONPath query.
96#[derive(Debug, Clone, PartialEq)]
97pub enum Filter {
98    /// Represents a logical OR filter.
99    Or(Vec<Filter>),
100    /// Represents a logical AND filter.
101    And(Vec<Filter>),
102    /// Represents an atomic filter.
103    Atom(FilterAtom),
104}
105
106impl Display for Filter {
107    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
108        let items_to_str = |items: &Vec<Filter>, sep: &str| {
109            items
110                .iter()
111                .map(|f| f.to_string())
112                .collect::<Vec<_>>()
113                .join(sep)
114        };
115
116        match self {
117            Filter::Or(filters) => write!(f, "{}", items_to_str(filters, " || ")),
118            Filter::And(filters) => write!(f, "{}", items_to_str(filters, " && ")),
119            Filter::Atom(atom) => write!(f, "{}", atom),
120        }
121    }
122}
123
124/// Enum representing different types of atomic filters in a JSONPath query.
125#[derive(Debug, Clone, PartialEq)]
126pub enum FilterAtom {
127    /// Represents a nested filter with an optional NOT flag.
128    Filter { expr: Box<Filter>, not: bool },
129    /// Represents a test filter with an optional NOT flag.
130    Test { expr: Box<Test>, not: bool },
131    /// Represents a comparison filter.
132    Comparison(Box<Comparison>),
133}
134
135impl FilterAtom {
136    pub fn filter(expr: Filter, not: bool) -> Self {
137        FilterAtom::Filter {
138            expr: Box::new(expr),
139            not,
140        }
141    }
142
143    pub fn test(expr: Test, not: bool) -> Self {
144        FilterAtom::Test {
145            expr: Box::new(expr),
146            not,
147        }
148    }
149
150    pub fn cmp(cmp: Box<Comparison>) -> Self {
151        FilterAtom::Comparison(cmp)
152    }
153}
154
155impl Display for FilterAtom {
156    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
157        match self {
158            FilterAtom::Filter { expr, not } => {
159                if *not {
160                    write!(f, "!{}", expr)
161                } else {
162                    write!(f, "{}", expr)
163                }
164            }
165            FilterAtom::Test { expr, not } => {
166                if *not {
167                    write!(f, "!{}", expr)
168                } else {
169                    write!(f, "{}", expr)
170                }
171            }
172            FilterAtom::Comparison(cmp) => write!(f, "{}", cmp),
173        }
174    }
175}
176/// Enum representing different types of comparisons in a JSONPath query.
177#[derive(Debug, Clone, PartialEq)]
178pub enum Comparison {
179    /// Represents an equality comparison.
180    Eq(Comparable, Comparable),
181    /// Represents a non-equality comparison.
182    Ne(Comparable, Comparable),
183    /// Represents a greater-than comparison.
184    Gt(Comparable, Comparable),
185    /// Represents a greater-than-or-equal-to comparison.
186    Gte(Comparable, Comparable),
187    /// Represents a less-than comparison.
188    Lt(Comparable, Comparable),
189    /// Represents a less-than-or-equal-to comparison.
190    Lte(Comparable, Comparable),
191}
192
193impl Comparison {
194    pub fn try_new(op: &str, left: Comparable, right: Comparable) -> Parsed<Self> {
195        match op {
196            "==" => Ok(Comparison::Eq(left, right)),
197            "!=" => Ok(Comparison::Ne(left, right)),
198            ">" => Ok(Comparison::Gt(left, right)),
199            ">=" => Ok(Comparison::Gte(left, right)),
200            "<" => Ok(Comparison::Lt(left, right)),
201            "<=" => Ok(Comparison::Lte(left, right)),
202            _ => Err(JsonPathError::InvalidJsonPath(format!(
203                "Invalid comparison operator: {}",
204                op
205            ))),
206        }
207    }
208
209    pub fn vals(&self) -> (&Comparable, &Comparable) {
210        match self {
211            Comparison::Eq(left, right) => (left, right),
212            Comparison::Ne(left, right) => (left, right),
213            Comparison::Gt(left, right) => (left, right),
214            Comparison::Gte(left, right) => (left, right),
215            Comparison::Lt(left, right) => (left, right),
216            Comparison::Lte(left, right) => (left, right),
217        }
218    }
219}
220
221impl Display for Comparison {
222    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
223        match self {
224            Comparison::Eq(left, right) => write!(f, "{} == {}", left, right),
225            Comparison::Ne(left, right) => write!(f, "{} != {}", left, right),
226            Comparison::Gt(left, right) => write!(f, "{} > {}", left, right),
227            Comparison::Gte(left, right) => write!(f, "{} >= {}", left, right),
228            Comparison::Lt(left, right) => write!(f, "{} < {}", left, right),
229            Comparison::Lte(left, right) => write!(f, "{} <= {}", left, right),
230        }
231    }
232}
233
234/// Enum representing different types of comparable values in a JSONPath query.
235#[derive(Debug, Clone, PartialEq)]
236pub enum Comparable {
237    /// Represents a literal value.
238    Literal(Literal),
239    /// Represents a function.
240    Function(TestFunction),
241    /// Represents a singular query.
242    SingularQuery(SingularQuery),
243}
244
245impl Display for Comparable {
246    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
247        match self {
248            Comparable::Literal(literal) => write!(f, "{}", literal),
249            Comparable::Function(func) => write!(f, "{}", func),
250            Comparable::SingularQuery(query) => write!(f, "{}", query),
251        }
252    }
253}
254
255/// Enum representing different types of singular queries in a JSONPath query.
256#[derive(Debug, Clone, PartialEq)]
257pub enum SingularQuery {
258    /// Represents a current node query.
259    Current(Vec<SingularQuerySegment>),
260    /// Represents a root node query.
261    Root(Vec<SingularQuerySegment>),
262}
263
264impl Display for SingularQuery {
265    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
266        match self {
267            SingularQuery::Current(segments) => write!(
268                f,
269                "@.{}",
270                segments.iter().map(|s| s.to_string()).collect::<String>()
271            ),
272            SingularQuery::Root(segments) => write!(
273                f,
274                "$.{}",
275                segments.iter().map(|s| s.to_string()).collect::<String>()
276            ),
277        }
278    }
279}
280
281/// Enum representing different types of singular query segments in a JSONPath query.
282#[derive(Debug, Clone, PartialEq)]
283pub enum SingularQuerySegment {
284    /// Represents an index segment.
285    Index(i64),
286    /// Represents a name segment.
287    Name(String),
288}
289
290impl Display for SingularQuerySegment {
291    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
292        match self {
293            SingularQuerySegment::Index(index) => write!(f, "{}", index),
294            SingularQuerySegment::Name(name) => write!(f, "{}", name),
295        }
296    }
297}
298
299/// Enum representing different types of tests in a JSONPath query.
300#[derive(Debug, Clone, PartialEq)]
301pub enum Test {
302    /// Represents a relative query.
303    RelQuery(Vec<Segment>),
304    /// Represents an absolute query.
305    AbsQuery(JpQuery),
306    /// Represents a function test.
307    Function(Box<TestFunction>),
308}
309
310impl Test {
311    pub fn is_res_bool(&self) -> bool {
312        match self {
313            Test::RelQuery(_) => false,
314            Test::AbsQuery(_) => false,
315            Test::Function(func) => match **func {
316                TestFunction::Length(_) => false,
317                TestFunction::Value(_) => false,
318                TestFunction::Count(_) => false,
319                TestFunction::Custom(_, _) => true,
320                TestFunction::Search(_, _) => true,
321                TestFunction::Match(_, _) => true,
322            },
323        }
324    }
325}
326
327impl Display for Test {
328    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
329        match self {
330            Test::RelQuery(segments) => write!(
331                f,
332                "{}",
333                segments.iter().map(|s| s.to_string()).collect::<String>()
334            ),
335            Test::AbsQuery(query) => write!(f, "{}", query),
336            Test::Function(func) => write!(f, "{}", func),
337        }
338    }
339}
340
341/// Enum representing different types of test functions in a JSONPath query.
342#[derive(Debug, Clone, PartialEq)]
343pub enum TestFunction {
344    /// Represents a custom function.
345    Custom(String, Vec<FnArg>),
346    /// Represents a length function.
347    Length(Box<FnArg>),
348    /// Represents a value function.
349    Value(FnArg),
350    /// Represents a count function.
351    Count(FnArg),
352    /// Represents a search function.
353    Search(FnArg, FnArg),
354    /// Represents a match function.
355    Match(FnArg, FnArg),
356}
357
358impl TestFunction {
359    pub fn try_new(name: &str, args: Vec<FnArg>) -> Parsed<Self> {
360        fn with_node_type_validation<'a>(
361            a: &'a FnArg,
362            name: &str,
363        ) -> Result<&'a FnArg, JsonPathError> {
364            if a.is_lit() {
365                Err(JsonPathError::InvalidJsonPath(format!(
366                    "Invalid argument for the function `{}`: expected a node, got a literal",
367                    name
368                )))
369            } else if a.is_filter() {
370                Err(JsonPathError::InvalidJsonPath(format!(
371                    "Invalid argument for the function `{}`: expected a node, got a filter",
372                    name
373                )))
374            } else {
375                Ok(a)
376            }
377        }
378
379        match (name, args.as_slice()) {
380            ("length", [a]) => Ok(TestFunction::Length(Box::new(a.clone()))),
381            ("value", [a]) => Ok(TestFunction::Value(a.clone())),
382            ("count", [a]) => Ok(TestFunction::Count(
383                with_node_type_validation(a, name)?.clone(),
384            )),
385            ("search", [a, b]) => Ok(TestFunction::Search(a.clone(), b.clone())),
386            ("match", [a, b]) => Ok(TestFunction::Match(a.clone(), b.clone())),
387            ("length" | "value" | "count" | "match" | "search", args) => {
388                Err(JsonPathError::InvalidJsonPath(format!(
389                    "Invalid number of arguments for the function `{}`: got {}",
390                    name,
391                    args.len()
392                )))
393            }
394            (custom, _) => Ok(TestFunction::Custom(custom.to_string(), args)),
395        }
396    }
397
398    pub fn is_comparable(&self) -> bool {
399        match self {
400            TestFunction::Length(_) => true,
401            TestFunction::Value(_) => true,
402            TestFunction::Count(_) => true,
403            TestFunction::Custom(_, _) => false,
404            TestFunction::Search(_, _) => false,
405            TestFunction::Match(_, _) => false,
406        }
407    }
408}
409
410impl Display for TestFunction {
411    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
412        match self {
413            TestFunction::Custom(name, args) => write!(
414                f,
415                "{}({})",
416                name,
417                args.iter().map(|a| a.to_string()).collect::<String>()
418            ),
419            TestFunction::Length(arg) => write!(f, "length({})", arg),
420            TestFunction::Value(arg) => write!(f, "value({})", arg),
421            TestFunction::Count(arg) => write!(f, "count({})", arg),
422            TestFunction::Search(arg1, arg2) => write!(f, "search({}, {})", arg1, arg2),
423            TestFunction::Match(arg1, arg2) => write!(f, "match({}, {})", arg1, arg2),
424        }
425    }
426}
427
428/// Enum representing different types of function arguments in a JSONPath query.
429#[derive(Debug, Clone, PartialEq)]
430pub enum FnArg {
431    /// Represents a literal argument.
432    Literal(Literal),
433    /// Represents a test argument.
434    Test(Box<Test>),
435    /// Represents a filter argument.
436    Filter(Filter),
437}
438
439impl FnArg {
440    pub fn is_lit(&self) -> bool {
441        matches!(self, FnArg::Literal(_))
442    }
443    pub fn is_filter(&self) -> bool {
444        matches!(self, FnArg::Filter(_))
445    }
446}
447
448impl Display for FnArg {
449    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
450        match self {
451            FnArg::Literal(literal) => write!(f, "{}", literal),
452            FnArg::Test(test) => write!(f, "{}", test),
453            FnArg::Filter(filter) => write!(f, "{}", filter),
454        }
455    }
456}
457
458/// Enum representing different types of literal values in a JSONPath query.
459#[derive(Debug, Clone, PartialEq)]
460pub enum Literal {
461    /// Represents an integer literal.
462    Int(i64),
463    /// Represents a floating-point literal.
464    Float(f64),
465    /// Represents a string literal.
466    String(String),
467    /// Represents a boolean literal.
468    Bool(bool),
469    /// Represents a null literal.
470    Null,
471}
472
473impl Display for Literal {
474    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
475        match self {
476            Literal::Int(val) => write!(f, "{}", val),
477            Literal::Float(val) => write!(f, "{}", val),
478            Literal::String(val) => write!(f, "\"{}\"", val),
479            Literal::Bool(val) => write!(f, "{}", val),
480            Literal::Null => write!(f, "null"),
481        }
482    }
483}