Skip to main content

partiql_eval/
test_value.rs

1use partiql_value::{EqualityValue, NullableEq, Value};
2
3use crate::eval::Evaluated;
4use partiql_extension_ion::decode::{IonDecoderBuilder, IonDecoderConfig};
5use partiql_extension_ion::Encoding;
6
7#[allow(dead_code)]
8#[derive(Debug, Ord, PartialOrd)]
9pub struct TestValue {
10    pub value: Value,
11}
12
13impl Eq for TestValue {}
14
15impl PartialEq for TestValue {
16    fn eq(&self, other: &Self) -> bool {
17        // When testing, we need NaN == NaN and NULL == NULL in order to assert test success properly
18        let wrap_value = EqualityValue::<'_, true, true, Value>;
19        NullableEq::eq(&wrap_value(&self.value), &wrap_value(&other.value)) == Value::Boolean(true)
20    }
21}
22
23impl From<Value> for TestValue {
24    fn from(value: Value) -> Self {
25        TestValue { value }
26    }
27}
28
29impl From<Evaluated> for TestValue {
30    fn from(value: Evaluated) -> Self {
31        value.result.into()
32    }
33}
34
35impl From<&str> for TestValue {
36    fn from(contents: &str) -> Self {
37        parse_test_value_str(contents).into()
38    }
39}
40
41fn parse_test_value_str(contents: &str) -> Value {
42    let reader = ion_rs_old::ReaderBuilder::new()
43        .build(contents)
44        .expect("reading contents");
45    let mut iter = IonDecoderBuilder::new(
46        IonDecoderConfig::default().with_mode(Encoding::PartiqlEncodedAsIon),
47    )
48    .build(reader)
49    .expect("building decoder");
50
51    let val = iter.next();
52
53    val.expect("test value to exist")
54        .expect("value decode to succeed")
55}
56
57#[cfg(test)]
58pub(crate) fn parse_partiql_value_str(contents: &str) -> Value {
59    use crate::env::basic::MapBindings;
60    use crate::eval::BasicContext;
61    use crate::plan::{EvaluationMode, EvaluatorPlanner};
62    use partiql_catalog::catalog::PartiqlCatalog;
63    use partiql_catalog::context::SystemContext;
64    use partiql_value::DateTime;
65    let catalog = PartiqlCatalog::default().to_shared_catalog();
66    let parsed = partiql_parser::Parser::default()
67        .parse(contents)
68        .expect("Expect successful parse");
69    let planner = partiql_logical_planner::LogicalPlanner::new(&catalog);
70    let logical = planner.lower(&parsed).expect("logical plan");
71    let evaluator = EvaluatorPlanner::new(EvaluationMode::Permissive, &catalog)
72        .compile(&logical)
73        .expect("Expect no plan error");
74    let sys = SystemContext {
75        now: DateTime::from_system_now_utc(),
76    };
77    let bindings = MapBindings::default();
78    let ctx = BasicContext::new(bindings, sys);
79    let value = evaluator.execute(&ctx).expect("evaluation to succeed");
80
81    value.result
82}
83
84#[cfg(test)]
85mod tests {
86    use super::parse_test_value_str;
87
88    use partiql_value::{bag, list, tuple, Value};
89
90    #[track_caller]
91    fn parse(test: &str, expected: Value) {
92        let val = parse_test_value_str(test);
93        assert_eq!(val, expected);
94    }
95
96    #[test]
97    fn simple() {
98        parse("null", Value::Null);
99        parse("$missing::null", Value::Missing);
100        parse("9", Value::Integer(9));
101        parse("true", Value::Boolean(true));
102        parse("false", Value::Boolean(false));
103        parse("\"str\"", Value::String(Box::new("str".into())));
104    }
105
106    #[test]
107    fn bag() {
108        let test = "$bag::[
109            {
110                f: 1,
111                d: 2e0,
112                s: 1
113            }
114        ]";
115        let expected = Value::from(bag![tuple![
116            ("f", 1),
117            ("d", Value::Real(2.0.into())),
118            ("s", 1)
119        ]]);
120        parse(test, expected);
121    }
122
123    #[test]
124    fn tuple() {
125        parse(
126            "{
127                    sensor: 1,
128                    reading: 42
129                  }",
130            Value::Tuple(Box::new(tuple![("sensor", 1), ("reading", 42)])),
131        );
132    }
133
134    #[test]
135    fn tt2() {
136        parse(
137            "{
138                    sensors: [
139                        {
140                            sensor: 1
141                        },
142                        {
143                            sensor: 2
144                        }
145                    ],
146                    logs: [
147                        {
148                            sensor: 1,
149                            co: 4d-1
150                        },
151                        {
152                            sensor: 1,
153                            co: 2d-1
154                        },
155                        {
156                            sensor: 2,
157                            co: 3d-1
158                        }
159                    ]
160                }",
161            Value::Tuple(Box::new(tuple![
162                (
163                    "sensors",
164                    list![tuple![("sensor", 1)], tuple![("sensor", 2)]]
165                ),
166                (
167                    "logs",
168                    list![
169                        tuple![("sensor", 1), ("co", rust_decimal::Decimal::new(4, 1))],
170                        tuple![("sensor", 1), ("co", rust_decimal::Decimal::new(2, 1))],
171                        tuple![("sensor", 2), ("co", rust_decimal::Decimal::new(3, 1))]
172                    ]
173                )
174            ])),
175        );
176    }
177
178    #[test]
179    fn list() {
180        let test = "[
181            {
182                f: 1,
183                d: 2e0,
184                s: 1
185            }
186        ]";
187        let expected = Value::from(list![tuple![
188            ("f", 1),
189            ("d", Value::Real(2.0.into())),
190            ("s", 1)
191        ]]);
192        parse(test, expected);
193    }
194}