|
|
@@ -48,8 +48,8 @@ use std::fmt::Debug;
|
|
|
|
|
|
|
|
|
|
|
|
pub use condition::{parse_condition, parse_to, Condition};
|
|
|
|
pub use condition::{parse_condition, parse_to, Condition};
|
|
|
|
use condition::{
|
|
|
|
use condition::{
|
|
|
|
parse_exists, parse_is_empty, parse_is_not_empty, parse_is_not_null, parse_is_null,
|
|
|
|
parse_contains, parse_ends_with, parse_exists, parse_is_empty, parse_is_not_empty,
|
|
|
|
parse_not_exists,
|
|
|
|
parse_is_not_null, parse_is_null, parse_not_exists, parse_starts_with,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
use error::{cut_with_err, ExpectedValueKind, NomErrorExt};
|
|
|
|
use error::{cut_with_err, ExpectedValueKind, NomErrorExt};
|
|
|
|
pub use error::{Error, ErrorKind};
|
|
|
|
pub use error::{Error, ErrorKind};
|
|
|
@@ -444,6 +444,9 @@ fn parse_primary(input: Span, depth: usize) -> IResult<FilterCondition> {
|
|
|
|
parse_geo_bounding_box,
|
|
|
|
parse_geo_bounding_box,
|
|
|
|
parse_in,
|
|
|
|
parse_in,
|
|
|
|
parse_not_in,
|
|
|
|
parse_not_in,
|
|
|
|
|
|
|
|
parse_contains,
|
|
|
|
|
|
|
|
parse_starts_with,
|
|
|
|
|
|
|
|
parse_ends_with,
|
|
|
|
parse_condition,
|
|
|
|
parse_condition,
|
|
|
|
parse_is_null,
|
|
|
|
parse_is_null,
|
|
|
|
parse_is_not_null,
|
|
|
|
parse_is_not_null,
|
|
|
@@ -489,6 +492,7 @@ pub mod tests {
|
|
|
|
fn parse() {
|
|
|
|
fn parse() {
|
|
|
|
use FilterCondition as Fc;
|
|
|
|
use FilterCondition as Fc;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[track_caller]
|
|
|
|
fn p(s: &str) -> impl std::fmt::Display + '_ {
|
|
|
|
fn p(s: &str) -> impl std::fmt::Display + '_ {
|
|
|
|
Fc::parse(s).unwrap().unwrap()
|
|
|
|
Fc::parse(s).unwrap().unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
@@ -558,6 +562,27 @@ pub mod tests {
|
|
|
|
insta::assert_display_snapshot!(p("NOT subscribers NOT EXISTS"), @"{subscribers} EXISTS");
|
|
|
|
insta::assert_display_snapshot!(p("NOT subscribers NOT EXISTS"), @"{subscribers} EXISTS");
|
|
|
|
insta::assert_display_snapshot!(p("subscribers NOT EXISTS"), @"NOT ({subscribers} EXISTS)");
|
|
|
|
insta::assert_display_snapshot!(p("subscribers NOT EXISTS"), @"NOT ({subscribers} EXISTS)");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Test CONTAINS + NOT CONTAINS
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("subscribers CONTAINS 'hello'"), @"{subscribers} CONTAINS {hello}");
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("NOT subscribers CONTAINS 'hello'"), @"NOT ({subscribers} CONTAINS {hello})");
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("subscribers NOT CONTAINS hello"), @"NOT ({subscribers} CONTAINS {hello})");
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("NOT subscribers NOT CONTAINS 'hello'"), @"{subscribers} CONTAINS {hello}");
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("subscribers NOT CONTAINS 'hello'"), @"NOT ({subscribers} CONTAINS {hello})");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Test STARTS WITH + NOT STARTS WITH
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("subscribers STARTS WITH 'hello'"), @"{subscribers} STARTS WITH {hello}");
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("NOT subscribers STARTS WITH 'hello'"), @"NOT ({subscribers} STARTS WITH {hello})");
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("subscribers NOT STARTS WITH hello"), @"NOT ({subscribers} STARTS WITH {hello})");
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("NOT subscribers NOT STARTS WITH 'hello'"), @"{subscribers} STARTS WITH {hello}");
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("subscribers NOT STARTS WITH 'hello'"), @"NOT ({subscribers} STARTS WITH {hello})");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Test ENDS WITH + NOT ENDS WITH
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("subscribers ENDS WITH 'hello'"), @"{subscribers} ENDS WITH {hello}");
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("NOT subscribers ENDS WITH 'hello'"), @"NOT ({subscribers} ENDS WITH {hello})");
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("subscribers NOT ENDS WITH hello"), @"NOT ({subscribers} ENDS WITH {hello})");
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("NOT subscribers NOT ENDS WITH 'hello'"), @"{subscribers} ENDS WITH {hello}");
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("subscribers NOT ENDS WITH 'hello'"), @"NOT ({subscribers} ENDS WITH {hello})");
|
|
|
|
|
|
|
|
|
|
|
|
// Test nested NOT
|
|
|
|
// Test nested NOT
|
|
|
|
insta::assert_display_snapshot!(p("NOT NOT NOT NOT x = 5"), @"{x} = {5}");
|
|
|
|
insta::assert_display_snapshot!(p("NOT NOT NOT NOT x = 5"), @"{x} = {5}");
|
|
|
|
insta::assert_display_snapshot!(p("NOT NOT (NOT NOT x = 5)"), @"{x} = {5}");
|
|
|
|
insta::assert_display_snapshot!(p("NOT NOT (NOT NOT x = 5)"), @"{x} = {5}");
|
|
|
@@ -629,7 +654,7 @@ pub mod tests {
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("'OR'"), @r###"
|
|
|
|
insta::assert_display_snapshot!(p("'OR'"), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` at `\'OR\'`.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` at `\'OR\'`.
|
|
|
|
1:5 'OR'
|
|
|
|
1:5 'OR'
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
|
@@ -639,12 +664,12 @@ pub mod tests {
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("channel Ponce"), @r###"
|
|
|
|
insta::assert_display_snapshot!(p("channel Ponce"), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` at `channel Ponce`.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` at `channel Ponce`.
|
|
|
|
1:14 channel Ponce
|
|
|
|
1:14 channel Ponce
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("channel = Ponce OR"), @r###"
|
|
|
|
insta::assert_display_snapshot!(p("channel = Ponce OR"), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` but instead got nothing.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` but instead got nothing.
|
|
|
|
19:19 channel = Ponce OR
|
|
|
|
19:19 channel = Ponce OR
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
|
@@ -729,12 +754,12 @@ pub mod tests {
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("colour NOT EXIST"), @r###"
|
|
|
|
insta::assert_display_snapshot!(p("colour NOT EXIST"), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` at `colour NOT EXIST`.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` at `colour NOT EXIST`.
|
|
|
|
1:17 colour NOT EXIST
|
|
|
|
1:17 colour NOT EXIST
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p("subscribers 100 TO1000"), @r###"
|
|
|
|
insta::assert_display_snapshot!(p("subscribers 100 TO1000"), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` at `subscribers 100 TO1000`.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` at `subscribers 100 TO1000`.
|
|
|
|
1:23 subscribers 100 TO1000
|
|
|
|
1:23 subscribers 100 TO1000
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
|
@@ -797,35 +822,35 @@ pub mod tests {
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
|
|
insta::assert_display_snapshot!(p(r#"value NULL"#), @r###"
|
|
|
|
insta::assert_display_snapshot!(p(r#"value NULL"#), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` at `value NULL`.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` at `value NULL`.
|
|
|
|
1:11 value NULL
|
|
|
|
1:11 value NULL
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
insta::assert_display_snapshot!(p(r#"value NOT NULL"#), @r###"
|
|
|
|
insta::assert_display_snapshot!(p(r#"value NOT NULL"#), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` at `value NOT NULL`.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` at `value NOT NULL`.
|
|
|
|
1:15 value NOT NULL
|
|
|
|
1:15 value NOT NULL
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
insta::assert_display_snapshot!(p(r#"value EMPTY"#), @r###"
|
|
|
|
insta::assert_display_snapshot!(p(r#"value EMPTY"#), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` at `value EMPTY`.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` at `value EMPTY`.
|
|
|
|
1:12 value EMPTY
|
|
|
|
1:12 value EMPTY
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
insta::assert_display_snapshot!(p(r#"value NOT EMPTY"#), @r###"
|
|
|
|
insta::assert_display_snapshot!(p(r#"value NOT EMPTY"#), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` at `value NOT EMPTY`.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` at `value NOT EMPTY`.
|
|
|
|
1:16 value NOT EMPTY
|
|
|
|
1:16 value NOT EMPTY
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
insta::assert_display_snapshot!(p(r#"value IS"#), @r###"
|
|
|
|
insta::assert_display_snapshot!(p(r#"value IS"#), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` at `value IS`.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` at `value IS`.
|
|
|
|
1:9 value IS
|
|
|
|
1:9 value IS
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
insta::assert_display_snapshot!(p(r#"value IS NOT"#), @r###"
|
|
|
|
insta::assert_display_snapshot!(p(r#"value IS NOT"#), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` at `value IS NOT`.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` at `value IS NOT`.
|
|
|
|
1:13 value IS NOT
|
|
|
|
1:13 value IS NOT
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
insta::assert_display_snapshot!(p(r#"value IS EXISTS"#), @r###"
|
|
|
|
insta::assert_display_snapshot!(p(r#"value IS EXISTS"#), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` at `value IS EXISTS`.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` at `value IS EXISTS`.
|
|
|
|
1:16 value IS EXISTS
|
|
|
|
1:16 value IS EXISTS
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
insta::assert_display_snapshot!(p(r#"value IS NOT EXISTS"#), @r###"
|
|
|
|
insta::assert_display_snapshot!(p(r#"value IS NOT EXISTS"#), @r###"
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `_geoRadius`, or `_geoBoundingBox` at `value IS NOT EXISTS`.
|
|
|
|
Was expecting an operation `=`, `!=`, `>=`, `>`, `<=`, `<`, `IN`, `NOT IN`, `TO`, `EXISTS`, `NOT EXISTS`, `IS NULL`, `IS NOT NULL`, `IS EMPTY`, `IS NOT EMPTY`, `CONTAINS`, `STARTS WITH`, `ENDS WITH`, `_geoRadius`, or `_geoBoundingBox` at `value IS NOT EXISTS`.
|
|
|
|
1:20 value IS NOT EXISTS
|
|
|
|
1:20 value IS NOT EXISTS
|
|
|
|
"###);
|
|
|
|
"###);
|
|
|
|
}
|
|
|
|
}
|
|
|
@@ -915,6 +940,9 @@ impl<'a> std::fmt::Display for Condition<'a> {
|
|
|
|
Condition::LowerThan(token) => write!(f, "< {token}"),
|
|
|
|
Condition::LowerThan(token) => write!(f, "< {token}"),
|
|
|
|
Condition::LowerThanOrEqual(token) => write!(f, "<= {token}"),
|
|
|
|
Condition::LowerThanOrEqual(token) => write!(f, "<= {token}"),
|
|
|
|
Condition::Between { from, to } => write!(f, "{from} TO {to}"),
|
|
|
|
Condition::Between { from, to } => write!(f, "{from} TO {to}"),
|
|
|
|
|
|
|
|
Condition::Contains(token) => write!(f, "CONTAINS {token}"),
|
|
|
|
|
|
|
|
Condition::StartsWith(token) => write!(f, "STARTS WITH {token}"),
|
|
|
|
|
|
|
|
Condition::EndsWith(token) => write!(f, "ENDS WITH {token}"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|