dbkit_core/
query.rs

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}