cql3_parser/
select.rs

1use crate::common::{FQName, Identifier, OrderClause, RelationElement};
2use itertools::Itertools;
3use std::fmt::{Display, Formatter};
4
5/// data for select statements
6#[derive(PartialEq, Debug, Clone)]
7pub struct Select {
8    /// if true DISTINCT results
9    pub distinct: bool,
10    /// if true JSON reslts
11    pub json: bool,
12    /// The table name.
13    pub table_name: FQName,
14    /// the list of elements to select.
15    pub columns: Vec<SelectElement>,
16    /// the where clause
17    pub where_clause: Vec<RelationElement>,
18    /// the optional ordering
19    pub order: Option<OrderClause>,
20    /// the number of items to return
21    pub limit: Option<i32>,
22    /// if true ALLOW FILTERING is displayed
23    pub filtering: bool,
24}
25
26impl Select {
27    /// return the column names selected
28    /// does not return functions.
29    pub fn select_names(&self) -> Vec<String> {
30        self.columns
31            .iter()
32            .filter_map(|e| {
33                if let SelectElement::Column(named) = e {
34                    Some(named.to_string())
35                } else {
36                    None
37                }
38            })
39            .collect()
40    }
41
42    /// return the aliased column names.  If the column is not aliased the
43    /// base column name is returned.
44    /// does not return functions.
45    pub fn select_alias(&self) -> Vec<Identifier> {
46        self.columns
47            .iter()
48            .filter_map(|e| match e {
49                SelectElement::Column(named) => {
50                    Some(named.alias.clone().unwrap_or_else(|| named.name.clone()))
51                }
52                _ => None,
53            })
54            .collect()
55    }
56}
57
58impl Display for Select {
59    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
60        write!(
61            f,
62            "SELECT {}{}{} FROM {}{}{}{}{}",
63            if self.distinct { "DISTINCT " } else { "" },
64            if self.json { "JSON " } else { "" },
65            self.columns.iter().join(", "),
66            self.table_name,
67            if !self.where_clause.is_empty() {
68                format!(" WHERE {}", self.where_clause.iter().join(" AND "))
69            } else {
70                "".to_string()
71            },
72            self.order
73                .as_ref()
74                .map_or("".to_string(), |x| format!(" ORDER BY {}", x)),
75            self.limit
76                .map_or("".to_string(), |x| format!(" LIMIT {}", x)),
77            if self.filtering {
78                " ALLOW FILTERING"
79            } else {
80                ""
81            }
82        )
83    }
84}
85
86/// the selectable elements for a select statement
87#[derive(PartialEq, Debug, Clone)]
88pub enum SelectElement {
89    /// All of the columns
90    Star,
91    /// a named column.  May have an alias specified.
92    Column(Named),
93    /// a named column.  May have an alias specified.
94    Function(Named),
95}
96
97impl Display for SelectElement {
98    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
99        match self {
100            SelectElement::Star => write!(f, "*"),
101            SelectElement::Column(named) | SelectElement::Function(named) => write!(f, "{}", named),
102        }
103    }
104}
105
106#[derive(PartialEq, Debug, Clone)]
107pub struct Named {
108    pub name: Identifier,
109    pub alias: Option<Identifier>,
110}
111
112/// the name an optional alias for a named item.
113impl Named {
114    pub fn new(name: &str, alias: &str) -> Named {
115        Named {
116            name: Identifier::parse(name),
117            alias: Some(Identifier::parse(alias)),
118        }
119    }
120
121    pub fn simple(name: &str) -> Named {
122        Named {
123            name: Identifier::parse(name),
124            alias: None,
125        }
126    }
127
128    pub fn alias_or_name(&self) -> &Identifier {
129        match &self.alias {
130            None => &self.name,
131            Some(alias) => alias,
132        }
133    }
134}
135
136impl Display for Named {
137    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
138        match &self.alias {
139            None => write!(f, "{}", self.name),
140            Some(a) => write!(f, "{} AS {}", self.name, a),
141        }
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use crate::select::{Named, SelectElement};
148
149    #[test]
150    fn test_select_element_display() {
151        assert_eq!("*", SelectElement::Star.to_string());
152        assert_eq!(
153            "col",
154            SelectElement::Column(Named::simple("col")).to_string()
155        );
156        assert_eq!(
157            "func",
158            SelectElement::Function(Named::simple("func")).to_string()
159        );
160        assert_eq!(
161            "col AS alias",
162            SelectElement::Column(Named::new("col", "alias")).to_string()
163        );
164        assert_eq!(
165            "func AS alias",
166            SelectElement::Function(Named::new("func", "alias")).to_string()
167        );
168    }
169}