1use crate::lexer::{Token, TokenKind, Tokenizer};
18use crate::parser::coercions::{
19 COERCEDateTime, COERCENumber, COERCEString, CoerceLowercase, CoerceSubstr, CoerceTitle,
20 CoerceUppercase, CoercedConst,
21};
22use crate::parser::expressions::{
23 Add, And, Arr, Between, Bool, Contains, ContainsAll, ContainsAny, Div, EndsWith, Eq, Gt, Gte,
24 In, Lt, Lte, Mult, Not, Null, Num, Or, SelectorPath, StartsWith, Str, Sub,
25};
26use anyhow::anyhow;
27use chrono::{DateTime, Utc};
28use gjson::Kind;
29use serde::Serialize;
30use std::collections::{BTreeMap, HashMap};
31use std::fmt::{Debug, Display, Formatter};
32use std::iter::Peekable;
33use std::sync::{OnceLock, RwLock};
34use thiserror::Error;
35
36pub type CustomCoercion = fn(
42 tokenizer: &mut Parser,
43 const_eligible: bool,
44 expression: BoxedExpression,
45) -> anyhow::Result<(bool, BoxedExpression)>;
46
47#[allow(clippy::too_many_lines)]
50pub fn coercions() -> &'static RwLock<HashMap<String, CustomCoercion>> {
51 static CUSTOM_COERCIONS: OnceLock<RwLock<HashMap<String, CustomCoercion>>> = OnceLock::new();
52 CUSTOM_COERCIONS.get_or_init(|| {
53 let mut m: HashMap<String, CustomCoercion> = HashMap::new();
54 m.insert("_datetime_".to_string(), |_, const_eligible, expression| {
55 let value = COERCEDateTime { value: expression };
56 if const_eligible {
57 Ok((
58 const_eligible,
59 Box::new(CoercedConst {
60 value: value.calculate(&[])?,
61 }),
62 ))
63 } else {
64 Ok((false, Box::new(value)))
65 }
66 });
67 m.insert("_string_".to_string(), |_, const_eligible, expression| {
68 let value = COERCEString { value: expression };
69 if const_eligible {
70 Ok((
71 const_eligible,
72 Box::new(CoercedConst {
73 value: value.calculate(&[])?,
74 }),
75 ))
76 } else {
77 Ok((false, Box::new(value)))
78 }
79 });
80 m.insert("_number_".to_string(), |_, const_eligible, expression| {
81 let value = COERCENumber { value: expression };
82 if const_eligible {
83 Ok((
84 const_eligible,
85 Box::new(CoercedConst {
86 value: value.calculate(&[])?,
87 }),
88 ))
89 } else {
90 Ok((false, Box::new(value)))
91 }
92 });
93 m.insert(
94 "_lowercase_".to_string(),
95 |_, const_eligible, expression| {
96 let value = CoerceLowercase { value: expression };
97 if const_eligible {
98 Ok((
99 const_eligible,
100 Box::new(CoercedConst {
101 value: value.calculate(&[])?,
102 }),
103 ))
104 } else {
105 Ok((false, Box::new(value)))
106 }
107 },
108 );
109 m.insert(
110 "_uppercase_".to_string(),
111 |_, const_eligible, expression| {
112 let value = CoerceUppercase { value: expression };
113 if const_eligible {
114 Ok((
115 const_eligible,
116 Box::new(CoercedConst {
117 value: value.calculate(&[])?,
118 }),
119 ))
120 } else {
121 Ok((false, Box::new(value)))
122 }
123 },
124 );
125 m.insert("_title_".to_string(), |_, const_eligible, expression| {
126 let value = CoerceTitle { value: expression };
127 if const_eligible {
128 Ok((
129 const_eligible,
130 Box::new(CoercedConst {
131 value: value.calculate(&[])?,
132 }),
133 ))
134 } else {
135 Ok((false, Box::new(value)))
136 }
137 });
138 m.insert(
139 "_substr_".to_string(),
140 |parser, const_eligible, expression| {
141 let _ = parser.tokenizer.next().map_or_else(
144 || Err(Error::Custom("Expected [ after _substr_".to_string())),
145 |v| {
146 let v = v.map_err(|e| Error::InvalidCOERCE(e.to_string()))?;
147 if v.kind == TokenKind::OpenBracket {
148 Ok(v)
149 } else {
150 Err(Error::Custom("Expected [ after _substr_".to_string()))
151 }
152 },
153 )?;
154
155 let start_idx = match parser.tokenizer.next().map_or_else(
156 || {
157 Err(Error::Custom(
158 "Expected number or colon after _substr_[".to_string(),
159 ))
160 },
161 Ok,
162 )?? {
163 Token {
164 kind: TokenKind::Number,
165 start,
166 len,
167 } => {
168 let start = start as usize;
169 Some(
170 String::from_utf8_lossy(&parser.exp[start..start + len as usize])
171 .parse::<usize>()?,
172 )
173 }
174 Token {
175 kind: TokenKind::Colon,
176 ..
177 } => None,
178 tok => {
179 let start = tok.start as usize;
180 Err(Error::Custom(format!(
181 "Expected number after _substr_[ but got {}",
182 String::from_utf8_lossy(&parser.exp[start..start + tok.len as usize])
183 )))?
184 }
185 };
186
187 if start_idx.is_some() {
188 let _ = parser.tokenizer.next().map_or_else(
189 || Err(Error::Custom("Expected : after _substr_[n".to_string())),
190 |v| {
191 let v = v.map_err(|e| Error::InvalidCOERCE(e.to_string()))?;
192 if v.kind == TokenKind::Colon {
193 Ok(v)
194 } else {
195 Err(Error::Custom("Expected : after _substr_[n".to_string()))
196 }
197 },
198 )?;
199 }
200
201 let end_idx = match parser.tokenizer.next().map_or_else(
202 || {
203 Err(Error::Custom(
204 "Expected number or ] after _substr_[n:".to_string(),
205 ))
206 },
207 Ok,
208 )?? {
209 Token {
210 kind: TokenKind::Number,
211 start,
212 len,
213 } => {
214 let start = start as usize;
215 Some(
216 String::from_utf8_lossy(&parser.exp[start..start + len as usize])
217 .parse::<usize>()?,
218 )
219 }
220 Token {
221 kind: TokenKind::CloseBracket,
222 ..
223 } => None,
224 tok => {
225 let start = tok.start as usize;
226 Err(Error::Custom(format!(
227 "Expected number after _substr_[n: but got {}",
228 String::from_utf8_lossy(&parser.exp[start..start + tok.len as usize])
229 )))?
230 }
231 };
232
233 if end_idx.is_some() {
234 let _ = parser.tokenizer.next().map_or_else(
235 || Err(Error::Custom("Expected ] after _substr_[n:n".to_string())),
236 |v| {
237 let v = v.map_err(|e| Error::InvalidCOERCE(e.to_string()))?;
238 if v.kind == TokenKind::CloseBracket {
239 Ok(v)
240 } else {
241 Err(Error::Custom("Expected ] after _substr_[n:n".to_string()))
242 }
243 },
244 )?;
245 }
246
247 match (start_idx, end_idx) {
248 (Some(start), Some(end)) if start > end => Err(Error::Custom(format!(
249 "Start index {start} is greater than end index {end}"
250 )))?,
251 (None, None) => Err(Error::Custom(
252 "Start and end index for substr cannot both be None".to_string(),
253 ))?,
254 _ => {}
255 }
256
257 let value = CoerceSubstr {
258 value: expression,
259 start_idx,
260 end_idx,
261 };
262 if const_eligible {
263 Ok((
264 const_eligible,
265 Box::new(CoercedConst {
266 value: value.calculate(&[])?,
267 }),
268 ))
269 } else {
270 Ok((false, Box::new(value)))
271 }
272 },
273 );
274 RwLock::new(m)
275 })
276}
277
278#[derive(Debug, PartialEq, Clone, Serialize)]
280#[serde(untagged)]
281pub enum Value {
282 Null,
283 String(String),
284 Number(f64),
285 Bool(bool),
286 DateTime(DateTime<Utc>), Object(BTreeMap<String, Value>),
288 Array(Vec<Value>),
289}
290
291impl Display for Value {
292 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
293 use serde::ser::Error;
294
295 match serde_json::to_string(self) {
296 Ok(s) => {
297 f.write_str(&s)?;
298 Ok(())
299 }
300 Err(e) => Err(std::fmt::Error::custom(e)),
301 }
302 }
303}
304
305impl From<gjson::Value<'_>> for Value {
306 fn from(v: gjson::Value) -> Self {
307 match v.kind() {
308 Kind::Null => Value::Null,
309 Kind::String => Value::String(v.str().to_string()),
310 Kind::Number => Value::Number(v.f64()),
311 Kind::False => Value::Bool(false),
312 Kind::True => Value::Bool(true),
313 Kind::Array => {
314 let arr = v.array().into_iter().map(Into::into).collect();
315 Value::Array(arr)
316 }
317 Kind::Object => {
318 let mut m = BTreeMap::new();
319 v.each(|k, v| {
320 m.insert(k.str().to_string(), v.into());
321 true
322 });
323 Value::Object(m)
324 }
325 }
326 }
327}
328
329pub trait Expression: Debug + Send + Sync {
331 fn calculate(&self, json: &[u8]) -> Result<Value>;
342}
343
344impl<T: Expression + ?Sized> Expression for Box<T> {
345 fn calculate(&self, json: &[u8]) -> Result<Value> {
346 (**self).calculate(json)
348 }
349}
350
351pub(in crate::parser) type BoxedExpression = Box<dyn Expression>;
353
354pub struct Parser<'a> {
356 exp: &'a [u8],
357 tokenizer: Peekable<Tokenizer<'a>>,
358}
359
360impl<'a> Parser<'a> {
361 fn new(exp: &'a [u8], tokenizer: Peekable<Tokenizer<'a>>) -> Self {
362 Parser { exp, tokenizer }
363 }
364
365 #[inline]
372 pub fn parse(expression: &str) -> anyhow::Result<BoxedExpression> {
373 Parser::parse_bytes(expression.as_bytes())
374 }
375
376 pub fn parse_bytes(expression: &[u8]) -> anyhow::Result<BoxedExpression> {
383 let tokenizer = Tokenizer::new_bytes(expression).peekable();
384 let mut parser = Parser::new(expression, tokenizer);
385 let result = parser.parse_expression()?;
386
387 match result {
388 Some(result) => Ok(result),
389 _ => Err(anyhow!("no expression results found")),
390 }
391 }
392
393 #[allow(clippy::too_many_lines)]
394 fn parse_expression(&mut self) -> anyhow::Result<Option<BoxedExpression>> {
395 let mut current: Option<BoxedExpression> = None;
396
397 loop {
398 if let Some(token) = self.tokenizer.next() {
399 let token = token?;
400 match current {
401 Some(expression) => {
402 if token.kind == TokenKind::CloseParen {
404 return Ok(Some(expression));
405 }
406 current = self.parse_operation(token, expression)?;
408 }
409 _ => {
410 current = Some(self.parse_value(token)?);
412 }
413 }
414 } else {
415 return Ok(current);
416 }
417 }
418 }
419
420 #[allow(clippy::too_many_lines)]
421 fn parse_value(&mut self, token: Token) -> anyhow::Result<BoxedExpression> {
422 match token.kind {
423 TokenKind::OpenBracket => {
424 let mut arr = Vec::new();
425
426 loop {
427 if let Some(token) = self.tokenizer.next() {
428 let token = token?;
429
430 match token.kind {
431 TokenKind::CloseBracket => {
432 break;
433 }
434 TokenKind::Comma => {} _ => {
436 arr.push(self.parse_value(token)?);
437 }
438 }
439 } else {
440 return Err(anyhow!("unclosed Array '['"));
441 }
442 }
443 Ok(Box::new(Arr { arr }))
444 }
445 TokenKind::OpenParen => match self.parse_expression()? {
446 Some(expression) => Ok(expression),
447 _ => Err(anyhow!(
448 "expression after open parenthesis '(' ends unexpectedly."
449 )),
450 },
451 TokenKind::SelectorPath => {
452 let start = token.start as usize;
453 Ok(Box::new(SelectorPath {
454 ident: String::from_utf8_lossy(
455 &self.exp[start + 1..(start + token.len as usize)],
456 )
457 .into_owned(),
458 }))
459 }
460 TokenKind::QuotedString => {
461 let start = token.start as usize;
462 Ok(Box::new(Str {
463 s: String::from_utf8_lossy(
464 &self.exp[start + 1..(start + token.len as usize - 1)],
465 )
466 .into_owned(),
467 }))
468 }
469 TokenKind::Number => {
470 let start = token.start as usize;
471 Ok(Box::new(Num {
472 n: String::from_utf8_lossy(&self.exp[start..start + token.len as usize])
473 .parse()?,
474 }))
475 }
476 TokenKind::BooleanTrue => Ok(Box::new(Bool { b: true })),
477 TokenKind::BooleanFalse => Ok(Box::new(Bool { b: false })),
478 TokenKind::Null => Ok(Box::new(Null {})),
479 TokenKind::Coerce => {
480 let next_token = self.next_operator_token(token)?;
482 let mut const_eligible = matches!(
483 next_token.kind,
484 TokenKind::QuotedString
485 | TokenKind::Number
486 | TokenKind::BooleanFalse
487 | TokenKind::BooleanTrue
488 | TokenKind::Null
489 );
490 let mut expression = self.parse_value(next_token)?;
491 loop {
492 if let Some(token) = self.tokenizer.next() {
493 let token = token?;
494 let start = token.start as usize;
495
496 if token.kind == TokenKind::Identifier {
497 let ident = String::from_utf8_lossy(
498 &self.exp[start..start + token.len as usize],
499 );
500 let hm = coercions().read().unwrap();
501 match hm.get(ident.as_ref()) {
502 Some(f) => {
503 let (ce, ne) = f(self, const_eligible, expression)?;
504 const_eligible = ce;
505 expression = ne;
506 }
507 _ => {
508 return Err(anyhow!("invalid COERCE data type '{:?}'", &ident));
509 }
510 }
511 } else {
512 return Err(anyhow!(
513 "COERCE missing data type identifier, found instead: {:?}",
514 &self.exp[start..(start + token.len as usize)]
515 ));
516 }
517 } else {
518 return Err(anyhow!("no identifier after value for: COERCE"));
519 }
520 if let Some(Ok(token)) = self.tokenizer.peek()
521 && token.kind == TokenKind::Comma
522 {
523 let _ = self.tokenizer.next(); continue;
525 }
526 break;
527 }
528 Ok(expression)
529 }
530 TokenKind::Not => {
531 let next_token = self.next_operator_token(token)?;
532 let value = self.parse_value(next_token)?;
533 Ok(Box::new(Not { value }))
534 }
535 _ => Err(anyhow!("token is not a valid value: {token:?}")),
536 }
537 }
538
539 #[allow(clippy::too_many_lines, clippy::needless_pass_by_value)]
540 fn next_operator_token(&mut self, operation_token: Token) -> anyhow::Result<Token> {
541 if let Some(token) = self.tokenizer.next() {
542 Ok(token?)
543 } else {
544 let start = operation_token.start as usize;
545 Err(anyhow!(
546 "no value found after operation: {:?}",
547 &self.exp[start..(start + operation_token.len as usize)]
548 ))
549 }
550 }
551
552 #[allow(clippy::too_many_lines)]
553 fn parse_operation(
554 &mut self,
555 token: Token,
556 current: BoxedExpression,
557 ) -> anyhow::Result<Option<BoxedExpression>> {
558 match token.kind {
559 TokenKind::Add => {
560 let next_token = self.next_operator_token(token)?;
561 let right = self.parse_value(next_token)?;
562 Ok(Some(Box::new(Add {
563 left: current,
564 right,
565 })))
566 }
567 TokenKind::Subtract => {
568 let next_token = self.next_operator_token(token)?;
569 let right = self.parse_value(next_token)?;
570 Ok(Some(Box::new(Sub {
571 left: current,
572 right,
573 })))
574 }
575 TokenKind::Multiply => {
576 let next_token = self.next_operator_token(token)?;
577 let right = self.parse_value(next_token)?;
578 Ok(Some(Box::new(Mult {
579 left: current,
580 right,
581 })))
582 }
583 TokenKind::Divide => {
584 let next_token = self.next_operator_token(token)?;
585 let right = self.parse_value(next_token)?;
586 Ok(Some(Box::new(Div {
587 left: current,
588 right,
589 })))
590 }
591 TokenKind::Equals => {
592 let next_token = self.next_operator_token(token)?;
593 let right = self.parse_value(next_token)?;
594 Ok(Some(Box::new(Eq {
595 left: current,
596 right,
597 })))
598 }
599 TokenKind::Gt => {
600 let next_token = self.next_operator_token(token)?;
601 let right = self.parse_value(next_token)?;
602 Ok(Some(Box::new(Gt {
603 left: current,
604 right,
605 })))
606 }
607 TokenKind::Gte => {
608 let next_token = self.next_operator_token(token)?;
609 let right = self.parse_value(next_token)?;
610 Ok(Some(Box::new(Gte {
611 left: current,
612 right,
613 })))
614 }
615 TokenKind::Lt => {
616 let next_token = self.next_operator_token(token)?;
617 let right = self.parse_value(next_token)?;
618 Ok(Some(Box::new(Lt {
619 left: current,
620 right,
621 })))
622 }
623 TokenKind::Lte => {
624 let next_token = self.next_operator_token(token)?;
625 let right = self.parse_value(next_token)?;
626 Ok(Some(Box::new(Lte {
627 left: current,
628 right,
629 })))
630 }
631 TokenKind::Or => {
632 let right = self
633 .parse_expression()?
634 .map_or_else(|| Err(anyhow!("invalid operation after ||")), Ok)?;
635 Ok(Some(Box::new(Or {
636 left: current,
637 right,
638 })))
639 }
640 TokenKind::And => {
641 let right = self
642 .parse_expression()?
643 .map_or_else(|| Err(anyhow!("invalid operation after &&")), Ok)?;
644 Ok(Some(Box::new(And {
645 left: current,
646 right,
647 })))
648 }
649 TokenKind::StartsWith => {
650 let next_token = self.next_operator_token(token)?;
651 let right = self.parse_value(next_token)?;
652 Ok(Some(Box::new(StartsWith {
653 left: current,
654 right,
655 })))
656 }
657 TokenKind::EndsWith => {
658 let next_token = self.next_operator_token(token)?;
659 let right = self.parse_value(next_token)?;
660 Ok(Some(Box::new(EndsWith {
661 left: current,
662 right,
663 })))
664 }
665 TokenKind::In => {
666 let next_token = self.next_operator_token(token)?;
667 let right = self.parse_value(next_token)?;
668 Ok(Some(Box::new(In {
669 left: current,
670 right,
671 })))
672 }
673 TokenKind::Contains => {
674 let next_token = self.next_operator_token(token)?;
675 let right = self.parse_value(next_token)?;
676 Ok(Some(Box::new(Contains {
677 left: current,
678 right,
679 })))
680 }
681 TokenKind::ContainsAny => {
682 let next_token = self.next_operator_token(token)?;
683 let right = self.parse_value(next_token)?;
684 Ok(Some(Box::new(ContainsAny {
685 left: current,
686 right,
687 })))
688 }
689 TokenKind::ContainsAll => {
690 let next_token = self.next_operator_token(token)?;
691 let right = self.parse_value(next_token)?;
692 Ok(Some(Box::new(ContainsAll {
693 left: current,
694 right,
695 })))
696 }
697 TokenKind::Between => {
698 let lhs_token = self.next_operator_token(token.clone())?;
699 let left = self.parse_value(lhs_token)?;
700 let rhs_token = self.next_operator_token(token)?;
701 let right = self.parse_value(rhs_token)?;
702 Ok(Some(Box::new(Between {
703 left,
704 right,
705 value: current,
706 })))
707 }
708 TokenKind::Not => {
709 let next_token = self.next_operator_token(token)?;
710 let value = self
711 .parse_operation(next_token, current)?
712 .map_or_else(|| Err(anyhow!("invalid operation after !")), Ok)?;
713 Ok(Some(Box::new(Not { value })))
714 }
715 TokenKind::CloseBracket => Ok(Some(current)),
716 _ => Err(anyhow!("invalid operation: {token:?}")),
717 }
718 }
719}
720
721pub type Result<T> = std::result::Result<T, Error>;
723
724#[derive(Error, Debug, PartialEq, Eq)]
726pub enum Error {
727 #[error("unsupported type comparison: {0}")]
728 UnsupportedTypeComparison(String),
729
730 #[error("unsupported COERCE: {0}")]
731 UnsupportedCOERCE(String),
732
733 #[error("invalid COERCE: {0}")]
734 InvalidCOERCE(String),
735
736 #[error("{0}")]
737 Custom(String),
738}
739
740#[cfg(test)]
741mod tests {
742 use super::*;
743
744 #[test]
745 fn sp_add_str_sp() -> anyhow::Result<()> {
746 let src = r#"{"field1":"Dean","field2":"Karn"}"#;
747 let expression = r#".field1 + " " + .field2"#;
748
749 let ex = Parser::parse(expression)?;
750 let result = ex.calculate(src.as_ref())?;
751 assert_eq!(Value::String("Dean Karn".to_string()), result);
752 Ok(())
753 }
754
755 #[test]
756 fn sp_add_sp_num() -> anyhow::Result<()> {
757 let src = r#"{"field1":10.1,"field2":23.23}"#;
758 let expression = ".field1 + .field2";
759
760 let ex = Parser::parse(expression)?;
761 let result = ex.calculate(src.as_ref())?;
762 assert_eq!(Value::Number(33.33), result);
763 Ok(())
764 }
765
766 #[test]
767 fn sp_sub_sp() -> anyhow::Result<()> {
768 let src = r#"{"field1":10.1,"field2":23.23}"#;
769 let expression = ".field2 - .field1";
770
771 let ex = Parser::parse(expression)?;
772 let result = ex.calculate(src.as_ref())?;
773 assert_eq!(Value::Number(13.13), result);
774 Ok(())
775 }
776
777 #[test]
778 fn sp_mult_identsp() -> anyhow::Result<()> {
779 let src = r#"{"field1":11.1,"field2":3}"#;
780 let expression = ".field2 * .field1";
781
782 let ex = Parser::parse(expression)?;
783 let result = ex.calculate(src.as_ref())?;
784 assert_eq!(Value::Number(33.3), result);
785 Ok(())
786 }
787
788 #[test]
789 fn sp_div_sp() -> anyhow::Result<()> {
790 let src = r#"{"field1":3,"field2":33.3}"#;
791 let expression = ".field2 / .field1";
792
793 let ex = Parser::parse(expression)?;
794 let result = ex.calculate(src.as_ref())?;
795 assert_eq!(Value::Number(11.1), result);
796 Ok(())
797 }
798
799 #[test]
800 fn num_add_num() -> anyhow::Result<()> {
801 let src = "";
802 let expression = "11.1 + 22.2";
803
804 let ex = Parser::parse(expression)?;
805 let result = ex.calculate(src.as_ref())?;
806 assert_eq!(Value::Number(33.3), result);
807 Ok(())
808 }
809
810 #[test]
811 fn sp_add_num() -> anyhow::Result<()> {
812 let src = r#"{"field1":3,"field2":33.3}"#;
813 let expression = "11.1 + .field1";
814
815 let ex = Parser::parse(expression)?;
816 let result = ex.calculate(src.as_ref())?;
817 assert_eq!(Value::Number(14.1), result);
818 Ok(())
819 }
820
821 #[test]
822 fn sp_eq_num_false() -> anyhow::Result<()> {
823 let src = r#"{"field1":3,"field2":33.3}"#;
824 let expression = "11.1 == .field1";
825
826 let ex = Parser::parse(expression)?;
827 let result = ex.calculate(src.as_ref())?;
828 assert_eq!(Value::Bool(false), result);
829 Ok(())
830 }
831
832 #[test]
833 fn sp_eq_num_true() -> anyhow::Result<()> {
834 let src = r#"{"field1":11.1,"field2":33.3}"#;
835 let expression = "11.1 == .field1";
836
837 let ex = Parser::parse(expression)?;
838 let result = ex.calculate(src.as_ref())?;
839 assert_eq!(Value::Bool(true), result);
840 Ok(())
841 }
842
843 #[test]
844 fn sp_gt_num_false() -> anyhow::Result<()> {
845 let src = r#"{"field1":11.1,"field2":33.3}"#;
846 let expression = "11.1 > .field1";
847
848 let ex = Parser::parse(expression)?;
849 let result = ex.calculate(src.as_ref())?;
850 assert_eq!(Value::Bool(false), result);
851 Ok(())
852 }
853
854 #[test]
855 fn sp_gte_num_true() -> anyhow::Result<()> {
856 let src = r#"{"field1":11.1,"field2":33.3}"#;
857 let expression = "11.1 >= .field1";
858
859 let ex = Parser::parse(expression)?;
860 let result = ex.calculate(src.as_ref())?;
861 assert_eq!(Value::Bool(true), result);
862 Ok(())
863 }
864
865 #[test]
866 fn bool_true() -> anyhow::Result<()> {
867 let ex = Parser::parse("true == true")?;
868 let result = ex.calculate("".as_bytes())?;
869 assert_eq!(Value::Bool(true), result);
870 Ok(())
871 }
872
873 #[test]
874 fn bool_false() -> anyhow::Result<()> {
875 let ex = Parser::parse("false == true")?;
876 let result = ex.calculate("".as_bytes())?;
877 assert_eq!(Value::Bool(false), result);
878 Ok(())
879 }
880
881 #[test]
882 fn null_eq() -> anyhow::Result<()> {
883 let ex = Parser::parse("NULL == NULL")?;
884 let result = ex.calculate("".as_bytes())?;
885 assert_eq!(Value::Bool(true), result);
886 Ok(())
887 }
888
889 #[test]
890 fn or() -> anyhow::Result<()> {
891 let ex = Parser::parse("true || false")?;
892 let result = ex.calculate("".as_bytes())?;
893 assert_eq!(Value::Bool(true), result);
894
895 let ex = Parser::parse("false || true")?;
896 let result = ex.calculate("".as_bytes())?;
897 assert_eq!(Value::Bool(true), result);
898
899 let ex = Parser::parse("false || false")?;
900 let result = ex.calculate("".as_bytes())?;
901 assert_eq!(Value::Bool(false), result);
902
903 let ex = Parser::parse("false || false || false == false")?;
904 let result = ex.calculate("".as_bytes())?;
905 assert_eq!(Value::Bool(true), result);
906
907 let ex = Parser::parse("false || false || false != false")?;
908 let result = ex.calculate("".as_bytes())?;
909 assert_eq!(Value::Bool(false), result);
910
911 Ok(())
912 }
913
914 #[test]
915 fn and() -> anyhow::Result<()> {
916 let ex = Parser::parse("true == true && false == false")?;
917 let result = ex.calculate("".as_bytes())?;
918 assert_eq!(Value::Bool(true), result);
919
920 let ex = Parser::parse("true && true")?;
921 let result = ex.calculate("".as_bytes())?;
922 assert_eq!(Value::Bool(true), result);
923
924 let ex = Parser::parse("false && false")?;
925 let result = ex.calculate("".as_bytes())?;
926 assert_eq!(Value::Bool(false), result);
927
928 let ex = Parser::parse("true && false")?;
929 let result = ex.calculate("".as_bytes())?;
930 assert_eq!(Value::Bool(false), result);
931
932 let ex = Parser::parse("false && true")?;
933 let result = ex.calculate("".as_bytes())?;
934 assert_eq!(Value::Bool(false), result);
935
936 Ok(())
937 }
938
939 #[test]
940 fn starts_with() -> anyhow::Result<()> {
941 let ex = Parser::parse(r#""team" STARTSWITH "i""#)?;
942 let result = ex.calculate("".as_bytes())?;
943 assert_eq!(Value::Bool(false), result);
944
945 let ex = Parser::parse(r#""team" STARTSWITH "te""#)?;
946 let result = ex.calculate("".as_bytes())?;
947 assert_eq!(Value::Bool(true), result);
948 Ok(())
949 }
950
951 #[test]
952 fn ends_with() -> anyhow::Result<()> {
953 let ex = Parser::parse(r#""team" ENDSWITH "i""#)?;
954 let result = ex.calculate("".as_bytes())?;
955 assert_eq!(Value::Bool(false), result);
956
957 let ex = Parser::parse(r#""team" ENDSWITH "am""#)?;
958 let result = ex.calculate("".as_bytes())?;
959 assert_eq!(Value::Bool(true), result);
960 Ok(())
961 }
962
963 #[test]
964 fn contains() -> anyhow::Result<()> {
965 let ex = Parser::parse(r#""team" CONTAINS "i""#)?;
966 let result = ex.calculate("".as_bytes())?;
967 assert_eq!(Value::Bool(false), result);
968
969 let ex = Parser::parse(r#""team" CONTAINS "ea""#)?;
970 let result = ex.calculate("".as_bytes())?;
971 assert_eq!(Value::Bool(true), result);
972
973 let ex = Parser::parse(r#"["ea"] CONTAINS "ea""#)?;
974 let result = ex.calculate("".as_bytes())?;
975 assert_eq!(Value::Bool(true), result);
976
977 let ex = Parser::parse(r#"["nope"] CONTAINS "ea""#)?;
978 let result = ex.calculate("".as_bytes())?;
979 assert_eq!(Value::Bool(false), result);
980
981 let ex = Parser::parse(r#"["a",["b","a"]] CONTAINS ["b","a"]"#)?;
982 let result = ex.calculate("".as_bytes())?;
983 assert_eq!(Value::Bool(true), result);
984 Ok(())
985 }
986
987 #[test]
988 fn contains_any() -> anyhow::Result<()> {
989 let ex = Parser::parse(r#""team" CONTAINS_ANY "im""#)?;
990 let result = ex.calculate("".as_bytes())?;
991 assert_eq!(Value::Bool(true), result);
992
993 let ex = Parser::parse(r#"["a","b","c"] CONTAINS_ANY "eac""#)?;
994 let result = ex.calculate("".as_bytes())?;
995 assert_eq!(Value::Bool(true), result);
996
997 let ex = Parser::parse(r#"["a","b","c"] CONTAINS_ANY "xyz""#)?;
998 let result = ex.calculate("".as_bytes())?;
999 assert_eq!(Value::Bool(false), result);
1000
1001 let ex = Parser::parse(r#"["a","b","c"] CONTAINS_ANY ["c","d","e"]"#)?;
1002 let result = ex.calculate("".as_bytes())?;
1003 assert_eq!(Value::Bool(true), result);
1004
1005 let ex = Parser::parse(r#"["a","b","c"] CONTAINS_ANY ["d","e","f"]"#)?;
1006 let result = ex.calculate("".as_bytes())?;
1007 assert_eq!(Value::Bool(false), result);
1008
1009 let ex = Parser::parse(r#"["a","b","c"] !CONTAINS_ANY ["d","e","f"]"#)?;
1010 let result = ex.calculate("".as_bytes())?;
1011 assert_eq!(Value::Bool(true), result);
1012
1013 let src = r#"{"AnnualRevenue":"2000000","NumberOfEmployees":"201","FirstName":"scott"}"#
1014 .as_bytes();
1015 let ex =
1016 Parser::parse(r#".FirstName CONTAINS_ANY ["noah", "emily", "alexandra","scott"]"#)?;
1017 let result = ex.calculate(src)?;
1018 assert_eq!(Value::Bool(true), result);
1019
1020 let src = r#"{"AnnualRevenue":"2000000","NumberOfEmployees":"201","FirstName":"scott"}"#
1021 .as_bytes();
1022 let ex = Parser::parse(r#".FirstName CONTAINS_ANY ["noah", "emily", "alexandra"]"#)?;
1023 let result = ex.calculate(src)?;
1024 assert_eq!(Value::Bool(false), result);
1025
1026 Ok(())
1027 }
1028
1029 #[test]
1030 fn contains_all() -> anyhow::Result<()> {
1031 let ex = Parser::parse(r#""team" CONTAINS_ALL "meat""#)?;
1032 let result = ex.calculate("".as_bytes())?;
1033 assert_eq!(Value::Bool(true), result);
1034
1035 let ex = Parser::parse(r#"["a","b","c"] CONTAINS_ALL "cab""#)?;
1036 let result = ex.calculate("".as_bytes())?;
1037 assert_eq!(Value::Bool(true), result);
1038
1039 let ex = Parser::parse(r#"["a","b","c"] CONTAINS_ALL "xyz""#)?;
1040 let result = ex.calculate("".as_bytes())?;
1041 assert_eq!(Value::Bool(false), result);
1042
1043 let ex = Parser::parse(r#"["a","b","c"] CONTAINS_ALL ["c","a","b"]"#)?;
1044 let result = ex.calculate("".as_bytes())?;
1045 assert_eq!(Value::Bool(true), result);
1046
1047 let ex = Parser::parse(r#"["a","b","c"] CONTAINS_ALL ["a","b"]"#)?;
1048 let result = ex.calculate("".as_bytes())?;
1049 assert_eq!(Value::Bool(true), result);
1050
1051 let ex = Parser::parse(r#"["a","b","c"] !CONTAINS_ALL ["a","b"]"#)?;
1052 let result = ex.calculate("".as_bytes())?;
1053 assert_eq!(Value::Bool(false), result);
1054
1055 let src = r#"{"AnnualRevenue":"2000000","NumberOfEmployees":"201","FirstName":"scott"}"#
1056 .as_bytes();
1057 let ex = Parser::parse(r#".FirstName CONTAINS_ALL ["sc", "ot", "ott","cot"]"#)?;
1058 let result = ex.calculate(src)?;
1059 assert_eq!(Value::Bool(true), result);
1060
1061 let src = r#"{"AnnualRevenue":"2000000","NumberOfEmployees":"201","FirstName":"scott"}"#
1062 .as_bytes();
1063 let ex = Parser::parse(r#".FirstName CONTAINS_ALL ["sc", "ot", "ott","b"]"#)?;
1064 let result = ex.calculate(src)?;
1065 assert_eq!(Value::Bool(false), result);
1066
1067 Ok(())
1068 }
1069
1070 #[test]
1071 fn inn() -> anyhow::Result<()> {
1072 let src = r#"{"field1":["test"]}"#.as_bytes();
1073 let expression = r#""test" IN .field1"#;
1074 let ex = Parser::parse(expression)?;
1075 let result = ex.calculate(src)?;
1076 assert_eq!(Value::Bool(true), result);
1077
1078 let src = r#"{"field1":["test"]}"#.as_bytes();
1079 let expression = r#""test" !IN .field1"#;
1080 let ex = Parser::parse(expression)?;
1081 let result = ex.calculate(src)?;
1082 assert_eq!(Value::Bool(false), result);
1083
1084 let expression = r#""test" !IN ["b","a","c"]"#;
1085 let ex = Parser::parse(expression)?;
1086 let result = ex.calculate("".as_bytes())?;
1087 assert_eq!(Value::Bool(true), result);
1088
1089 let src = r#"{"field1":["test"]}"#.as_bytes();
1090 let expression = r#""me" IN .field1"#;
1091 let ex = Parser::parse(expression)?;
1092 let result = ex.calculate(src)?;
1093 assert_eq!(Value::Bool(false), result);
1094 Ok(())
1095 }
1096
1097 #[test]
1098 fn inn_arr() -> anyhow::Result<()> {
1099 let expression = r#""me" IN ["you","me"]"#;
1100 let ex = Parser::parse(expression)?;
1101 let result = ex.calculate("".as_bytes())?;
1102 assert_eq!(Value::Bool(true), result);
1103
1104 let expression = r#""me" IN ["z"]"#;
1105 let ex = Parser::parse(expression)?;
1106 let result = ex.calculate("".as_bytes())?;
1107 assert_eq!(Value::Bool(false), result);
1108
1109 let expression = r#""me" IN []"#;
1110 let ex = Parser::parse(expression)?;
1111 let result = ex.calculate("".as_bytes())?;
1112 assert_eq!(Value::Bool(false), result);
1113
1114 let expression = "[] == []";
1115 let ex = Parser::parse(expression)?;
1116 let result = ex.calculate("".as_bytes())?;
1117 assert_eq!(Value::Bool(true), result);
1118
1119 let expression = r#"[] == ["test"]"#;
1120 let ex = Parser::parse(expression)?;
1121 let result = ex.calculate("".as_bytes())?;
1122 assert_eq!(Value::Bool(false), result);
1123
1124 Ok(())
1125 }
1126
1127 #[test]
1128 fn ampersand() -> anyhow::Result<()> {
1129 let expression = "(1 + 1) / 2";
1130 let ex = Parser::parse(expression)?;
1131 let result = ex.calculate("".as_bytes())?;
1132 assert_eq!(Value::Number(1.0), result);
1133
1134 let expression = "1 + (1 / 2)";
1135 let ex = Parser::parse(expression)?;
1136 let result = ex.calculate("".as_bytes())?;
1137 assert_eq!(Value::Number(1.5), result);
1138 Ok(())
1139 }
1140
1141 #[test]
1142 fn company_employees() -> anyhow::Result<()> {
1143 let src = r#"{"name":"Company","properties":{"employees":50}}"#.as_bytes();
1144 let expression = ".properties.employees > 20";
1145 let ex = Parser::parse(expression)?;
1146 let result = ex.calculate(src)?;
1147 assert_eq!(Value::Bool(true), result);
1148
1149 let expression = ".properties.employees > 50";
1150 let ex = Parser::parse(expression)?;
1151 let result = ex.calculate(src)?;
1152 assert_eq!(Value::Bool(false), result);
1153 Ok(())
1154 }
1155
1156 #[test]
1157 fn company_not_employees() -> anyhow::Result<()> {
1158 let src = r#"{"name":"Company","properties":{"employees":50}}"#.as_bytes();
1159 let expression = ".properties.employees !> 20";
1160 let ex = Parser::parse(expression)?;
1161 let result = ex.calculate(src)?;
1162 assert_eq!(Value::Bool(false), result);
1163
1164 let expression = ".properties.employees !> 50";
1165 let ex = Parser::parse(expression)?;
1166 let result = ex.calculate(src)?;
1167 assert_eq!(Value::Bool(true), result);
1168
1169 let expression = ".properties.employees != 50";
1170 let ex = Parser::parse(expression)?;
1171 let result = ex.calculate(src)?;
1172 assert_eq!(Value::Bool(false), result);
1173 Ok(())
1174 }
1175
1176 #[test]
1177 fn company_not() -> anyhow::Result<()> {
1178 let src = r#"{"f1":true,"f2":false}"#.as_bytes();
1179 let expression = "!.f1";
1180 let ex = Parser::parse(expression)?;
1181 let result = ex.calculate(src)?;
1182 assert_eq!(Value::Bool(false), result);
1183
1184 let src = r#"{"f1":true,"f2":false}"#.as_bytes();
1185 let expression = "!.f2";
1186 let ex = Parser::parse(expression)?;
1187 let result = ex.calculate(src)?;
1188 assert_eq!(Value::Bool(true), result);
1189
1190 let src = r#"{"f1":true,"f2":false}"#.as_bytes();
1191 let expression = "!(.f1 && .f2)";
1192 let ex = Parser::parse(expression)?;
1193 let result = ex.calculate(src)?;
1194 assert_eq!(Value::Bool(true), result);
1195
1196 let src = r#"{"f1":true,"f2":false}"#.as_bytes();
1197 let expression = "!(.f1 != .f2)";
1198 let ex = Parser::parse(expression)?;
1199 let result = ex.calculate(src)?;
1200 assert_eq!(Value::Bool(false), result);
1201
1202 let src = r#"{"f1":true,"f2":false}"#.as_bytes();
1203 let expression = "!(.f1 != .f2) && !.f2";
1204 let ex = Parser::parse(expression)?;
1205 let result = ex.calculate(src)?;
1206 assert_eq!(Value::Bool(false), result);
1207
1208 Ok(())
1209 }
1210
1211 #[test]
1212 fn test_display() {
1213 assert_eq!(format!("{}", Value::Null), "null");
1214 assert_eq!(
1215 format!("{}", Value::String("string".to_string())),
1216 r#""string""#
1217 );
1218 assert_eq!(format!("{}", Value::Number(64.1)), "64.1");
1219 assert_eq!(format!("{}", Value::Bool(true)), "true");
1220
1221 let mut m = BTreeMap::new();
1222 m.insert("key".to_string(), Value::String("value".to_string()));
1223 m.insert("key2".to_string(), Value::String("value2".to_string()));
1224
1225 assert_eq!(
1226 format!("{}", Value::Object(m)),
1227 r#"{"key":"value","key2":"value2"}"#
1228 );
1229 assert_eq!(
1230 format!(
1231 "{}",
1232 Value::Array(vec![
1233 Value::String("string".to_string()),
1234 Value::Number(1.1)
1235 ])
1236 ),
1237 r#"["string",1.1]"#
1238 );
1239 }
1240
1241 #[test]
1242 fn coerce_datetime() -> anyhow::Result<()> {
1243 let src = r#"{"name":"2022-01-02"}"#.as_bytes();
1244 let expression = "COERCE .name _datetime_";
1245 let ex = Parser::parse(expression)?;
1246 let result = ex.calculate(src)?;
1247 assert_eq!(r#""2022-01-02T00:00:00Z""#, format!("{result}"));
1248
1249 let src = r#"{"dt1":"2022-01-02","dt2":"2022-01-02"}"#.as_bytes();
1250 let expression = "COERCE .dt1 _datetime_ == COERCE .dt2 _datetime_";
1251 let ex = Parser::parse(expression)?;
1252 let result = ex.calculate(src)?;
1253 assert_eq!(Value::Bool(true), result);
1254
1255 let src =
1256 r#"{"dt1":"2022-07-14T17:50:08.318426000Z","dt2":"2022-07-14T17:50:08.318426001Z"}"#
1257 .as_bytes();
1258 let expression = "COERCE .dt1 _datetime_ == COERCE .dt2 _datetime_ && true == true";
1259 let ex = Parser::parse(expression)?;
1260 let result = ex.calculate(src)?;
1261 assert_eq!(Value::Bool(false), result);
1262
1263 let src =
1264 r#"{"dt1":"2022-07-14T17:50:08.318426000Z","dt2":"2022-07-14T17:50:08.318426001Z"}"#
1265 .as_bytes();
1266 let expression = "(COERCE .dt1 _datetime_ == COERCE .dt2 _datetime_) && true == true";
1267 let ex = Parser::parse(expression)?;
1268 let result = ex.calculate(src)?;
1269 assert_eq!(Value::Bool(false), result);
1270
1271 let src =
1272 r#"{"dt1":"2022-07-14T17:50:08.318426000Z","dt2":"2022-07-14T17:50:08.318426001Z"}"#
1273 .as_bytes();
1274 let expression = "(COERCE .dt1 _datetime_ == COERCE .dt2 _datetime_) && true == true";
1275 let ex = Parser::parse(expression)?;
1276 let result = ex.calculate(src)?;
1277 assert_eq!(Value::Bool(false), result);
1278
1279 let src =
1280 r#"{"dt1":"2022-07-14T17:50:08.318426000Z","dt2":"2022-07-14T17:50:08.318426001Z"}"#
1281 .as_bytes();
1282 let expression = "(COERCE .dt1 _datetime_) == (COERCE .dt2 _datetime_) && true == true";
1283 let ex = Parser::parse(expression)?;
1284 let result = ex.calculate(src)?;
1285 assert_eq!(Value::Bool(false), result);
1286
1287 let src = r#"{"dt1":"2022-07-14T17:50:08.318426000Z"}"#.as_bytes();
1288 let expression =
1289 r#"COERCE .dt1 _datetime_ == COERCE "2022-07-14T17:50:08.318426000Z" _datetime_"#;
1290 let ex = Parser::parse(expression)?;
1291 let result = ex.calculate(src)?;
1292 assert_eq!(Value::Bool(true), result);
1293
1294 let src = r#"{"dt1":"2022-07-14T17:50:08.318426000Z"}"#.as_bytes();
1295 let expression =
1296 r#"COERCE .dt1 _datetime_ == COERCE "2022-07-14T17:50:08.318426001Z" _datetime_"#;
1297 let ex = Parser::parse(expression)?;
1298 let result = ex.calculate(src)?;
1299 assert_eq!(Value::Bool(false), result);
1300
1301 let expression = r#"COERCE "2022-07-14T17:50:08.318426000Z" _datetime_ == COERCE "2022-07-14T17:50:08.318426000Z" _datetime_"#;
1302 let ex = Parser::parse(expression)?;
1303 let result = ex.calculate("".as_bytes())?;
1304 assert_eq!(Value::Bool(true), result);
1305
1306 let expression = r#"COERCE "2022-07-14T17:50:08.318426001Z" _datetime_ > COERCE "2022-07-14T17:50:08.318426000Z" _datetime_"#;
1307 let ex = Parser::parse(expression)?;
1308 let result = ex.calculate("".as_bytes())?;
1309 assert_eq!(Value::Bool(true), result);
1310
1311 let expression = r#"COERCE "2022-07-14T17:50:08.318426000Z" _datetime_ < COERCE "2022-07-14T17:50:08.318426001Z" _datetime_"#;
1312 let ex = Parser::parse(expression)?;
1313 let result = ex.calculate("".as_bytes())?;
1314 assert_eq!(Value::Bool(true), result);
1315
1316 let expression = r#"COERCE "2022-07-14T17:50:08.318426000Z" _datetime_ >= COERCE "2022-07-14T17:50:08.318426000Z" _datetime_"#;
1317 let ex = Parser::parse(expression)?;
1318 let result = ex.calculate("".as_bytes())?;
1319 assert_eq!(Value::Bool(true), result);
1320
1321 let expression = r#"COERCE "2022-07-14T17:50:08.318426000Z" _datetime_ <= COERCE "2022-07-14T17:50:08.318426000Z" _datetime_"#;
1322 let ex = Parser::parse(expression)?;
1323 let result = ex.calculate("".as_bytes())?;
1324 assert_eq!(Value::Bool(true), result);
1325
1326 let expression = r#"COERCE "2022-07-14T17:50:08.318426001Z" _datetime_ >= COERCE "2022-07-14T17:50:08.318426000Z" _datetime_"#;
1327 let ex = Parser::parse(expression)?;
1328 let result = ex.calculate("".as_bytes())?;
1329 assert_eq!(Value::Bool(true), result);
1330
1331 let expression = r#"COERCE "2022-07-14T17:50:08.318426000Z" _datetime_ <= COERCE "2022-07-14T17:50:08.318426001Z" _datetime_"#;
1332 let ex = Parser::parse(expression)?;
1333 let result = ex.calculate("".as_bytes())?;
1334 assert_eq!(Value::Bool(true), result);
1335
1336 Ok(())
1337 }
1338
1339 #[test]
1340 fn coerce_number() -> anyhow::Result<()> {
1341 let src = r#"{"key":1}"#.as_bytes();
1342 let expression = "COERCE .key _number_";
1343 let ex = Parser::parse(expression)?;
1344 let result = ex.calculate(src)?;
1345 assert_eq!("1.0", format!("{result}"));
1346
1347 let src = r#"{"key":"2"}"#.as_bytes();
1348 let expression = "COERCE .key _number_";
1349 let ex = Parser::parse(expression)?;
1350 let result = ex.calculate(src)?;
1351 assert_eq!("2.0", format!("{result}"));
1352
1353 let src = r#"{"key":true}"#.as_bytes();
1354 let expression = "COERCE .key _number_";
1355 let ex = Parser::parse(expression)?;
1356 let result = ex.calculate(src)?;
1357 assert_eq!("1.0", format!("{result}"));
1358
1359 let src = r#"{"key":false}"#.as_bytes();
1360 let expression = "COERCE .key _number_";
1361 let ex = Parser::parse(expression)?;
1362 let result = ex.calculate(src)?;
1363 assert_eq!("0.0", format!("{result}"));
1364
1365 let src = r#"{"key":"2023-05-30T06:21:05Z"}"#.as_bytes();
1366 let expression = "COERCE .key _datetime_,_number_";
1367 let ex = Parser::parse(expression)?;
1368 let result = ex.calculate(src)?;
1369 assert_eq!("1.685427665e+18", format!("{result}"));
1370
1371 Ok(())
1372 }
1373
1374 #[test]
1375 fn coerce_string() -> anyhow::Result<()> {
1376 let src = r#"{"name":"Joeybloggs"}"#.as_bytes();
1377 let expression = "COERCE .name _string_";
1378 let ex = Parser::parse(expression)?;
1379 let result = ex.calculate(src)?;
1380 assert_eq!(r#""Joeybloggs""#, format!("{result}"));
1381
1382 let src = r#"{"name":null}"#.as_bytes();
1383 let expression = "COERCE .name _string_";
1384 let ex = Parser::parse(expression)?;
1385 let result = ex.calculate(src)?;
1386 assert_eq!(r#""null""#, format!("{result}"));
1387
1388 let src = r#"{"name":true}"#.as_bytes();
1389 let expression = "COERCE .name _string_";
1390 let ex = Parser::parse(expression)?;
1391 let result = ex.calculate(src)?;
1392 assert_eq!(r#""true""#, format!("{result}"));
1393
1394 let src = r#"{"name":false}"#.as_bytes();
1395 let expression = "COERCE .name _string_";
1396 let ex = Parser::parse(expression)?;
1397 let result = ex.calculate(src)?;
1398 assert_eq!(r#""false""#, format!("{result}"));
1399
1400 let src = r#"{"name":10}"#.as_bytes();
1401 let expression = "COERCE .name _string_";
1402 let ex = Parser::parse(expression)?;
1403 let result = ex.calculate(src)?;
1404 assert_eq!(r#""10""#, format!("{result}"));
1405
1406 let src = r#"{"name":10.03}"#.as_bytes();
1407 let expression = "COERCE .name _string_";
1408 let ex = Parser::parse(expression)?;
1409 let result = ex.calculate(src)?;
1410 assert_eq!(r#""10.03""#, format!("{result}"));
1411
1412 let src = r#"{"name":10.03}"#.as_bytes();
1413 let expression = "COERCE .name _string_";
1414 let ex = Parser::parse(expression)?;
1415 let result = ex.calculate(src)?;
1416 assert_eq!(r#""10.03""#, format!("{result}"));
1417
1418 let src = r#"{"name":"2023-05-30T06:21:05Z"}"#.as_bytes();
1419 let expression = "COERCE .name _datetime_,_string_";
1420 let ex = Parser::parse(expression)?;
1421 let result = ex.calculate(src)?;
1422 assert_eq!(r#""2023-05-30T06:21:05Z""#, format!("{result}"));
1423
1424 let src = r#"{"name":"Joeybloggs","age":39}"#.as_bytes();
1425 let expression = ".name + ' - Age ' + COERCE .age _string_";
1426 let ex = Parser::parse(expression)?;
1427 let result = ex.calculate(src)?;
1428 assert_eq!(r#""Joeybloggs - Age 39""#, format!("{result}"));
1429
1430 Ok(())
1431 }
1432
1433 #[test]
1434 fn coerce_lowercase() -> anyhow::Result<()> {
1435 let src = r#"{"name":"Joeybloggs"}"#.as_bytes();
1436 let expression = "COERCE .name _lowercase_";
1437 let ex = Parser::parse(expression)?;
1438 let result = ex.calculate(src)?;
1439 assert_eq!(r#""joeybloggs""#, format!("{result}"));
1440
1441 let src = r#"{"f1":"dean","f2":"DeAN"}"#.as_bytes();
1442 let expression = "COERCE .f1 _lowercase_ == COERCE .f2 _lowercase_";
1443 let ex = Parser::parse(expression)?;
1444 let result = ex.calculate(src)?;
1445 assert_eq!(Value::Bool(true), result);
1446
1447 Ok(())
1448 }
1449
1450 #[test]
1451 fn coerce_uppercase() -> anyhow::Result<()> {
1452 let src = r#"{"name":"Joeybloggs"}"#.as_bytes();
1453 let expression = "COERCE .name _uppercase_";
1454 let ex = Parser::parse(expression)?;
1455 let result = ex.calculate(src)?;
1456 assert_eq!(r#""JOEYBLOGGS""#, format!("{result}"));
1457
1458 let src = r#"{"f1":"dean","f2":"DeAN"}"#.as_bytes();
1459 let expression = "COERCE .f1 _uppercase_ == COERCE .f2 _uppercase_";
1460 let ex = Parser::parse(expression)?;
1461 let result = ex.calculate(src)?;
1462 assert_eq!(Value::Bool(true), result);
1463
1464 Ok(())
1465 }
1466
1467 #[test]
1468 fn coerce_title() -> anyhow::Result<()> {
1469 let src = r#"{"name":"mr."}"#.as_bytes();
1470 let expression = "COERCE .name _title_";
1471 let ex = Parser::parse(expression)?;
1472 let result = ex.calculate(src)?;
1473 assert_eq!(r#""Mr.""#, format!("{result}"));
1474
1475 let src = r#"{"f1":"mr.","f2":"Mr."}"#.as_bytes();
1476 let expression = "COERCE .f1 _title_ == COERCE .f2 _title_";
1477 let ex = Parser::parse(expression)?;
1478 let result = ex.calculate(src)?;
1479 assert_eq!(Value::Bool(true), result);
1480
1481 Ok(())
1482 }
1483
1484 #[test]
1485 fn coerce_multiple() -> anyhow::Result<()> {
1486 let src = r#"{"name":"mr."}"#.as_bytes();
1487 let expression = "COERCE .name _uppercase_,_title_";
1488 let ex = Parser::parse(expression)?;
1489 let result = ex.calculate(src)?;
1490 assert_eq!(r#""Mr.""#, format!("{result}"));
1491
1492 Ok(())
1493 }
1494
1495 #[test]
1496 fn between() -> anyhow::Result<()> {
1497 let expression = "1 BETWEEN 0 10";
1498 let ex = Parser::parse(expression)?;
1499 let result = ex.calculate("".as_bytes())?;
1500 assert_eq!(Value::Bool(true), result);
1501
1502 let expression = "0 BETWEEN 0 10";
1503 let ex = Parser::parse(expression)?;
1504 let result = ex.calculate("".as_bytes())?;
1505 assert_eq!(Value::Bool(false), result);
1506
1507 let expression = "10 BETWEEN 0 10";
1508 let ex = Parser::parse(expression)?;
1509 let result = ex.calculate("".as_bytes())?;
1510 assert_eq!(Value::Bool(false), result);
1511
1512 let expression = ".key BETWEEN 0 10";
1513 let ex = Parser::parse(expression)?;
1514 let result = ex.calculate("".as_bytes())?;
1515 assert_eq!(Value::Bool(false), result);
1516
1517 let expression = "0 BETWEEN .key 10";
1518 let ex = Parser::parse(expression)?;
1519 let result = ex.calculate("".as_bytes())?;
1520 assert_eq!(Value::Bool(false), result);
1521
1522 let expression = "10 BETWEEN 0 .key";
1523 let ex = Parser::parse(expression)?;
1524 let result = ex.calculate("".as_bytes())?;
1525 assert_eq!(Value::Bool(false), result);
1526
1527 let expression = r#""g" BETWEEN "a" "z""#;
1528 let ex = Parser::parse(expression)?;
1529 let result = ex.calculate("".as_bytes())?;
1530 assert_eq!(Value::Bool(true), result);
1531
1532 let expression = r#""z" BETWEEN "a" "z""#;
1533 let ex = Parser::parse(expression)?;
1534 let result = ex.calculate("".as_bytes())?;
1535 assert_eq!(Value::Bool(false), result);
1536
1537 let expression = r#"COERCE "2022-01-02" _datetime_ BETWEEN COERCE "2022-01-01" _datetime_ COERCE "2022-01-30" _datetime_"#;
1538 let ex = Parser::parse(expression)?;
1539 let result = ex.calculate("".as_bytes())?;
1540 assert_eq!(Value::Bool(true), result);
1541
1542 let expression = r#"COERCE "2022-01-01" _datetime_ BETWEEN COERCE "2022-01-01" _datetime_ COERCE "2022-01-30" _datetime_"#;
1543 let ex = Parser::parse(expression)?;
1544 let result = ex.calculate("".as_bytes())?;
1545 assert_eq!(Value::Bool(false), result);
1546
1547 Ok(())
1548 }
1549
1550 #[test]
1551 fn parse_exponent_number() -> anyhow::Result<()> {
1552 let expression = "1e3 == 1000";
1553 let ex = Parser::parse(expression)?;
1554 let result = ex.calculate("".as_bytes())?;
1555 assert_eq!(Value::Bool(true), result);
1556
1557 let expression = "-1e-3 == -0.001";
1558 let ex = Parser::parse(expression)?;
1559 let result = ex.calculate("".as_bytes())?;
1560 assert_eq!(Value::Bool(true), result);
1561
1562 let expression = "+1e-3 == 0.001";
1563 let ex = Parser::parse(expression)?;
1564 let result = ex.calculate("".as_bytes())?;
1565 assert_eq!(Value::Bool(true), result);
1566
1567 Ok(())
1568 }
1569
1570 #[test]
1571 fn parse_random_expressions() -> anyhow::Result<()> {
1572 let src = r#"{"AnnualRevenue":"2000000","NumberOfEmployees":"201","FirstName":"scott"}"#
1573 .as_bytes();
1574 let expression = r#".NumberOfEmployees > "200" && .AnnualRevenue == "2000000""#;
1575 let ex = Parser::parse(expression)?;
1576 let result = ex.calculate(src)?;
1577 assert_eq!(Value::Bool(true), result);
1578
1579 let expression = r#".AnnualRevenue >= "5000000" || (.NumberOfEmployees > "200" && .AnnualRevenue == "2000000")"#;
1580 let ex = Parser::parse(expression)?;
1581 let result = ex.calculate(src)?;
1582 assert_eq!(Value::Bool(true), result);
1583
1584 let expression = r#".AnnualRevenue >= "5000000" || (true && .AnnualRevenue == "2000000")"#;
1585 let ex = Parser::parse(expression)?;
1586 let result = ex.calculate(src)?;
1587 assert_eq!(Value::Bool(true), result);
1588
1589 let expression = r#".AnnualRevenue >= "5000000" || (.NumberOfEmployees > "200" && true)"#;
1590 let ex = Parser::parse(expression)?;
1591 let result = ex.calculate(src)?;
1592 assert_eq!(Value::Bool(true), result);
1593
1594 let expression = r#"true || (.NumberOfEmployees > "200" && .AnnualRevenue == "2000000")"#;
1595 let ex = Parser::parse(expression)?;
1596 let result = ex.calculate(src)?;
1597 assert_eq!(Value::Bool(true), result);
1598
1599 let expression = r#"false || (.NumberOfEmployees > "200" && .AnnualRevenue == "2000000")"#;
1600 let ex = Parser::parse(expression)?;
1601 let result = ex.calculate(src)?;
1602 assert_eq!(Value::Bool(true), result);
1603
1604 let expression = ".MyValue != NULL && .MyValue > 19";
1605 let ex = Parser::parse(expression)?;
1606 let result = ex.calculate(src)?;
1607 assert_eq!(Value::Bool(false), result);
1608
1609 Ok(())
1610 }
1611
1612 #[test]
1613 fn custom_coerce() -> anyhow::Result<()> {
1614 #[derive(Debug)]
1615 struct Star {
1616 expression: Box<dyn Expression>,
1617 }
1618
1619 impl Expression for Star {
1620 fn calculate(&self, json: &[u8]) -> Result<Value> {
1621 let inner = self.expression.calculate(json)?;
1622
1623 match inner {
1624 Value::String(s) => Ok(Value::String("*".repeat(s.len()))),
1625 value => Err(Error::UnsupportedCOERCE(format!(
1626 "cannot star value {value}"
1627 ))),
1628 }
1629 }
1630 }
1631
1632 {
1633 let mut hm = coercions().write().unwrap();
1634 hm.insert("_star_".to_string(), |_, const_eligible, expression| {
1635 Ok((const_eligible, Box::new(Star { expression })))
1636 });
1637 }
1638
1639 let expression = r#"COERCE "My Name" _star_"#;
1640 let ex = Parser::parse(expression)?;
1641 let result = ex.calculate("{}".as_bytes())?;
1642 assert_eq!(Value::String("*******".to_string()), result);
1643
1644 let expression = "COERCE 1234 _string_,_star_";
1645 let ex = Parser::parse(expression)?;
1646 let result = ex.calculate("{}".as_bytes())?;
1647 assert_eq!(Value::String("****".to_string()), result);
1648
1649 Ok(())
1650 }
1651
1652 #[test]
1653 fn coerce_substr() -> anyhow::Result<()> {
1654 let src = r#"{"name":"Joeybloggs"}"#.as_bytes();
1655 let expression = "COERCE .name _substr_[4:]";
1656 let ex = Parser::parse(expression)?;
1657 let result = ex.calculate(src)?;
1658 assert_eq!(r#""bloggs""#, format!("{result}"));
1659
1660 let src = r#"{"name":"Joeybloggs"}"#.as_bytes();
1661 let expression = "COERCE .name _substr_[:4]";
1662 let ex = Parser::parse(expression)?;
1663 let result = ex.calculate(src)?;
1664 assert_eq!(r#""Joey""#, format!("{result}"));
1665
1666 let src = r#"{"name":"Joeybloggs"}"#.as_bytes();
1667 let expression = "COERCE .name _substr_[3:5]";
1668 let ex = Parser::parse(expression)?;
1669 let result = ex.calculate(src)?;
1670 assert_eq!(r#""yb""#, format!("{result}"));
1671
1672 let src = "{}".as_bytes();
1674 let expression = r#"COERCE "Joeybloggs" _substr_[3:5]"#;
1675 let ex = Parser::parse(expression)?;
1676 let result = ex.calculate(src)?;
1677 assert_eq!(r#""yb""#, format!("{result}"));
1678
1679 let src = r#"{"name":"Joeybloggs"}"#.as_bytes();
1681 let expression = "COERCE .name _substr_[500:1000]";
1682 let ex = Parser::parse(expression)?;
1683 let result = ex.calculate(src)?;
1684 assert_eq!("null", format!("{result}"));
1685 Ok(())
1686 }
1687}