Skip to content

Commit 7259ac6

Browse files
committed
add sing query
1 parent fb99476 commit 7259ac6

File tree

5 files changed

+114
-25
lines changed

5 files changed

+114
-25
lines changed

src/parser/grammar/json_path_9535.pest

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ paren_expr = {not_op? ~ S ~ "(" ~ S ~ logical_expr_or ~ S ~ ")"}
2121
comp_expr = { comparable ~ S ~ comp_op ~ S ~ comparable }
2222
test_expr = {not_op? ~ S ~ (filter_query | function_expr)}
2323
function_expr = { function_name ~ "(" ~ S ~ (function_argument ~ (S ~ "," ~ S ~ function_argument)*)? ~ S ~ ")" }
24+
function_name = { function_name_first ~ function_name_char* }
25+
function_name_first = { LCALPHA }
26+
function_name_char = { function_name_first | "_" | DIGIT }
2427
function_argument = { literal | filter_query | logical_expr_or | function_expr }
2528
filter_query = {rel_query | jp_query}
2629
rel_query = {curr ~ S ~ segments}
@@ -35,9 +38,7 @@ singular_query_segments = { (S ~ (name_segment | index_segment))* }
3538
name_segment = { ("[" ~ name_selector ~ "]") | ("." ~ member_name_shorthand) }
3639
index_segment = { "[" ~ index_selector ~ "]" }
3740
comp_op = { "==" | "!=" | "<=" | ">=" | "<" | ">" }
38-
function_name = { function_name_first ~ function_name_char* }
39-
function_name_first = { LCALPHA }
40-
function_name_char = { function_name_first | "_" | DIGIT }
41+
4142
LCALPHA = { 'a'..'z' }
4243

4344

@@ -52,7 +53,7 @@ member_name_shorthand = { name_first ~ name_char* }
5253
name_first = { ALPHA | "_" | '\u{0080}'..'\u{D7FF}' | '\u{E000}'..'\u{10FFFF}' }
5354
name_char = { name_first | DIGIT }
5455
not_op = {"!"}
55-
curr = {"@"}
56+
curr = _{"@"}
5657
ESC = _{ "\\" }
5758
unescaped = _{
5859
'\u{0020}'..'\u{0021}' |

src/parser/macros2.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::parser::model2::Literal;
1+
use crate::parser::model2::{Literal, SingularQuery};
22

33
#[macro_export]
44
macro_rules! lit {
@@ -7,4 +7,33 @@ macro_rules! lit {
77
(s$s:expr) => { Literal::String($s.to_string()) };
88
(i$n:expr) => { Literal::Int($n) };
99
(f$n:expr) => { Literal::Float($n) };
10+
}
11+
12+
#[macro_export]
13+
macro_rules! q_segments {
14+
($segment:tt) => {
15+
vec![q_segment!($segment)]
16+
};
17+
// Recursive case: multiple segments
18+
($segment:tt $($rest:tt)*) => {{
19+
let mut segments = q_segments!($($rest)*);
20+
segments.insert(0, q_segment!($segment));
21+
segments
22+
}};
23+
}
24+
25+
#[macro_export]
26+
macro_rules! q_segment {
27+
($name:ident) => { SingularQuerySegment::Name(stringify!($name).to_string()) };
28+
([$name:ident]) => { SingularQuerySegment::Name(format!("\"{}\"", stringify!($name))) };
29+
([$index:expr]) => { SingularQuerySegment::Index($index) };
30+
}
31+
#[macro_export]
32+
macro_rules! singular_query {
33+
(@$($segment:tt)*) => {
34+
SingularQuery::Current(q_segments!($($segment)*))
35+
};
36+
($($segment:tt)*) => {
37+
SingularQuery::Root(q_segments!($($segment)*))
38+
};
1039
}

src/parser/model2.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use std::fmt::{Display, Formatter};
2+
use crate::parser::errors2::JsonPathParserError;
3+
use crate::parser::parser2::Parsed;
24

35
/// Represents a JSONPath query with a list of segments.
46
#[derive(Debug, Clone)]
@@ -171,8 +173,8 @@ impl Display for Comparable {
171173
}
172174

173175
/// Enum representing different types of singular queries in a JSONPath query.
174-
#[derive(Debug, Clone)]
175-
enum SingularQuery {
176+
#[derive(Debug, Clone, PartialEq)]
177+
pub enum SingularQuery {
176178
/// Represents a current node query.
177179
Current(Vec<SingularQuerySegment>),
178180
/// Represents a root node query.
@@ -189,8 +191,8 @@ impl Display for SingularQuery {
189191
}
190192

191193
/// Enum representing different types of singular query segments in a JSONPath query.
192-
#[derive(Debug, Clone)]
193-
enum SingularQuerySegment {
194+
#[derive(Debug, Clone, PartialEq)]
195+
pub enum SingularQuerySegment {
194196
/// Represents an index segment.
195197
Index(i64),
196198
/// Represents a name segment.
@@ -244,6 +246,21 @@ enum TestFunction {
244246
Match(FnArg, FnArg),
245247
}
246248

249+
impl TestFunction {
250+
pub fn new(name: &str, args: Vec<FnArg>) -> Parsed<Self> {
251+
match (name,args.as_slice()) {
252+
("length",[a]) => Ok(TestFunction::Length(Box::new(a.clone()))),
253+
("value",[a]) => Ok(TestFunction::Value(a.clone())),
254+
("count",[a]) => Ok(TestFunction::Count(a.clone())),
255+
("search",[a,b]) => Ok(TestFunction::Search(a.clone(), b.clone())),
256+
("match", [a,b]) => Ok(TestFunction::Match(a.clone(), b.clone())),
257+
("length" | "value" | "count" | "match" | "search", args ) =>
258+
Err(JsonPathParserError::InvalidJsonPath(format!("Invalid number of arguments for the function `{}`: got {}", name, args.len()))),
259+
(custom,_) => Ok(TestFunction::Custom(custom.to_string(), args)),
260+
}
261+
}
262+
}
263+
247264
impl Display for TestFunction {
248265
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
249266
match self {

src/parser/parser2.rs

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::parser::errors2::JsonPathParserError;
55
use crate::parser::model::JsonPath;
66
use crate::path::JsonLike;
77
use pest::Parser;
8-
use crate::parser::model2::Literal;
8+
use crate::parser::model2::{Literal, SingularQuery, SingularQuerySegment};
99

1010
#[derive(Parser)]
1111
#[grammar = "parser/grammar/json_path_9535.pest"]
@@ -28,6 +28,35 @@ where
2828
}
2929

3030

31+
pub fn singular_query_segments(rule:Pair<Rule>) -> Parsed<Vec<SingularQuerySegment>> {
32+
let mut segments = vec![];
33+
for r in rule.into_inner(){
34+
match r.as_rule(){
35+
Rule::name_segment => {
36+
segments.push(SingularQuerySegment::Name(child(r)?.as_str().to_string()));
37+
}
38+
Rule::index_segment => {
39+
segments.push(
40+
SingularQuerySegment::Index(child(r)?
41+
.as_str()
42+
.parse::<i64>()
43+
.map_err(|e|(e,"int"))?));
44+
}
45+
_ => return Err(r.into())
46+
}
47+
}
48+
Ok(segments)
49+
}
50+
51+
pub fn singular_query(rule:Pair<Rule>) -> Parsed<SingularQuery>{
52+
let query = child(rule)?;
53+
let segments = singular_query_segments(child(query.clone())?)?;
54+
match query.as_rule() {
55+
Rule::rel_singular_query => Ok(SingularQuery::Current(segments)),
56+
Rule::abs_singular_query => Ok(SingularQuery::Root(segments)),
57+
_ => Err(query.into())
58+
}
59+
}
3160

3261
pub fn literal(rule:Pair<Rule>) -> Parsed<Literal> {
3362
fn parse_number(num: &str) -> Parsed<Literal> {
@@ -59,20 +88,9 @@ pub fn literal(rule:Pair<Rule>) -> Parsed<Literal> {
5988

6089

6190
fn child(rule:Pair<Rule>) -> Parsed<Pair<Rule>> {
62-
let string = rule.as_str().to_string();
63-
rule.into_inner().next().ok_or(JsonPathParserError::EmptyInner(string))
91+
let rule_as_str = rule.as_str().to_string();
92+
rule.into_inner().next().ok_or(JsonPathParserError::EmptyInner(rule_as_str))
6493
}
6594
fn children(rule:Pair<Rule>) -> Pairs<Rule> {
6695
rule.into_inner()
6796
}
68-
69-
#[cfg(test)]
70-
mod tests {
71-
use std::fmt::Debug;
72-
use super::*;
73-
use std::panic;
74-
use pest::error::Error;
75-
use crate::lit;
76-
77-
78-
}

src/parser/tests.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
use crate::parser::model2::SingularQuery;
2+
use crate::parser::model2::SingularQuerySegment;
13
use crate::parser::model2::Literal;
24
use std::fmt::Debug;
35
use pest::error::Error;
46
use pest::iterators::Pair;
57
use pest::Parser;
6-
use crate::lit;
7-
use crate::parser::parser2::{literal, Rule};
8+
use crate::{lit, q_segments, q_segment, singular_query};
9+
use crate::parser::parser2::{literal, singular_query, singular_query_segments, Rule};
810
use std::panic;
911

1012
struct TestPair<T> {
@@ -88,4 +90,26 @@ fn literals(){
8890
;
8991

9092

93+
}
94+
95+
#[test]
96+
fn singular_query_segment_test(){
97+
TestPair::new(Rule::singular_query_segments, singular_query_segments)
98+
.assert("[\"b\"][\"b\"]",q_segments!([b][b]))
99+
.assert("[2][1]",q_segments!([2][1]))
100+
.assert("[2][\"a\"]",q_segments!([2][a]))
101+
.assert(".a.b",q_segments!(a b))
102+
.assert(".a.b[\"c\"][1]",q_segments!(a b [c][1]))
103+
;
104+
}
105+
#[test]
106+
fn singular_query_test(){
107+
TestPair::new(Rule::singular_query, singular_query)
108+
.assert("@.a.b",singular_query!(@ a b))
109+
.assert("@",SingularQuery::Current(vec![]))
110+
.assert("$",SingularQuery::Root(vec![]))
111+
.assert("$.a.b.c",singular_query!(a b c))
112+
.assert("$[\"a\"].b[3]",singular_query!([a] b [3]))
113+
114+
;
91115
}

0 commit comments

Comments
 (0)