Skip to main content

ksql/parser/
parse.rs

1//! Parser is used to parse an expression for use against JSON data.
2//!
3//! ```rust
4//! use ksql::parser::{Parser, Value};
5//! use std::error::Error;
6//!
7//! fn main() -> Result<(), Box<dyn Error>>{
8//!     let src = r#"{"name":"MyCompany", "properties":{"employees": 50}"#.as_bytes();
9//!     let ex = Parser::parse(".properties.employees > 20")?;
10//!     let result = ex.calculate(src)?;
11//!     assert_eq!(Value::Bool(true), result);
12//!     Ok(())
13//! }
14//! ```
15//!
16
17use 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
36/// Represents a Custom Coercion function.
37/// It accepts if the previous value being parsed during the coercion is constant eligible
38/// eg. a String to a `DateTime` and the previous expression.
39///
40/// It returns if the coercion is still constant eligible and the new boxed expression.
41pub type CustomCoercion = fn(
42    tokenizer: &mut Parser,
43    const_eligible: bool,
44    expression: BoxedExpression,
45) -> anyhow::Result<(bool, BoxedExpression)>;
46
47/// Returns a `HasMap` of all coercions guarded by a Mutex for use allowing registration,
48/// removal or even replacing of existing coercions.
49#[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                // get substring info, expect the format to be _substr_[start:end]
142
143                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/// Represents the calculated Expression result.
279#[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>), // What to put here arg! do we preserve the original zone etc..?
287    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
329/// Represents a stateless parsed expression that can be applied to JSON data.
330pub trait Expression: Debug + Send + Sync {
331    /// Will execute the parsed expression and apply it against the supplied json data.
332    ///
333    /// # Warnings
334    ///
335    /// This function assumes that the supplied JSON data is valid.
336    ///
337    /// # Errors
338    ///
339    /// Will return `Err` if the expression cannot be applied to the supplied data due to invalid
340    /// data type comparisons.
341    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        // Defer the method call to the inner T
347        (**self).calculate(json)
348    }
349}
350
351/// Is an alias for a Box<dyn Expression>
352pub(in crate::parser) type BoxedExpression = Box<dyn Expression>;
353
354/// Parses a supplied expression and returns a `BoxedExpression`.
355pub 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    /// parses the provided expression and turning it into a computation that can be applied to some
366    /// source data.
367    ///
368    /// # Errors
369    ///
370    /// Will return `Err` the expression is invalid.
371    #[inline]
372    pub fn parse(expression: &str) -> anyhow::Result<BoxedExpression> {
373        Parser::parse_bytes(expression.as_bytes())
374    }
375
376    /// parses the provided expression as bytes and turning it into a computation that can be applied to some
377    /// source data.
378    ///
379    /// # Errors
380    ///
381    /// Will return `Err` the expression is invalid.
382    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                        // CloseParen is the end of an expression block, return parsed expression.
403                        if token.kind == TokenKind::CloseParen {
404                            return Ok(Some(expression));
405                        }
406                        // look for next operation
407                        current = self.parse_operation(token, expression)?;
408                    }
409                    _ => {
410                        // look for next value
411                        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 => {} // optional for defining arrays
435                            _ => {
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                // COERCE <expression> _<datatype>_
481                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(); // consume peeked comma
524                        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
721/// Result type for the `parse` function.
722pub type Result<T> = std::result::Result<T, Error>;
723
724/// Error type for the expression parser.
725#[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        // const eligible
1673        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        // if indexes beyond string value:
1680        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}