fix: expression date range; (#49)

* fix: expression date range;

* restore tests; update v8;

* perf: add precomputation for interval; add standard tests;
This commit is contained in:
stefan-gorules
2023-07-01 16:59:09 +02:00
committed by GitHub
parent ccca4df2e6
commit 9caac0c812
5 changed files with 116 additions and 20 deletions
+2 -2
View File
@@ -18,10 +18,10 @@ async-trait = { workspace = true }
bincode = { workspace = true, optional = true }
serde_json = { workspace = true, features = ["arbitrary_precision"] }
serde = { version = "1.0.163", features = ["derive"] }
serde_v8 = { version = "0.100.0" }
serde_v8 = { version = "0.103.0" }
once_cell = { version = "1.17.2" }
futures = "0.3.28"
v8 = { version = "0.73.0" }
v8 = { version = "0.74.0" }
zen-expression = { path = "../expression", version = "0.5.2" }
[dev-dependencies]
+24
View File
@@ -17,25 +17,48 @@ pub(crate) struct ParserIterator<'a, 'b> {
position: Cell<usize>,
bump: &'b Bump,
is_done: Cell<bool>,
has_interval: bool,
}
impl<'a, 'b> ParserIterator<'a, 'b> {
pub fn try_new(tokens: &'a Vec<Token<'a>>, bump: &'b Bump) -> Result<Self, ParserError> {
let current = tokens.get(0).ok_or(ParserError::TokenOutOfBounds)?;
let has_interval = tokens
.iter()
.any(|t| t.kind == TokenKind::Operator && t.value == "..");
Ok(Self {
tokens,
bump,
has_interval,
current: Cell::new(current),
position: Cell::new(0),
is_done: Cell::new(false),
})
}
pub fn has_interval(&self) -> bool {
self.has_interval
}
pub fn current(&self) -> &'a Token<'a> {
self.current.get()
}
pub fn position(&self) -> usize {
self.position.get()
}
pub fn set_position(&self, position: usize) -> ParserResult<()> {
let Some(token) = self.tokens.get(position) else {
return Err(ParserError::TokenOutOfBounds)
};
self.position.set(position);
self.current.set(token);
Ok(())
}
pub fn is_done(&self) -> bool {
self.is_done.get()
}
@@ -66,6 +89,7 @@ impl<'a, 'b> ParserIterator<'a, 'b> {
Ok(())
}
#[allow(dead_code)]
pub fn lookup(&self, dx: usize, kind: TokenKind, values: TokenValues<'a>) -> bool {
self.token_cmp_at_bool(self.position.get() + dx, kind, values)
}
+31 -9
View File
@@ -178,21 +178,43 @@ where
}
fn parse_interval(&self) -> ParserResult<Option<&'b Node<'b>>> {
// Performance optimisation: skip if expression does not contain an interval for faster evaluation
if !self.iterator.has_interval() {
return Ok(None);
}
if self.iterator.current().kind != TokenKind::Bracket {
return Ok(None);
}
if !self.iterator.lookup(2, TokenKind::Operator, Some(&[".."])) {
return Ok(None);
}
let initial_position = self.iterator.position();
let left_bracket = self.iterator.current().value;
self.iterator.expect(TokenKind::Bracket, None)?;
let left = self.parse_primary_expression()?;
self.iterator.expect(TokenKind::Operator, Some(&[".."]))?;
let right = self.parse_primary_expression()?;
if let Err(_) = self.iterator.expect(TokenKind::Bracket, None) {
self.iterator.set_position(initial_position)?;
return Ok(None);
};
let Ok(left) = self.parse_primary_expression() else {
self.iterator.set_position(initial_position)?;
return Ok(None);
};
if let Err(_) = self.iterator.expect(TokenKind::Operator, Some(&[".."])) {
self.iterator.set_position(initial_position)?;
return Ok(None);
};
let Ok(right) = self.parse_primary_expression() else {
self.iterator.set_position(initial_position)?;
return Ok(None);
};
let right_bracket = self.iterator.current().value;
self.iterator.expect(TokenKind::Bracket, None)?;
if let Err(_) = self.iterator.expect(TokenKind::Bracket, None) {
self.iterator.set_position(initial_position)?;
return Ok(None);
};
let interval_node = self.iterator.node(Node::Interval {
left_bracket: self.iterator.str_value(left_bracket),
+31 -9
View File
@@ -135,27 +135,49 @@ where
}
fn parse_interval(&self, node: &'b Node<'b>) -> ParserResult<Option<&'b Node<'b>>> {
// Performance optimisation: skip if expression does not contain an interval for faster evaluation
if !self.iterator.has_interval() {
return Ok(None);
}
let current_token = self.iterator.current();
if current_token.kind != TokenKind::Bracket {
return Ok(None);
}
if !self.iterator.lookup(2, TokenKind::Operator, Some(&[".."])) {
return Ok(None);
}
let initial_position = self.iterator.position();
let should_wrap =
!self
.iterator
.lookup_back(1, TokenKind::Operator, Some(&["not in", "in"]));
let left_bracket = self.iterator.current().value;
self.iterator.expect(TokenKind::Bracket, None)?;
let left = self.parse_primary()?;
self.iterator.expect(TokenKind::Operator, Some(&[".."]))?;
let right = self.parse_primary()?;
if let Err(_) = self.iterator.expect(TokenKind::Bracket, None) {
self.iterator.set_position(initial_position)?;
return Ok(None);
}
let Ok(left) = self.parse_primary() else {
self.iterator.set_position(initial_position)?;
return Ok(None);
};
if let Err(_) = self.iterator.expect(TokenKind::Operator, Some(&[".."])) {
self.iterator.set_position(initial_position)?;
return Ok(None);
}
let Ok(right) = self.parse_primary() else {
self.iterator.set_position(initial_position)?;
return Ok(None);
};
let right_bracket = self.iterator.current().value;
self.iterator.expect(TokenKind::Bracket, None)?;
if let Err(_) = self.iterator.expect(TokenKind::Bracket, None) {
self.iterator.set_position(initial_position)?;
return Ok(None);
}
let interval_node = self.iterator.node(Node::Interval {
left,
+28
View File
@@ -128,6 +128,14 @@ fn isolate_standard_test() {
expr: r#"date("2022-04-04") > date("2022-03-04")"#,
result: json!(true),
},
TestCase {
expr: r#"date("2022-04-04") in [date("2022-03-04")..date("2022-04-04")]"#,
result: json!(true),
},
TestCase {
expr: r#"date("2022-04-04") in [date("2022-03-04")..date("2022-04-04"))"#,
result: json!(false),
},
TestCase {
expr: r#"time("2022-04-04T21:48:30Z") > time("2022-05-04 21:48:20")"#,
result: json!(true),
@@ -513,6 +521,26 @@ fn isolate_unary_tests() {
result: json!(true),
}]),
},
UnaryTestEnv {
env: json!({
"input": "2023-01-02"
}),
reference: "date(input)",
cases: Vec::from([
TestCase {
expr: r#"[date("2023-01-01")..date("2023-01-03")]"#,
result: json!(true),
},
TestCase {
expr: r#"[date("2023-02-01")..date("2023-01-03")]"#,
result: json!(false),
},
TestCase {
expr: r#"$ in [date("2023-01-01")..date("2023-01-03")]"#,
result: json!(true),
},
]),
},
UnaryTestEnv {
env: json!({
"customer": {