Skip to content

Commit 0d6124a

Browse files
author
Dean Karn
committed
refactor for maint
1 parent 1328234 commit 0d6124a

37 files changed

+786
-644
lines changed

src/parser/coercions/constant.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use crate::parser::{Expression, Value};
2+
3+
#[derive(Debug)]
4+
pub(in crate::parser) struct CoercedConst {
5+
pub value: Value,
6+
}
7+
8+
impl Expression for CoercedConst {
9+
fn calculate(&self, _json: &[u8]) -> crate::parser::parse::Result<Value> {
10+
Ok(self.value.clone())
11+
}
12+
}

src/parser/coercions/date_time.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Error, Expression, Value};
3+
4+
#[derive(Debug)]
5+
pub(in crate::parser) struct COERCEDateTime {
6+
pub value: BoxedExpression,
7+
}
8+
9+
impl Expression for COERCEDateTime {
10+
fn calculate(&self, json: &[u8]) -> crate::parser::parse::Result<Value> {
11+
let value = self.value.calculate(json)?;
12+
13+
match value {
14+
Value::String(ref s) => match anydate::parse_utc(s) {
15+
Err(_) => Ok(Value::Null),
16+
Ok(dt) => Ok(Value::DateTime(dt)),
17+
},
18+
Value::Null => Ok(value),
19+
value => Err(Error::UnsupportedCOERCE(
20+
format!("{value} COERCE datetime",),
21+
)),
22+
}
23+
}
24+
}

src/parser/coercions/lowercase.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Error, Expression, Value};
3+
4+
#[derive(Debug)]
5+
pub(in crate::parser) struct CoerceLowercase {
6+
pub value: BoxedExpression,
7+
}
8+
9+
impl Expression for CoerceLowercase {
10+
fn calculate(&self, json: &[u8]) -> crate::parser::parse::Result<Value> {
11+
let v = self.value.calculate(json)?;
12+
match v {
13+
Value::String(s) => Ok(Value::String(s.to_lowercase())),
14+
v => Err(Error::UnsupportedCOERCE(format!("{v} COERCE lowercase",))),
15+
}
16+
}
17+
}

src/parser/coercions/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
mod constant;
2+
mod date_time;
3+
mod lowercase;
4+
mod number;
5+
mod string;
6+
mod sub_str;
7+
mod title;
8+
mod uppercase;
9+
10+
pub(super) use constant::CoercedConst;
11+
pub(super) use date_time::COERCEDateTime;
12+
pub(super) use lowercase::CoerceLowercase;
13+
pub(super) use number::COERCENumber;
14+
pub(super) use string::COERCEString;
15+
pub(super) use sub_str::CoerceSubstr;
16+
pub(super) use title::CoerceTitle;
17+
pub(super) use uppercase::CoerceUppercase;

src/parser/coercions/number.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Error, Expression, Value};
3+
4+
#[derive(Debug)]
5+
pub(in crate::parser) struct COERCENumber {
6+
pub value: BoxedExpression,
7+
}
8+
9+
impl Expression for COERCENumber {
10+
#[allow(clippy::cast_precision_loss)]
11+
fn calculate(&self, json: &[u8]) -> crate::parser::parse::Result<Value> {
12+
let value = self.value.calculate(json)?;
13+
match value {
14+
Value::String(s) => Ok(Value::Number(
15+
s.parse::<f64>()
16+
.map_err(|e| Error::UnsupportedCOERCE(e.to_string()))?,
17+
)),
18+
Value::Number(num) => Ok(Value::Number(num)),
19+
Value::Bool(b) => Ok(Value::Number(if b { 1.0 } else { 0.0 })),
20+
Value::DateTime(dt) => Ok(Value::Number(
21+
dt.timestamp_nanos_opt().unwrap_or_default() as f64
22+
)),
23+
_ => Err(Error::UnsupportedCOERCE(
24+
format!("{value} COERCE datetime",),
25+
)),
26+
}
27+
}
28+
}

src/parser/coercions/string.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Expression, Value};
3+
use chrono::SecondsFormat;
4+
5+
#[derive(Debug)]
6+
pub(in crate::parser) struct COERCEString {
7+
pub value: BoxedExpression,
8+
}
9+
10+
impl Expression for COERCEString {
11+
fn calculate(&self, json: &[u8]) -> crate::parser::parse::Result<Value> {
12+
let value = self.value.calculate(json)?;
13+
match value {
14+
Value::Null => Ok(Value::String("null".to_string())),
15+
Value::String(s) => Ok(Value::String(s)),
16+
Value::Number(num) => Ok(Value::String(num.to_string())),
17+
Value::Bool(b) => Ok(Value::String(b.to_string())),
18+
Value::DateTime(dt) => Ok(Value::String(
19+
dt.to_rfc3339_opts(SecondsFormat::AutoSi, true),
20+
)),
21+
Value::Array(_) | Value::Object(_) => Ok(Value::String(value.to_string())),
22+
}
23+
}
24+
}

src/parser/coercions/sub_str.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Error, Expression, Value};
3+
4+
#[derive(Debug)]
5+
pub(in crate::parser) struct CoerceSubstr {
6+
pub value: BoxedExpression,
7+
pub start_idx: Option<usize>,
8+
pub end_idx: Option<usize>,
9+
}
10+
11+
impl Expression for CoerceSubstr {
12+
fn calculate(&self, json: &[u8]) -> crate::parser::parse::Result<Value> {
13+
let v = self.value.calculate(json)?;
14+
match v {
15+
Value::String(s) => match (self.start_idx, self.end_idx) {
16+
(Some(start), Some(end)) => Ok(s
17+
.get(start..end)
18+
.map_or_else(|| Value::Null, |s| Value::String(s.to_string()))),
19+
(Some(start), None) => Ok(s
20+
.get(start..)
21+
.map_or_else(|| Value::Null, |s| Value::String(s.to_string()))),
22+
(None, Some(end)) => Ok(s
23+
.get(..end)
24+
.map_or_else(|| Value::Null, |s| Value::String(s.to_string()))),
25+
_ => Err(Error::UnsupportedCOERCE(format!(
26+
"COERCE substr for {s}, [{:?}:{:?}]",
27+
self.start_idx, self.end_idx
28+
))),
29+
},
30+
v => Err(Error::UnsupportedCOERCE(format!("{v} COERCE substr",))),
31+
}
32+
}
33+
}

src/parser/coercions/title.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Error, Expression, Value};
3+
4+
#[derive(Debug)]
5+
pub(in crate::parser) struct CoerceTitle {
6+
pub value: BoxedExpression,
7+
}
8+
9+
impl Expression for CoerceTitle {
10+
fn calculate(&self, json: &[u8]) -> crate::parser::parse::Result<Value> {
11+
let v = self.value.calculate(json)?;
12+
match v {
13+
Value::String(s) => {
14+
let mut c = s.chars();
15+
match c.next() {
16+
None => Ok(Value::String(s)),
17+
Some(f) => Ok(Value::String(
18+
f.to_uppercase().collect::<String>() + c.as_str().to_lowercase().as_str(),
19+
)),
20+
}
21+
}
22+
v => Err(Error::UnsupportedCOERCE(format!("{v} COERCE title",))),
23+
}
24+
}
25+
}

src/parser/coercions/uppercase.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Error, Expression, Value};
3+
4+
#[derive(Debug)]
5+
pub(in crate::parser) struct CoerceUppercase {
6+
pub value: BoxedExpression,
7+
}
8+
9+
impl Expression for CoerceUppercase {
10+
fn calculate(&self, json: &[u8]) -> crate::parser::parse::Result<Value> {
11+
let v = self.value.calculate(json)?;
12+
match v {
13+
Value::String(s) => Ok(Value::String(s.to_uppercase())),
14+
v => Err(Error::UnsupportedCOERCE(format!("{v} COERCE uppercase",))),
15+
}
16+
}
17+
}

src/parser/expressions/add.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Error, Expression, Result, Value};
3+
4+
#[derive(Debug)]
5+
pub(in crate::parser) struct Add {
6+
pub left: BoxedExpression,
7+
pub right: BoxedExpression,
8+
}
9+
10+
impl Expression for Add {
11+
fn calculate(&self, json: &[u8]) -> Result<Value> {
12+
let left = self.left.calculate(json)?;
13+
let right = self.right.calculate(json)?;
14+
15+
match (left, right) {
16+
(Value::String(s1), Value::String(ref s2)) => Ok(Value::String(s1 + s2)),
17+
(Value::String(s1), Value::Null) => Ok(Value::String(s1)),
18+
(Value::Null, Value::String(s2)) => Ok(Value::String(s2)),
19+
(Value::Number(n1), Value::Number(n2)) => Ok(Value::Number(n1 + n2)),
20+
(Value::Number(n1), Value::Null) => Ok(Value::Number(n1)),
21+
(Value::Null, Value::Number(n2)) => Ok(Value::Number(n2)),
22+
(l, r) => Err(Error::UnsupportedTypeComparison(format!("{l} + {r}",))),
23+
}
24+
}
25+
}

src/parser/expressions/and.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Error, Expression, Result, Value};
3+
4+
#[derive(Debug)]
5+
pub(in crate::parser) struct And {
6+
pub left: BoxedExpression,
7+
pub right: BoxedExpression,
8+
}
9+
10+
impl Expression for And {
11+
fn calculate(&self, json: &[u8]) -> Result<Value> {
12+
let left = self.left.calculate(json)?;
13+
14+
if let Value::Bool(is_true) = left {
15+
if !is_true {
16+
return Ok(left);
17+
}
18+
}
19+
20+
let right = self.right.calculate(json)?;
21+
22+
match (left, right) {
23+
(Value::Bool(b1), Value::Bool(b2)) => Ok(Value::Bool(b1 && b2)),
24+
(l, r) => Err(Error::UnsupportedTypeComparison(format!("{l} && {r}",))),
25+
}
26+
}
27+
}

src/parser/expressions/arr.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Expression, Result, Value};
3+
4+
#[derive(Debug)]
5+
pub(in crate::parser) struct Arr {
6+
pub arr: Vec<BoxedExpression>,
7+
}
8+
9+
impl Expression for Arr {
10+
fn calculate(&self, json: &[u8]) -> Result<Value> {
11+
let mut arr = Vec::new();
12+
for e in &self.arr {
13+
arr.push(e.calculate(json)?);
14+
}
15+
Ok(Value::Array(arr))
16+
}
17+
}

src/parser/expressions/between.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Error, Expression, Result, Value};
3+
4+
#[derive(Debug)]
5+
pub(in crate::parser) struct Between {
6+
pub left: BoxedExpression,
7+
pub right: BoxedExpression,
8+
pub value: BoxedExpression,
9+
}
10+
11+
impl Expression for Between {
12+
fn calculate(&self, json: &[u8]) -> Result<Value> {
13+
let left = self.left.calculate(json)?;
14+
let right = self.right.calculate(json)?;
15+
let value = self.value.calculate(json)?;
16+
17+
match (value, left, right) {
18+
(Value::String(v), Value::String(lhs), Value::String(rhs)) => {
19+
Ok(Value::Bool(v > lhs && v < rhs))
20+
}
21+
(Value::Number(v), Value::Number(lhs), Value::Number(rhs)) => {
22+
Ok(Value::Bool(v > lhs && v < rhs))
23+
}
24+
(Value::DateTime(v), Value::DateTime(lhs), Value::DateTime(rhs)) => {
25+
Ok(Value::Bool(v > lhs && v < rhs))
26+
}
27+
(Value::Null, _, _) | (_, Value::Null, _) | (_, _, Value::Null) => {
28+
Ok(Value::Bool(false))
29+
}
30+
(v, lhs, rhs) => Err(Error::UnsupportedTypeComparison(format!(
31+
"{v} BETWEEN {lhs} {rhs}",
32+
))),
33+
}
34+
}
35+
}

src/parser/expressions/bool.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use crate::parser::{Expression, Result, Value};
2+
3+
#[derive(Debug)]
4+
pub(in crate::parser) struct Bool {
5+
pub b: bool,
6+
}
7+
8+
impl Expression for Bool {
9+
fn calculate(&self, _: &[u8]) -> Result<Value> {
10+
Ok(Value::Bool(self.b))
11+
}
12+
}

src/parser/expressions/contains.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Error, Expression, Result, Value};
3+
4+
#[derive(Debug)]
5+
pub(in crate::parser) struct Contains {
6+
pub left: BoxedExpression,
7+
pub right: BoxedExpression,
8+
}
9+
10+
impl Expression for Contains {
11+
fn calculate(&self, json: &[u8]) -> Result<Value> {
12+
let left = self.left.calculate(json)?;
13+
let right = self.right.calculate(json)?;
14+
match (left, right) {
15+
(Value::String(s1), Value::String(s2)) => Ok(Value::Bool(s1.contains(&s2))),
16+
(Value::Array(arr1), v) => Ok(Value::Bool(arr1.contains(&v))),
17+
(l, r) => Err(Error::UnsupportedTypeComparison(format!(
18+
"{l} CONTAINS {r}",
19+
))),
20+
}
21+
}
22+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use crate::parser::parse::BoxedExpression;
2+
use crate::parser::{Error, Expression, Result, Value};
3+
4+
#[derive(Debug)]
5+
pub(in crate::parser) struct ContainsAll {
6+
pub left: BoxedExpression,
7+
pub right: BoxedExpression,
8+
}
9+
10+
impl Expression for ContainsAll {
11+
fn calculate(&self, json: &[u8]) -> Result<Value> {
12+
let left = self.left.calculate(json)?;
13+
let right = self.right.calculate(json)?;
14+
match (left, right) {
15+
(Value::String(s1), Value::String(s2)) => {
16+
let b1: Vec<char> = s1.chars().collect();
17+
Ok(Value::Bool(s2.chars().all(|b| b1.contains(&b))))
18+
}
19+
(Value::Array(arr1), Value::Array(arr2)) => {
20+
Ok(Value::Bool(arr2.iter().all(|v| arr1.contains(v))))
21+
}
22+
(Value::Array(arr), Value::String(s)) => Ok(Value::Bool(
23+
s.chars()
24+
.all(|v| arr.contains(&Value::String(v.to_string()))),
25+
)),
26+
(Value::String(s), Value::Array(arr)) => Ok(Value::Bool(arr.iter().all(|v| match v {
27+
Value::String(s2) => s.contains(s2),
28+
_ => false,
29+
}))),
30+
(l, r) => Err(Error::UnsupportedTypeComparison(format!(
31+
"{l} CONTAINS_ALL {r}",
32+
))),
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)