1use keelson_core::clause::{
2 Combines, Fetch, GroupBy, HasCombines, HasFetch, HasGroupBy, HasHaving, HasJoins, HasLimit,
3 HasLocks, HasOffset, HasOrderBy, HasSelectList, HasTableRef, HasWhere, HasWindows, HasWith,
4 Having, Join, Limit, Locks, Offset, OrderBy, SelectList, TableRef, Where, Windows, With,
5};
6use keelson_core::expr::{Expr, IntoExpr, IntoExprList};
7use keelson_core::{Dialect, Error, Expression, Mod, Query, QueryExtensions, QueryType, SqlWriter};
8
9use super::{HasExtraTables, write_from_list};
10use crate::Psql;
11use crate::extras::Distinct;
12
13#[derive(Debug, Clone, Default)]
47pub struct SelectQuery {
48 pub with: With,
50 pub distinct: Option<Distinct>,
52 pub select_list: SelectList,
54 pub from: TableRef,
56 pub extra_from: Vec<TableRef>,
58 pub where_: Where,
60 pub group_by: GroupBy,
62 pub having: Having,
64 pub windows: Windows,
66 pub order_by: OrderBy,
68 pub limit: Limit,
70 pub offset: Offset,
72 pub fetch: Fetch,
74 pub locks: Locks,
76 pub combines: Combines,
78}
79
80impl SelectQuery {
81 pub fn new() -> SelectQuery {
83 SelectQuery::default()
84 }
85
86 pub fn apply(&mut self, mods: impl Mod<SelectQuery>) {
88 mods.apply(self);
89 }
90
91 fn has_tail_clauses(&self) -> bool {
94 !self.order_by.is_empty()
95 || !self.limit.is_empty()
96 || !self.offset.is_empty()
97 || !self.fetch.is_empty()
98 || !self.locks.is_empty()
99 }
100}
101
102impl Expression for SelectQuery {
103 fn write_sql(&self, w: &mut SqlWriter<'_>) {
104 if !self.limit.is_empty() && !self.fetch.is_empty() {
110 w.record_error(Error::conflicting_clauses("LIMIT", "FETCH"));
111 return;
112 }
113
114 w.write_if(!self.with.is_empty(), "", &self.with, " ");
115
116 let parens = self
117 .combines
118 .parenthesises_leading_query(self.has_tail_clauses());
119 if parens {
120 w.push_str("(");
121 }
122
123 w.push_str("SELECT ");
124 if let Some(distinct) = &self.distinct {
125 w.write_expr(distinct);
126 w.push_str(" ");
127 }
128 w.write_expr(&self.select_list);
130
131 write_from_list(
132 w,
133 " FROM ",
134 &self.from,
135 &self.extra_from,
136 "the FROM item its joins attach to",
137 );
138
139 w.write_if(!self.where_.is_empty(), " ", &self.where_, "");
140 w.write_if(!self.group_by.is_empty(), " ", &self.group_by, "");
141 w.write_if(!self.having.is_empty(), " ", &self.having, "");
142 w.write_if(!self.windows.is_empty(), " ", &self.windows, "");
143 w.write_if(!self.order_by.is_empty(), " ", &self.order_by, "");
144 w.write_if(!self.limit.is_empty(), " ", &self.limit, "");
145 w.write_if(!self.offset.is_empty(), " ", &self.offset, "");
146 w.write_if(!self.fetch.is_empty(), " ", &self.fetch, "");
147 w.write_if(!self.locks.is_empty(), " ", &self.locks, "");
148
149 if parens {
150 w.push_str(")");
151 }
152
153 w.write_if(!self.combines.is_empty(), " ", &self.combines, "");
154 }
155}
156
157impl Query for SelectQuery {
158 fn query_type(&self) -> QueryType {
159 QueryType::Select
160 }
161
162 fn dialect(&self) -> &dyn Dialect {
163 &Psql
164 }
165}
166
167impl<H, L, M> QueryExtensions<H, L, M> for SelectQuery {}
168
169impl IntoExpr for SelectQuery {
170 fn into_expr(self) -> Expr {
171 crate::query(self)
172 }
173}
174
175impl IntoExprList for SelectQuery {
176 fn into_expr_list(self) -> Vec<Expr> {
177 vec![self.into_expr()]
178 }
179}
180
181impl HasWith for SelectQuery {
182 fn with_mut(&mut self) -> &mut With {
183 &mut self.with
184 }
185}
186
187impl HasSelectList for SelectQuery {
188 fn select_list_mut(&mut self) -> &mut SelectList {
189 &mut self.select_list
190 }
191}
192
193impl HasTableRef for SelectQuery {
194 fn table_ref_mut(&mut self) -> &mut TableRef {
195 &mut self.from
196 }
197}
198
199impl HasExtraTables for SelectQuery {
200 fn extra_tables_mut(&mut self) -> &mut Vec<TableRef> {
201 &mut self.extra_from
202 }
203}
204
205impl HasJoins for SelectQuery {
206 fn joins_mut(&mut self) -> &mut Vec<Join> {
207 &mut self.from.joins
208 }
209}
210
211impl HasWhere for SelectQuery {
212 fn where_mut(&mut self) -> &mut Where {
213 &mut self.where_
214 }
215}
216
217impl HasGroupBy for SelectQuery {
218 fn group_by_mut(&mut self) -> &mut GroupBy {
219 &mut self.group_by
220 }
221}
222
223impl HasHaving for SelectQuery {
224 fn having_mut(&mut self) -> &mut Having {
225 &mut self.having
226 }
227}
228
229impl HasWindows for SelectQuery {
230 fn windows_mut(&mut self) -> &mut Windows {
231 &mut self.windows
232 }
233}
234
235impl HasOrderBy for SelectQuery {
236 fn order_by_mut(&mut self) -> &mut OrderBy {
237 &mut self.order_by
238 }
239}
240
241impl HasLimit for SelectQuery {
242 fn limit_mut(&mut self) -> &mut Limit {
243 &mut self.limit
244 }
245}
246
247impl HasOffset for SelectQuery {
248 fn offset_mut(&mut self) -> &mut Offset {
249 &mut self.offset
250 }
251}
252
253impl HasFetch for SelectQuery {
254 fn fetch_mut(&mut self) -> &mut Fetch {
255 &mut self.fetch
256 }
257}
258
259impl HasLocks for SelectQuery {
260 fn locks_mut(&mut self) -> &mut Locks {
261 &mut self.locks
262 }
263}
264
265impl HasCombines for SelectQuery {
266 fn combines_mut(&mut self) -> &mut Combines {
267 &mut self.combines
268 }
269}