piqel/sql/
selector.rs

1use std::collections::VecDeque;
2use std::str::FromStr;
3
4use crate::parser;
5use crate::sql::Env;
6use crate::sql::Expr;
7use crate::value::PqlValue;
8
9#[derive(Debug, Clone, PartialEq)]
10pub enum SelectorNode {
11    String(String),
12    Number(i64),
13}
14
15impl Default for SelectorNode {
16    fn default() -> Self {
17        Self::String(String::default())
18    }
19}
20
21impl From<&str> for SelectorNode {
22    fn from(s: &str) -> Self {
23        Self::String(s.to_string())
24    }
25}
26
27impl From<i64> for SelectorNode {
28    fn from(i: i64) -> Self {
29        Self::Number(i)
30    }
31}
32
33impl From<SelectorNode> for String {
34    fn from(node: SelectorNode) -> Self {
35        match node {
36            SelectorNode::String(s) => s,
37            SelectorNode::Number(i) => format!("{}", i),
38        }
39    }
40}
41
42impl SelectorNode {
43    pub fn to_string(&self) -> String {
44        String::from(self.to_owned())
45    }
46}
47
48#[derive(Debug, Default, Clone, PartialEq)]
49pub struct Selector {
50    pub data: VecDeque<SelectorNode>,
51}
52
53impl FromStr for Selector {
54    type Err = anyhow::Error;
55
56    fn from_str(s: &str) -> anyhow::Result<Self> {
57        match parser::expressions::parse_selector(s) {
58            Ok((_, r)) => Ok(r),
59            Err(_err) => anyhow::bail!("failed"),
60        }
61    }
62}
63
64impl From<&[&str]> for Selector {
65    fn from(ss: &[&str]) -> Self {
66        let data = ss
67            .iter()
68            .map(|s| SelectorNode::String(s.to_string()))
69            .collect::<VecDeque<_>>();
70        Self { data }
71    }
72}
73
74impl From<&[String]> for Selector {
75    fn from(ss: &[String]) -> Self {
76        let data = ss
77            .iter()
78            .map(|s| SelectorNode::String(s.to_string()))
79            .collect::<VecDeque<_>>();
80        Self { data }
81    }
82}
83
84impl From<&str> for Selector {
85    fn from(s: &str) -> Self {
86        let data = s
87            .to_string()
88            .split(".")
89            .map(|s| SelectorNode::String(s.to_string()))
90            .collect::<VecDeque<_>>();
91        Self { data }
92    }
93}
94
95impl From<&SelectorNode> for Selector {
96    fn from(node: &SelectorNode) -> Self {
97        Self {
98            data: vec![node]
99                .into_iter()
100                .map(|n| n.to_owned())
101                .collect::<VecDeque<_>>(),
102        }
103    }
104}
105impl From<&[SelectorNode]> for Selector {
106    fn from(nodes: &[SelectorNode]) -> Self {
107        Self {
108            data: nodes
109                .into_iter()
110                .map(|n| n.to_owned())
111                .collect::<VecDeque<_>>(),
112        }
113    }
114}
115
116impl Selector {
117    pub fn len(&self) -> usize {
118        self.data.len()
119    }
120
121    pub fn get(&self, ith: usize) -> Option<SelectorNode> {
122        self.data.get(ith).map(|e| e.to_owned())
123    }
124
125    pub fn last(&self) -> Option<String> {
126        if let Some(last) = self.to_vec().last() {
127            Some(last.to_string())
128        } else {
129            None
130        }
131    }
132
133    pub fn split_first(&self) -> Option<(SelectorNode, Self)> {
134        let mut data = self.data.to_owned();
135
136        if let Some(first) = data.pop_front() {
137            Some((first, Self { data }))
138        } else {
139            None
140        }
141    }
142
143    pub fn split_last(&self) -> Option<(Self, SelectorNode)> {
144        let mut data = self.data.to_owned();
145
146        if let Some(last) = data.pop_back() {
147            Some((Self { data }, last))
148        } else {
149            None
150        }
151    }
152
153    pub fn to_string(&self) -> String {
154        self.data
155            .clone()
156            .into_iter()
157            .map(|node| node.to_string())
158            .collect::<Vec<String>>()
159            .join(".")
160    }
161
162    pub fn to_vec(&self) -> Vec<SelectorNode> {
163        self.data.clone().into_iter().collect::<Vec<SelectorNode>>()
164    }
165
166    pub fn expand_fullpath(&self, env: &Env) -> Self {
167        if let Some((head, tail)) = self.split_first() {
168            let mut selector = Selector::default();
169
170            selector.data.append(
171                &mut env
172                    .expand_fullpath_as_selector(&Selector::from(vec![head].as_slice()))
173                    .data,
174            );
175            selector.data.append(&mut tail.data.to_owned());
176            selector
177        } else {
178            todo!()
179        }
180    }
181
182    pub fn expand_fullpath2(&self, env: &Env) -> Self {
183        env.expand_fullpath_as_selector(&self)
184    }
185
186    pub fn expand_abspath(&self, env: &Env) -> Self {
187        if let Some((head, tail)) = self.split_first() {
188            let mut selector = Selector::default();
189            if head != SelectorNode::default() {
190                selector.data.push_front(SelectorNode::default());
191            }
192
193            selector.data.append(
194                &mut env
195                    .expand_fullpath_as_selector(&Selector::from(vec![head].as_slice()))
196                    .data,
197            );
198            selector.data.append(&mut tail.data.to_owned());
199            selector
200        } else {
201            todo!()
202        }
203    }
204
205    pub fn evaluate(&self, env: &Env) -> Option<PqlValue> {
206        if let Some((head, tail)) = self.expand_fullpath(&env).split_first() {
207            if let Some(expr) = env.get(head.to_string().as_str()) {
208                match expr {
209                    Expr::Value(value) => {
210                        let v = if tail.data.len() > 0 {
211                            value.select_by_selector(&tail)
212                        } else {
213                            Some(value)
214                        };
215                        v
216                    }
217                    Expr::Selector(selector) => {
218                        let s = selector.expand_fullpath(&env);
219                        s.evaluate(&env)
220                    }
221                    Expr::Star => todo!(),
222                    Expr::Func(_) => todo!(),
223                    Expr::Add(_, _) => todo!(),
224                    Expr::Sub(_, _) => todo!(),
225                    Expr::Mul(_, _) => todo!(),
226                    Expr::Div(_, _) => todo!(),
227                    Expr::Rem(_, _) => todo!(),
228                    Expr::Exp(_, _) => todo!(),
229                    Expr::Sql(_) => todo!(),
230                }
231            } else {
232                self.expand_abspath(&env).evaluate(&env)
233            }
234        } else {
235            unreachable!()
236        }
237    }
238
239    pub fn intersect(&self, other: &Selector) -> Selector {
240        let mut res = Selector::default();
241
242        for (a, b) in self.data.iter().zip(other.data.iter()) {
243            if a == b {
244                res.data.push_back(a.to_owned())
245            } else {
246                break;
247            }
248        }
249
250        res
251    }
252}
253
254#[cfg(test)]
255mod tests {
256    use std::str::FromStr;
257
258    use crate::planner::Drain;
259
260    use crate::sql::Env;
261    use crate::sql::Expr;
262    use crate::sql::Field;
263    use crate::sql::Selector;
264    use crate::value::PqlValue;
265
266    fn get_data() -> anyhow::Result<PqlValue> {
267        PqlValue::from_str(
268            r#"
269{
270  'hr': {
271      'employeesNest': <<
272         {
273          'id': 3,
274          'name': 'Bob Smith',
275          'title': null,
276          'projects': [ { 'name': 'AWS Redshift Spectrum querying' },
277                        { 'name': 'AWS Redshift security' },
278                        { 'name': 'AWS Aurora security' }
279                      ]
280          },
281          {
282              'id': 4,
283              'name': 'Susan Smith',
284              'title': 'Dev Mgr',
285              'projects': []
286          },
287          {
288              'id': 6,
289              'name': 'Jane Smith',
290              'title': 'Software Eng 2',
291              'projects': [ { 'name': 'AWS Redshift security' } ]
292          }
293      >>
294    }
295}
296    "#,
297        )
298    }
299
300    #[test]
301    fn test_eval_selector_fullpath() -> anyhow::Result<()> {
302        let env = {
303            let mut env = Env::default();
304            let data = get_data()?;
305            env.insert("", &Expr::Value(data));
306            env
307        };
308
309        let selector = Selector::from_str(".hr.employeesNest.name")?;
310
311        assert_eq!(
312            selector.evaluate(&env),
313            Some(PqlValue::from_str(
314                r#"
315[
316  "Bob Smith",
317  "Susan Smith",
318  "Jane Smith"
319]
320"#
321            )?)
322        );
323        Ok(())
324    }
325
326    #[test]
327    fn test_eval_selector_aliaspath() -> anyhow::Result<()> {
328        let env = {
329            let mut env = Env::default();
330            let data = get_data()?;
331            env.insert("", &Expr::Value(data));
332            let drain = Drain(vec![
333                Field::from_str(r#"hr.employeesNest AS e"#)?,
334                Field::from_str(r#"e.projects AS p"#)?,
335            ]);
336            drain.execute(&mut env);
337            env
338        };
339
340        let selector = Selector::from_str("e.projects")?;
341        assert_eq!(
342            selector.evaluate(&env),
343            Some(PqlValue::from_str(
344                r#"
345[
346  [
347    {
348      "name": "AWS Redshift Spectrum querying"
349    },
350    {
351      "name": "AWS Redshift security"
352    },
353    {
354      "name": "AWS Aurora security"
355    }
356  ],
357  [],
358  [
359    {
360      "name": "AWS Redshift security"
361    }
362  ]
363]
364"#
365            )?)
366        );
367        Ok(())
368    }
369
370    #[test]
371    fn test_eval_selector_aliaspath2() -> anyhow::Result<()> {
372        let env = {
373            let mut env = Env::default();
374            let data = get_data()?;
375            env.insert("", &Expr::Value(data));
376            let drain = Drain(vec![
377                Field::from_str(r#"hr.employeesNest AS e"#)?,
378                Field::from_str(r#"e.projects AS p"#)?,
379            ]);
380            drain.execute(&mut env);
381            env
382        };
383
384        let selector = Selector::from_str("p")?;
385        assert_eq!(
386            selector.evaluate(&env),
387            Some(PqlValue::from_str(
388                r#"
389    [
390      [
391        {
392          "name": "AWS Redshift Spectrum querying"
393        },
394        {
395          "name": "AWS Redshift security"
396        },
397        {
398          "name": "AWS Aurora security"
399        }
400      ],
401      [],
402      [
403        {
404          "name": "AWS Redshift security"
405        }
406      ]
407    ]
408    "#
409            )?)
410        );
411        Ok(())
412    }
413
414    #[test]
415    fn test_eval_selector_num() -> anyhow::Result<()> {
416        let env = {
417            let mut env = Env::default();
418            let data = get_data()?;
419            env.insert("", &Expr::Value(data));
420            let drain = Drain(vec![Field::from_str(r#"3 AS n"#)?]);
421            drain.execute(&mut env);
422            env
423        };
424
425        let selector = Selector::from_str("n")?;
426        assert_eq!(selector.evaluate(&env), Some(PqlValue::from_str("3")?));
427        Ok(())
428    }
429
430    #[test]
431    fn test_calculate_common_path() -> anyhow::Result<()> {
432        let abc = Selector::from("a.b.c");
433        let abd = Selector::from("a.b.d");
434
435        let res = abc.intersect(&abd);
436
437        assert_eq!(res, Selector::from("a.b"));
438
439        Ok(())
440    }
441}