Skip to content

Commit

Permalink
example code that statically compiles the regex
Browse files Browse the repository at this point in the history
  • Loading branch information
xMAC94x committed May 17, 2024
1 parent e85553c commit e527958
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/parser/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
macro_rules! filter {
() => {FilterExpression::Atom(op!,FilterSign::new(""),op!())};
( $left:expr, $s:literal, $right:expr) => {
FilterExpression::Atom($left,FilterSign::new($s),$right)
FilterExpression::Atom($left,FilterSign::new($s, &$right),$right)
};
( $left:expr,||, $right:expr) => {FilterExpression::Or(Box::new($left),Box::new($right)) };
( $left:expr,&&, $right:expr) => {FilterExpression::And(Box::new($left),Box::new($right)) };
Expand Down
33 changes: 29 additions & 4 deletions src/parser/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,15 @@ impl Operand {
}

/// The operators for filtering functions
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone)]
pub enum FilterSign {
Equal,
Unequal,
Less,
Greater,
LeOrEq,
GrOrEq,
Regex,
Regex(Option<regex::Regex>),
In,
Nin,
Size,
Expand All @@ -116,16 +116,41 @@ pub enum FilterSign {
Exists,
}

impl PartialEq for FilterSign {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(FilterSign::Equal, FilterSign::Equal) => true,
(FilterSign::Unequal, FilterSign::Unequal) => true,
(FilterSign::Less, FilterSign::Less) => true,
(FilterSign::Greater, FilterSign::Greater) => true,
(FilterSign::LeOrEq, FilterSign::LeOrEq) => true,
(FilterSign::GrOrEq, FilterSign::GrOrEq) => true,
(FilterSign::Regex(_), FilterSign::Regex(_)) => true,
(FilterSign::In, FilterSign::In) => true,
(FilterSign::Nin, FilterSign::Nin) => true,
(FilterSign::Size, FilterSign::Size) => true,
(FilterSign::NoneOf, FilterSign::NoneOf) => true,
(FilterSign::AnyOf, FilterSign::AnyOf) => true,
(FilterSign::SubSetOf, FilterSign::SubSetOf) => true,
(FilterSign::Exists, FilterSign::Exists) => true,
(_, _) => false,
}
}
}

impl FilterSign {
pub fn new(key: &str) -> Self {
pub fn new(key: &str, op: &Operand) -> Self {
match key {
"==" => FilterSign::Equal,
"!=" => FilterSign::Unequal,
"<" => FilterSign::Less,
">" => FilterSign::Greater,
"<=" => FilterSign::LeOrEq,
">=" => FilterSign::GrOrEq,
"~=" => FilterSign::Regex,
"~=" => FilterSign::Regex(match op {
Operand::Static(Value::String(reg)) => regex::Regex::new(reg).ok(),
_ => None,
}),
"in" => FilterSign::In,
"nin" => FilterSign::Nin,
"size" => FilterSign::Size,
Expand Down
7 changes: 4 additions & 3 deletions src/parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,10 @@ fn parse_logic_atom(mut pairs: Pairs<Rule>) -> Result<FilterExpression, JsonPath
if pairs.peek().is_none() {
Ok(FilterExpression::exists(left))
} else {
let sign: FilterSign = FilterSign::new(pairs.next().expect("unreachable in arithmetic: should have a value as pairs.peek() was Some(_)").as_str());
let right: Operand =
parse_atom(pairs.next().expect("unreachable in arithemetic: should have a right side operand"))?;
let sign = pairs.next().expect("unreachable in arithmetic: should have a value as pairs.peek() was Some(_)").as_str();
let right = pairs.next().expect("unreachable in arithemetic: should have a right side operand");
let right: Operand = parse_atom(right)?;
let sign: FilterSign = FilterSign::new(sign, &right);
Ok(FilterExpression::Atom(left, sign, right))
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/path/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,10 @@ impl<'a> FilterPath<'a> {
FilterSign::GrOrEq => {
FilterPath::compound(&FilterSign::Greater, &FilterSign::Equal, left, right)
}
FilterSign::Regex => regex(
FilterSign::Regex(reg) => regex(
JsonPathValue::vec_as_data(left),
JsonPathValue::vec_as_data(right),
reg,
),
FilterSign::In => inside(
JsonPathValue::vec_as_data(left),
Expand Down Expand Up @@ -582,8 +583,8 @@ mod tests {
let chain = chain!(path!($), path!("key"), index);
let path_inst = json_path_instance(&chain, &json);
let expected_res = jp_v![
&exp4;"$.['key'][0]",
&exp3;"$.['key'][2]",
&exp4;"$.['key'][0]",
&exp3;"$.['key'][2]",
&exp4;"$.['key'][4]"];
assert_eq!(
path_inst.find(JsonPathValue::from_root(&json)),
Expand Down
29 changes: 18 additions & 11 deletions src/path/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,17 @@ pub fn any_of(left: Vec<&Value>, right: Vec<&Value>) -> bool {
}

/// ensure that the element on the left sides mathes the regex on the right side
pub fn regex(left: Vec<&Value>, right: Vec<&Value>) -> bool {
pub fn regex(left: Vec<&Value>, right: Vec<&Value>, reg: &Option<Regex>) -> bool {
if left.is_empty() || right.is_empty() {
return false;
}

match right.first() {
Some(Value::String(str)) => {
if let Ok(regex) = Regex::new(str) {
for el in left.iter() {
if let Some(v) = el.as_str() {
if regex.is_match(v) {
return true;
}
match reg {
Some(reg) => {
for el in left.iter() {
if let Some(v) = el.as_str() {
if reg.is_match(v) {
return true;
}
}
}
Expand Down Expand Up @@ -171,6 +169,7 @@ pub fn eq(left: Vec<&Value>, right: Vec<&Value>) -> bool {
#[cfg(test)]
mod tests {
use crate::path::json::{any_of, eq, less, regex, size, sub_set_of};
use regex::Regex;
use serde_json::{json, Value};

#[test]
Expand Down Expand Up @@ -243,8 +242,16 @@ mod tests {
let left3 = json!("a#11");
let left4 = json!("#a11");

assert!(regex(vec![&left1, &left2, &left3, &left4], vec![&right]));
assert!(!regex(vec![&left1, &left3, &left4], vec![&right]))
assert!(regex(
vec![&left1, &left2, &left3, &left4],
vec![&right],
&Regex::new(right.as_str().unwrap()).ok(),
));
assert!(!regex(
vec![&left1, &left3, &left4],
vec![&right],
&Regex::new(right.as_str().unwrap()).ok(),
))
}

#[test]
Expand Down

0 comments on commit e527958

Please sign in to comment.