Skip to main content

partiql_eval/
env.rs

1use partiql_catalog::context::Bindings;
2use partiql_value::{BindingsName, Tuple, Value};
3use std::fmt::Debug;
4use unicase::UniCase;
5
6pub mod basic {
7    use super::{Bindings, BindingsName, Debug, Tuple, UniCase, Value};
8    use partiql_value::datum::{RefFieldView, RefTupleView};
9    use std::borrow::Cow;
10
11    use rustc_hash::FxHashMap;
12
13    #[derive(Debug, Clone)]
14    pub struct MapBindings<T> {
15        sensitive: FxHashMap<String, usize>,
16        insensitive: FxHashMap<UniCase<String>, usize>,
17        values: Vec<T>,
18    }
19
20    impl<T> Default for MapBindings<T> {
21        fn default() -> Self {
22            MapBindings {
23                sensitive: FxHashMap::default(),
24                insensitive: FxHashMap::default(),
25                values: vec![],
26            }
27        }
28    }
29
30    impl<T> MapBindings<T> {
31        pub fn insert(&mut self, name: &str, value: T) {
32            if let std::collections::hash_map::Entry::Vacant(e) =
33                self.insensitive.entry(UniCase::new(name.to_string()))
34            {
35                let idx = self.values.len();
36                self.values.push(value);
37                self.sensitive.insert(name.to_string(), idx);
38                e.insert(idx);
39            } else {
40                panic!("Cannot insert duplicate binding of name {name}")
41            }
42        }
43    }
44
45    impl<T> Bindings<T> for MapBindings<T>
46    where
47        T: Clone + Debug,
48    {
49        #[inline]
50        fn get<'a>(&'a self, name: &BindingsName<'_>) -> Option<Cow<'a, T>> {
51            let idx = match name {
52                BindingsName::CaseSensitive(s) => self.sensitive.get(s.as_ref()),
53                BindingsName::CaseInsensitive(s) => {
54                    self.insensitive.get(&UniCase::new(s.to_string()))
55                }
56            };
57            idx.and_then(|idx| self.values.get(*idx).map(Cow::Borrowed))
58        }
59    }
60
61    impl<'a> From<&'a dyn RefTupleView<'a, Value>> for MapBindings<Value> {
62        fn from(value: &'a dyn RefTupleView<'a, Value>) -> Self {
63            let mut bindings = MapBindings::default();
64            for RefFieldView { name, value } in value.tuple_fields_iter() {
65                bindings.insert(name.unwrap_or("_1"), value.into_owned());
66            }
67            bindings
68        }
69    }
70
71    impl From<&Tuple> for MapBindings<Value> {
72        fn from(t: &Tuple) -> Self {
73            let mut bindings = MapBindings::default();
74            for (k, v) in t.pairs() {
75                bindings.insert(k, v.clone());
76            }
77            bindings
78        }
79    }
80
81    impl From<Tuple> for MapBindings<Value> {
82        fn from(t: Tuple) -> Self {
83            let mut bindings = MapBindings::default();
84            for (k, v) in t.into_pairs() {
85                bindings.insert(&k, v);
86            }
87            bindings
88        }
89    }
90
91    impl From<Value> for MapBindings<Value> {
92        fn from(val: Value) -> Self {
93            match val {
94                Value::Null => MapBindings::default(),
95                Value::Missing => MapBindings::default(),
96                Value::Tuple(t) => (*t).into(),
97                _ => todo!(),
98            }
99        }
100    }
101
102    impl From<&Value> for MapBindings<Value> {
103        fn from(val: &Value) -> Self {
104            match val {
105                Value::Null => MapBindings::default(),
106                Value::Missing => MapBindings::default(),
107                Value::Tuple(t) => t.as_ref().into(),
108                _ => todo!(),
109            }
110        }
111    }
112
113    #[derive(Debug)]
114    pub struct NestedBindings<'a, T>
115    where
116        T: Debug,
117    {
118        bindings: MapBindings<T>,
119        parent: &'a dyn Bindings<T>,
120    }
121
122    impl<'a, T> NestedBindings<'a, T>
123    where
124        T: Debug,
125    {
126        pub fn new(bindings: MapBindings<T>, parent: &'a dyn Bindings<T>) -> Self {
127            Self { bindings, parent }
128        }
129    }
130
131    impl<'b, T> Bindings<T> for NestedBindings<'b, T>
132    where
133        T: Clone + Debug + 'b,
134    {
135        fn get<'a>(&'a self, name: &BindingsName<'_>) -> Option<Cow<'a, T>> {
136            match self.bindings.get(name) {
137                Some(v) => Some(v),
138                None => self.parent.get(name),
139            }
140        }
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147    use crate::env::basic::MapBindings;
148    use partiql_value::tuple;
149
150    #[test]
151    fn test_bindings_from_tuple() {
152        let t = tuple![("a", tuple![("p", 1)]), ("b", 2)];
153
154        // by ref
155        let bindings = MapBindings::from(&t);
156        assert_eq!(
157            bindings
158                .get(&BindingsName::CaseInsensitive("a".to_string().into()))
159                .as_ref()
160                .map(AsRef::as_ref),
161            Some(&Value::from(tuple![("p", 1)]))
162        );
163        assert_eq!(
164            bindings
165                .get(&BindingsName::CaseInsensitive("b".to_string().into()))
166                .as_ref()
167                .map(AsRef::as_ref),
168            Some(&Value::from(2))
169        );
170
171        // by ownership
172        let bindings = MapBindings::from(t);
173        assert_eq!(
174            bindings
175                .get(&BindingsName::CaseInsensitive("a".to_string().into()))
176                .as_ref()
177                .map(AsRef::as_ref),
178            Some(&Value::from(tuple![("p", 1)]))
179        );
180        assert_eq!(
181            bindings
182                .get(&BindingsName::CaseInsensitive("b".to_string().into()))
183                .as_ref()
184                .map(AsRef::as_ref),
185            Some(&Value::from(2))
186        );
187    }
188
189    #[test]
190    fn test_bindings_from_value() {
191        let bindings = MapBindings::from(Value::Null);
192        assert_eq!(
193            bindings.get(&BindingsName::CaseInsensitive("a".to_string().into())),
194            None
195        );
196        let bindings = MapBindings::from(&Value::Null);
197        assert_eq!(
198            bindings.get(&BindingsName::CaseInsensitive("a".to_string().into())),
199            None
200        );
201        let bindings = MapBindings::from(Value::Missing);
202        assert_eq!(
203            bindings.get(&BindingsName::CaseInsensitive("a".to_string().into())),
204            None
205        );
206        let bindings = MapBindings::from(&Value::Missing);
207        assert_eq!(
208            bindings.get(&BindingsName::CaseInsensitive("a".to_string().into())),
209            None
210        );
211
212        let t = Value::from(tuple![("a", tuple![("p", 1)]), ("b", 2)]);
213
214        // by ref
215        let bindings = MapBindings::from(&t);
216        assert_eq!(
217            bindings
218                .get(&BindingsName::CaseInsensitive("a".to_string().into()))
219                .as_ref()
220                .map(AsRef::as_ref),
221            Some(&Value::from(tuple![("p", 1)]))
222        );
223        assert_eq!(
224            bindings
225                .get(&BindingsName::CaseInsensitive("b".to_string().into()))
226                .as_ref()
227                .map(AsRef::as_ref),
228            Some(&Value::from(2))
229        );
230
231        // by ownership
232        let bindings = MapBindings::from(t);
233        assert_eq!(
234            bindings
235                .get(&BindingsName::CaseInsensitive("a".to_string().into()))
236                .as_ref()
237                .map(AsRef::as_ref),
238            Some(&Value::from(tuple![("p", 1)]))
239        );
240        assert_eq!(
241            bindings
242                .get(&BindingsName::CaseInsensitive("b".to_string().into()))
243                .as_ref()
244                .map(AsRef::as_ref),
245            Some(&Value::from(2))
246        );
247    }
248
249    #[test]
250    #[should_panic]
251    fn test_bindings_insert_panics_same_string() {
252        let mut bindings = MapBindings::default();
253        bindings.insert("foo", Value::from(1));
254        bindings.insert("foo", Value::from(2));
255    }
256
257    #[test]
258    #[should_panic]
259    fn test_bindings_insert_panics_case_insensitive_string() {
260        let mut bindings = MapBindings::default();
261        bindings.insert("foo", Value::from(1));
262        bindings.insert("FOO", Value::from(2));
263    }
264}