1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#![deny(rust_2018_idioms)]
#![deny(clippy::all)]

mod subquery_tests;

#[cfg(test)]
mod tests {
    use partiql_ast_passes::error::AstTransformationError;
    use partiql_catalog::context::SystemContext;
    use partiql_catalog::{Catalog, PartiqlCatalog};
    use partiql_eval as eval;
    use partiql_eval::env::basic::MapBindings;
    use partiql_eval::error::{EvalErr, PlanErr};
    use partiql_eval::eval::{BasicContext, EvalPlan, EvalResult, Evaluated};
    use partiql_eval::plan::EvaluationMode;
    use partiql_logical as logical;
    use partiql_parser::{Parsed, ParserError, ParserResult};
    use partiql_value::{DateTime, Value};
    use thiserror::Error;

    #[derive(Error, Debug)]
    enum TestError<'a> {
        #[error("Parse error: {0:?}")]
        Parse(ParserError<'a>),
        #[error("Lower error: {0:?}")]
        Lower(AstTransformationError),
        #[error("Plan error: {0:?}")]
        Plan(PlanErr),
        #[error("Evaluation error: {0:?}")]
        Eval(EvalErr),
    }

    impl<'a> From<ParserError<'a>> for TestError<'a> {
        fn from(err: ParserError<'a>) -> Self {
            TestError::Parse(err)
        }
    }

    impl From<AstTransformationError> for TestError<'_> {
        fn from(err: AstTransformationError) -> Self {
            TestError::Lower(err)
        }
    }

    impl From<PlanErr> for TestError<'_> {
        fn from(err: PlanErr) -> Self {
            TestError::Plan(err)
        }
    }

    impl From<EvalErr> for TestError<'_> {
        fn from(err: EvalErr) -> Self {
            TestError::Eval(err)
        }
    }

    #[track_caller]
    #[inline]
    fn parse(statement: &str) -> ParserResult<'_> {
        partiql_parser::Parser::default().parse(statement)
    }

    #[track_caller]
    #[inline]
    fn lower(
        catalog: &dyn Catalog,
        parsed: &Parsed<'_>,
    ) -> Result<logical::LogicalPlan<logical::BindingsOp>, AstTransformationError> {
        let planner = partiql_logical_planner::LogicalPlanner::new(catalog);
        planner.lower(parsed)
    }

    #[track_caller]
    #[inline]
    fn compile(
        mode: EvaluationMode,
        catalog: &dyn Catalog,
        logical: logical::LogicalPlan<logical::BindingsOp>,
    ) -> Result<EvalPlan, PlanErr> {
        let mut planner = eval::plan::EvaluatorPlanner::new(mode, catalog);
        planner.compile(&logical)
    }

    #[track_caller]
    #[inline]
    fn evaluate(mut plan: EvalPlan, bindings: MapBindings<Value>) -> EvalResult {
        let sys = SystemContext {
            now: DateTime::from_system_now_utc(),
        };
        let ctx = BasicContext::new(bindings, sys);
        plan.execute_mut(&ctx)
    }

    #[track_caller]
    #[inline]
    fn eval(statement: &str, mode: EvaluationMode) -> Result<Evaluated, TestError<'_>> {
        let catalog = PartiqlCatalog::default();

        let parsed = parse(statement)?;
        let lowered = lower(&catalog, &parsed)?;
        let bindings = Default::default();
        let plan = compile(mode, &catalog, lowered)?;
        Ok(evaluate(plan, bindings)?)
    }

    #[test]
    fn order_by_count() {
        let query = "select foo, count(1) as n from
            <<
                { 'foo': 'foo' },
                { 'foo': 'bar' },
                { 'foo': 'qux' },
                { 'foo': 'bar' },
                { 'foo': 'baz' },
                { 'foo': 'bar' },
                { 'foo': 'baz' }
            >>  group by foo order by n desc";

        let res = eval(query, EvaluationMode::Permissive);
        assert!(res.is_ok());
    }
}