Skip to main content

openpql_pql_parser/ast/
stmt.rs

1use super::{Error, Expr, FromClause, FxHashSet, ResultE, Selector, user_err};
2
3/// A single `select ... from ... [where ...]` statement.
4#[derive(PartialEq, Debug)]
5pub struct Stmt<'i> {
6    /// Aggregate selectors in the `select` list.
7    pub selectors: Vec<Selector<'i>>,
8    /// `from` clause.
9    pub from: FromClause<'i>,
10    /// Optional `where` predicate.
11    pub where_clause: Option<Expr<'i>>,
12}
13
14fn ensure_uniq_names<'i>(selectors: &[Selector]) -> ResultE<'i, ()> {
15    let mut used = FxHashSet::default();
16
17    for selector in selectors {
18        if let Some(id) = &selector.alias
19            && !used.insert(id.inner.to_ascii_lowercase())
20        {
21            return Err(user_err(Error::DuplicatedSelectorName(id.loc)));
22        }
23    }
24
25    Ok(())
26}
27
28impl<'i> Stmt<'i> {
29    /// Builds a statement, rejecting duplicate selector aliases.
30    pub fn new(
31        selectors: Vec<Selector<'i>>,
32        from: FromClause<'i>,
33        where_clause: Option<Expr<'i>>,
34    ) -> ResultE<'i, Self> {
35        ensure_uniq_names(&selectors)?;
36
37        Ok(Self {
38            selectors,
39            from,
40            where_clause,
41        })
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use crate::*;
49
50    fn s(s: &str) -> Stmt<'_> {
51        parser::StmtParser::new().parse(s).unwrap()
52    }
53
54    fn e(s: &str) -> Error {
55        parser::StmtParser::new().parse(s).unwrap_err().into()
56    }
57
58    #[test]
59    fn test_stmt() {
60        assert_eq!(s("select avg(_)  from _=''").selectors.len(), 1);
61        assert_eq!(s("select avg(_), from _=''").selectors.len(), 1);
62
63        assert_eq!(
64            s("select avg(_) as s1 from _=''").selectors[0].alias,
65            Some(("s1", (17, 19)).into())
66        );
67
68        assert_eq!(
69            e("select avg(_) as s1, avg(_) as s1 from _=''"),
70            Error::DuplicatedSelectorName((31, 33))
71        );
72    }
73
74    #[test]
75    fn test_stmt_where_absent() {
76        let stmt = s("select count(_) from _=''");
77        assert!(stmt.where_clause.is_none());
78    }
79
80    #[test]
81    fn test_stmt_where_present() {
82        let stmt = s("select count(_) from _='' where 1 = 1");
83        assert!(stmt.where_clause.is_some());
84    }
85
86    #[test]
87    fn test_stmt_where_logical() {
88        let _ = s("select count(_) from _='' where 1 = 1 and 2 = 2");
89        let _ = s("select count(_) from _='' where 1 = 1 or 2 = 2");
90        let _ = s("select count(_) from _='' where not 1 = 2");
91        let _ = s("select count(_) from _='' where not 1 = 2 and 1 = 1");
92    }
93}