1use std::marker::PhantomData;
2
3use crate::compile::{CompiledSql, SqlBuilder, ToSql};
4use crate::expr::{Expr, ExprNode, IntoExpr};
5use crate::load::{ApplyLoad, LoadChain, NoLoad};
6use crate::rel::RelationInfo;
7use crate::schema::{ColumnRef, Table};
8
9#[derive(Debug, Clone, Copy)]
10pub enum JoinKind {
11 Inner,
12 Left,
13}
14
15#[derive(Debug, Clone)]
16pub struct Join {
17 pub table: Table,
18 pub on: Expr<bool>,
19 pub kind: JoinKind,
20}
21
22#[derive(Debug, Clone)]
23pub struct SelectItem {
24 pub expr: ExprNode,
25 pub alias: Option<String>,
26}
27
28#[derive(Debug, Clone, Copy)]
29pub enum OrderDirection {
30 Asc,
31 Desc,
32}
33
34#[derive(Debug, Clone)]
35pub enum OrderExpr {
36 Expr(ExprNode),
37 Alias(String),
38}
39
40pub trait IntoOrderExpr {
41 fn into_order_expr(self) -> OrderExpr;
42}
43
44impl IntoOrderExpr for ColumnRef {
45 fn into_order_expr(self) -> OrderExpr {
46 OrderExpr::Expr(ExprNode::Column(self))
47 }
48}
49
50impl<M, T> IntoOrderExpr for crate::schema::Column<M, T> {
51 fn into_order_expr(self) -> OrderExpr {
52 OrderExpr::Expr(ExprNode::Column(self.as_ref()))
53 }
54}
55
56impl<T> IntoOrderExpr for Expr<T> {
57 fn into_order_expr(self) -> OrderExpr {
58 OrderExpr::Expr(self.node)
59 }
60}
61
62#[derive(Debug, Clone)]
63pub struct Order {
64 pub expr: OrderExpr,
65 pub direction: OrderDirection,
66}
67
68#[derive(Debug, Clone)]
69pub struct Select<Out, Loads = NoLoad> {
70 table: Table,
71 columns: Option<Vec<SelectItem>>,
72 joins: Vec<Join>,
73 filters: Vec<Expr<bool>>,
74 group_by: Vec<ExprNode>,
75 having: Vec<Expr<bool>>,
76 order_by: Vec<Order>,
77 limit: Option<u64>,
78 offset: Option<u64>,
79 distinct: bool,
80 loads: Loads,
81 _marker: PhantomData<Out>,
82}
83
84impl<Out> Select<Out, NoLoad> {
85 pub fn new(table: Table) -> Self {
86 Self {
87 table,
88 columns: None,
89 joins: Vec::new(),
90 filters: Vec::new(),
91 group_by: Vec::new(),
92 having: Vec::new(),
93 order_by: Vec::new(),
94 limit: None,
95 offset: None,
96 distinct: false,
97 loads: NoLoad,
98 _marker: PhantomData,
99 }
100 }
101}
102
103impl<Out, Loads> Select<Out, Loads> {
104 pub fn table(&self) -> Table {
105 self.table
106 }
107
108 pub fn columns_ref(&self) -> Option<&[SelectItem]> {
109 self.columns.as_deref()
110 }
111
112 pub fn joins(&self) -> &[Join] {
113 &self.joins
114 }
115
116 pub fn select_only(mut self) -> Self {
117 self.columns = Some(Vec::new());
118 self
119 }
120
121 pub fn column<T>(mut self, expr: impl IntoExpr<T>) -> Self {
122 let item = SelectItem {
123 expr: expr.into_expr().node,
124 alias: None,
125 };
126 match &mut self.columns {
127 Some(columns) => columns.push(item),
128 None => self.columns = Some(vec![item]),
129 }
130 self
131 }
132
133 pub fn column_as<T>(mut self, expr: impl IntoExpr<T>, alias: &str) -> Self {
134 let item = SelectItem {
135 expr: expr.into_expr().node,
136 alias: Some(alias.to_string()),
137 };
138 match &mut self.columns {
139 Some(columns) => columns.push(item),
140 None => self.columns = Some(vec![item]),
141 }
142 self
143 }
144
145 pub fn filter(mut self, expr: Expr<bool>) -> Self {
146 self.filters.push(expr);
147 self
148 }
149
150 pub fn group_by<T>(mut self, expr: impl IntoExpr<T>) -> Self {
151 self.group_by.push(expr.into_expr().node);
152 self
153 }
154
155 pub fn having(mut self, expr: Expr<bool>) -> Self {
156 self.having.push(expr);
157 self
158 }
159
160 pub fn join<R>(mut self, rel: R) -> Self
161 where
162 R: RelationInfo<Parent = Out>,
163 {
164 let relation = rel.relation();
165 for (table, on) in relation.join_steps() {
166 self.joins.push(Join {
167 table,
168 on,
169 kind: JoinKind::Inner,
170 });
171 }
172 self
173 }
174
175 pub fn left_join<R>(mut self, rel: R) -> Self
176 where
177 R: RelationInfo<Parent = Out>,
178 {
179 let relation = rel.relation();
180 for (table, on) in relation.join_steps() {
181 self.joins.push(Join {
182 table,
183 on,
184 kind: JoinKind::Left,
185 });
186 }
187 self
188 }
189
190 pub fn join_on(mut self, table: Table, on: Expr<bool>) -> Self {
191 self.joins.push(Join {
192 table,
193 on,
194 kind: JoinKind::Inner,
195 });
196 self
197 }
198
199 pub fn left_join_on(mut self, table: Table, on: Expr<bool>) -> Self {
200 self.joins.push(Join {
201 table,
202 on,
203 kind: JoinKind::Left,
204 });
205 self
206 }
207
208 pub fn limit(mut self, limit: u64) -> Self {
209 self.limit = Some(limit);
210 self
211 }
212
213 pub fn offset(mut self, offset: u64) -> Self {
214 self.offset = Some(offset);
215 self
216 }
217
218 pub fn distinct(mut self) -> Self {
219 self.distinct = true;
220 self
221 }
222
223 pub fn order_by(mut self, order: Order) -> Self {
224 self.order_by.push(order);
225 self
226 }
227
228 pub fn columns(mut self, columns: Vec<ColumnRef>) -> Self {
229 let items = columns
230 .into_iter()
231 .map(|col| SelectItem {
232 expr: ExprNode::Column(col),
233 alias: None,
234 })
235 .collect::<Vec<_>>();
236 self.columns = Some(items);
237 self
238 }
239
240 pub fn into_model<T>(self) -> Select<T, Loads> {
241 Select {
242 table: self.table,
243 columns: self.columns,
244 joins: self.joins,
245 filters: self.filters,
246 group_by: self.group_by,
247 having: self.having,
248 order_by: self.order_by,
249 limit: self.limit,
250 offset: self.offset,
251 distinct: self.distinct,
252 loads: self.loads,
253 _marker: PhantomData,
254 }
255 }
256
257 pub fn with<L>(self, load: L) -> Select<L::Out2, LoadChain<Loads, L>>
258 where
259 L: ApplyLoad<Out>,
260 {
261 Select {
262 table: self.table,
263 columns: self.columns,
264 joins: self.joins,
265 filters: self.filters,
266 group_by: self.group_by,
267 having: self.having,
268 order_by: self.order_by,
269 limit: self.limit,
270 offset: self.offset,
271 distinct: self.distinct,
272 loads: LoadChain {
273 prev: self.loads,
274 load,
275 },
276 _marker: PhantomData,
277 }
278 }
279
280 pub fn compile(&self) -> CompiledSql {
281 self.compile_inner(true, true)
282 }
283
284 pub fn compile_without_pagination(&self) -> CompiledSql {
285 self.compile_inner(false, false)
286 }
287
288 pub fn compile_with_extra(
289 &self,
290 extra_columns: &[SelectItem],
291 extra_joins: &[Join],
292 ) -> CompiledSql {
293 self.compile_inner_with(extra_columns, extra_joins, true, true)
294 }
295
296 fn compile_inner(&self, include_order: bool, include_pagination: bool) -> CompiledSql {
297 self.compile_inner_with(&[], &[], include_order, include_pagination)
298 }
299
300 fn compile_inner_with(
301 &self,
302 extra_columns: &[SelectItem],
303 extra_joins: &[Join],
304 include_order: bool,
305 include_pagination: bool,
306 ) -> CompiledSql {
307 let mut builder = SqlBuilder::new();
308 builder.push_sql("SELECT ");
309 if self.distinct {
310 builder.push_sql("DISTINCT ");
311 }
312 match &self.columns {
313 Some(columns) => {
314 for (idx, col) in columns.iter().enumerate() {
315 if idx > 0 {
316 builder.push_sql(", ");
317 }
318 col.expr.to_sql(&mut builder);
319 if let Some(alias) = &col.alias {
320 builder.push_sql(" AS ");
321 builder.push_sql(alias);
322 }
323 }
324 if !extra_columns.is_empty() {
325 for col in extra_columns {
326 builder.push_sql(", ");
327 col.expr.to_sql(&mut builder);
328 if let Some(alias) = &col.alias {
329 builder.push_sql(" AS ");
330 builder.push_sql(alias);
331 }
332 }
333 }
334 }
335 None => {
336 builder.push_sql(self.table.qualifier());
337 builder.push_sql(".*");
338 if !extra_columns.is_empty() {
339 for col in extra_columns {
340 builder.push_sql(", ");
341 col.expr.to_sql(&mut builder);
342 if let Some(alias) = &col.alias {
343 builder.push_sql(" AS ");
344 builder.push_sql(alias);
345 }
346 }
347 }
348 }
349 }
350 builder.push_sql(" FROM ");
351 builder.push_sql(&self.table.qualified_name());
352 if let Some(alias) = self.table.alias {
353 builder.push_sql(" ");
354 builder.push_sql(alias);
355 }
356 for join in &self.joins {
357 builder.push_sql(match join.kind {
358 JoinKind::Inner => " JOIN ",
359 JoinKind::Left => " LEFT JOIN ",
360 });
361 builder.push_sql(&join.table.qualified_name());
362 if let Some(alias) = join.table.alias {
363 builder.push_sql(" ");
364 builder.push_sql(alias);
365 }
366 builder.push_sql(" ON ");
367 join.on.node.to_sql(&mut builder);
368 }
369 for join in extra_joins {
370 builder.push_sql(match join.kind {
371 JoinKind::Inner => " JOIN ",
372 JoinKind::Left => " LEFT JOIN ",
373 });
374 builder.push_sql(&join.table.qualified_name());
375 if let Some(alias) = join.table.alias {
376 builder.push_sql(" ");
377 builder.push_sql(alias);
378 }
379 builder.push_sql(" ON ");
380 join.on.node.to_sql(&mut builder);
381 }
382 if !self.filters.is_empty() {
383 builder.push_sql(" WHERE ");
384 for (idx, expr) in self.filters.iter().enumerate() {
385 if idx > 0 {
386 builder.push_sql(" AND ");
387 }
388 expr.node.to_sql(&mut builder);
389 }
390 }
391 if !self.group_by.is_empty() {
392 builder.push_sql(" GROUP BY ");
393 for (idx, expr) in self.group_by.iter().enumerate() {
394 if idx > 0 {
395 builder.push_sql(", ");
396 }
397 expr.to_sql(&mut builder);
398 }
399 }
400 if !self.having.is_empty() {
401 builder.push_sql(" HAVING ");
402 for (idx, expr) in self.having.iter().enumerate() {
403 if idx > 0 {
404 builder.push_sql(" AND ");
405 }
406 expr.node.to_sql(&mut builder);
407 }
408 }
409 if include_order && !self.order_by.is_empty() {
410 builder.push_sql(" ORDER BY ");
411 for (idx, order) in self.order_by.iter().enumerate() {
412 if idx > 0 {
413 builder.push_sql(", ");
414 }
415 match &order.expr {
416 OrderExpr::Expr(expr) => expr.to_sql(&mut builder),
417 OrderExpr::Alias(alias) => builder.push_sql(alias),
418 }
419 builder.push_sql(match order.direction {
420 OrderDirection::Asc => " ASC",
421 OrderDirection::Desc => " DESC",
422 });
423 }
424 }
425 if include_pagination {
426 if let Some(limit) = self.limit {
427 builder.push_sql(" LIMIT ");
428 builder.push_sql(&limit.to_string());
429 }
430 if let Some(offset) = self.offset {
431 builder.push_sql(" OFFSET ");
432 builder.push_sql(&offset.to_string());
433 }
434 }
435 builder.finish()
436 }
437
438 pub fn debug_sql(&self) -> String {
439 self.compile().sql
440 }
441
442 pub fn into_parts(self) -> (CompiledSql, Loads) {
443 let compiled = self.compile();
444 (compiled, self.loads)
445 }
446
447 pub fn into_parts_with_loads(self) -> (Select<Out, NoLoad>, Loads) {
448 let Select {
449 table,
450 columns,
451 joins,
452 filters,
453 group_by,
454 having,
455 order_by,
456 limit,
457 offset,
458 distinct,
459 loads,
460 _marker,
461 } = self;
462
463 let select = Select {
464 table,
465 columns,
466 joins,
467 filters,
468 group_by,
469 having,
470 order_by,
471 limit,
472 offset,
473 distinct,
474 loads: NoLoad,
475 _marker,
476 };
477
478 (select, loads)
479 }
480}
481
482impl Order {
483 pub fn asc(expr: impl IntoOrderExpr) -> Self {
484 Self {
485 expr: expr.into_order_expr(),
486 direction: OrderDirection::Asc,
487 }
488 }
489
490 pub fn desc(expr: impl IntoOrderExpr) -> Self {
491 Self {
492 expr: expr.into_order_expr(),
493 direction: OrderDirection::Desc,
494 }
495 }
496
497 pub fn asc_alias(alias: &str) -> Self {
498 Self {
499 expr: OrderExpr::Alias(alias.to_string()),
500 direction: OrderDirection::Asc,
501 }
502 }
503
504 pub fn desc_alias(alias: &str) -> Self {
505 Self {
506 expr: OrderExpr::Alias(alias.to_string()),
507 direction: OrderDirection::Desc,
508 }
509 }
510}