1use crate::common::{FQName, Identifier, OrderClause, RelationElement};
2use itertools::Itertools;
3use std::fmt::{Display, Formatter};
4
5#[derive(PartialEq, Debug, Clone)]
7pub struct Select {
8 pub distinct: bool,
10 pub json: bool,
12 pub table_name: FQName,
14 pub columns: Vec<SelectElement>,
16 pub where_clause: Vec<RelationElement>,
18 pub order: Option<OrderClause>,
20 pub limit: Option<i32>,
22 pub filtering: bool,
24}
25
26impl Select {
27 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 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#[derive(PartialEq, Debug, Clone)]
88pub enum SelectElement {
89 Star,
91 Column(Named),
93 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
112impl 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}