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 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 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 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 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}