Skip to main content

turso_sql/
query.rs

1//! DML statement builders: `SELECT`, `INSERT`, `UPDATE` and `DELETE`.
2//!
3//! Each builder is a plain data structure with chainable setters; nothing is
4//! validated or rendered until the writer runs, so a partially built
5//! statement can be stored, cloned and completed later — which is how
6//! `turso-orm` assembles entity queries in several passes. The fields are
7//! `pub(crate)` rather than private so the writer in `crate::writer` can
8//! read them directly without a mirror of accessors.
9//!
10//! The module owns the shape of DML statements only. Expressions and
11//! conditions come from `crate::expr`, identifiers from `crate::iden`, and
12//! the SQL text is produced by `crate::writer`.
13//!
14//! - [`Query`]: the entry point, with one constructor per statement
15//!   (`Query::select()` and friends);
16//! - [`Select`], [`Insert`], [`Update`], [`Delete`]: the four statements;
17//! - [`Join`], [`JoinType`], [`OnConflict`], [`Returning`], [`SelectItem`]:
18//!   the clauses they are built from.
19
20use crate::expr::{Condition, Expr, IntoCondition, Order};
21use crate::iden::{ColumnRef, Ident, IntoIden, TableRef};
22use crate::value::Value;
23
24/// The entry point to the DML builders, mirroring the `Query::select()`
25/// style.
26#[derive(Debug)]
27pub struct Query;
28
29impl Query {
30    /// Starts a `SELECT`.
31    pub fn select() -> Select {
32        Select::default()
33    }
34
35    /// Starts an `INSERT`.
36    pub fn insert() -> Insert {
37        Insert::default()
38    }
39
40    /// Starts an `UPDATE`.
41    pub fn update() -> Update {
42        Update::default()
43    }
44
45    /// Starts a `DELETE`.
46    pub fn delete() -> Delete {
47        Delete::default()
48    }
49}
50
51/// An item of a select list.
52#[derive(Clone, Debug, PartialEq)]
53pub enum SelectItem {
54    /// Any expression, possibly aliased with [`Expr::alias`].
55    Expr(Expr),
56}
57
58/// The join kinds.
59#[derive(Clone, Copy, Debug, PartialEq, Eq)]
60pub enum JoinType {
61    /// An `INNER JOIN`.
62    Inner,
63    /// A `LEFT JOIN`.
64    Left,
65    /// A `CROSS JOIN`.
66    Cross,
67}
68
69/// A join clause.
70#[derive(Clone, Debug, PartialEq)]
71pub struct Join {
72    /// The join kind.
73    pub kind: JoinType,
74    /// The joined table.
75    pub table: TableRef,
76    /// The `ON` condition, absent for a `CROSS JOIN`.
77    pub on: Option<Expr>,
78}
79
80/// A `RETURNING` clause.
81#[derive(Clone, Debug, Default, PartialEq)]
82pub enum Returning {
83    /// No `RETURNING` clause.
84    #[default]
85    None,
86    /// `RETURNING *`.
87    All,
88    /// `RETURNING a, b`.
89    Columns(Vec<ColumnRef>),
90}
91
92/// A `SELECT` statement.
93#[derive(Clone, Debug, Default, PartialEq)]
94pub struct Select {
95    /// Whether `DISTINCT` is set.
96    pub(crate) distinct: bool,
97    /// The select list; empty renders as `*`.
98    pub(crate) items: Vec<SelectItem>,
99    /// The `FROM` tables.
100    pub(crate) from: Vec<TableRef>,
101    /// A derived table `FROM (subquery) AS alias`, appended after `from`.
102    pub(crate) from_subquery: Option<(Box<Select>, Ident)>,
103    /// The join clauses, in order.
104    pub(crate) joins: Vec<Join>,
105    /// The `WHERE` condition; empty renders as nothing.
106    pub(crate) r#where: Condition,
107    /// The `GROUP BY` expressions.
108    pub(crate) group_by: Vec<Expr>,
109    /// The `HAVING` condition; empty renders as nothing.
110    pub(crate) having: Condition,
111    /// The `ORDER BY` terms.
112    pub(crate) order_by: Vec<(Expr, Order)>,
113    /// The `LIMIT`, bound as a parameter.
114    pub(crate) limit: Option<u64>,
115    /// The `OFFSET`, bound as a parameter.
116    pub(crate) offset: Option<u64>,
117}
118
119impl Select {
120    /// A new empty select whose conditions default to `Condition::all()`.
121    pub fn new() -> Self {
122        Self {
123            r#where: Condition::all(),
124            having: Condition::all(),
125            ..Default::default()
126        }
127    }
128
129    /// Sets `SELECT DISTINCT`.
130    #[must_use]
131    pub fn distinct(mut self) -> Self {
132        self.distinct = true;
133        self
134    }
135
136    /// Selects a column.
137    #[must_use]
138    pub fn column(mut self, column: impl Into<ColumnRef>) -> Self {
139        self.items
140            .push(SelectItem::Expr(Expr::Column(column.into())));
141        self
142    }
143
144    /// Selects several columns.
145    #[must_use]
146    pub fn columns<C: Into<ColumnRef>>(mut self, columns: impl IntoIterator<Item = C>) -> Self {
147        for c in columns {
148            self = self.column(c);
149        }
150        self
151    }
152
153    /// Selects an expression.
154    #[must_use]
155    pub fn expr(mut self, expr: Expr) -> Self {
156        self.items.push(SelectItem::Expr(expr));
157        self
158    }
159
160    /// Selects an aliased expression.
161    #[must_use]
162    pub fn expr_as(self, expr: Expr, alias: impl IntoIden) -> Self {
163        self.expr(expr.alias(alias))
164    }
165
166    /// Whether any item has been selected; without one the statement renders
167    /// `SELECT *`.
168    pub fn has_items(&self) -> bool {
169        !self.items.is_empty()
170    }
171
172    /// Removes all selected items.
173    #[must_use]
174    pub fn clear_items(mut self) -> Self {
175        self.items.clear();
176        self
177    }
178
179    /// Adds a `FROM table`.
180    #[must_use]
181    pub fn from(mut self, table: impl Into<TableRef>) -> Self {
182        self.from.push(table.into());
183        self
184    }
185
186    /// Sets `FROM (subquery) AS alias`.
187    #[must_use]
188    pub fn from_subquery(mut self, subquery: Select, alias: impl IntoIden) -> Self {
189        self.from_subquery = Some((Box::new(subquery), alias.into_iden()));
190        self
191    }
192
193    /// Adds a `JOIN table ON cond` of the given kind.
194    #[must_use]
195    pub fn join(
196        mut self,
197        kind: JoinType,
198        table: impl Into<TableRef>,
199        on: impl IntoCondition,
200    ) -> Self {
201        self.joins.push(Join {
202            kind,
203            table: table.into(),
204            on: on.into_condition().into_expr(),
205        });
206        self
207    }
208
209    /// Adds an `INNER JOIN`.
210    #[must_use]
211    pub fn inner_join(self, table: impl Into<TableRef>, on: impl IntoCondition) -> Self {
212        self.join(JoinType::Inner, table, on)
213    }
214
215    /// Adds a `LEFT JOIN`.
216    #[must_use]
217    pub fn left_join(self, table: impl Into<TableRef>, on: impl IntoCondition) -> Self {
218        self.join(JoinType::Left, table, on)
219    }
220
221    /// Adds a condition to `WHERE` with `AND`.
222    #[must_use]
223    pub fn and_where(mut self, cond: impl IntoCondition) -> Self {
224        self.r#where = std::mem::take(&mut self.r#where).add(cond);
225        self
226    }
227
228    /// Replaces the whole `WHERE` condition.
229    #[must_use]
230    pub fn cond_where(mut self, cond: impl IntoCondition) -> Self {
231        self.r#where = cond.into_condition();
232        self
233    }
234
235    /// Adds a `GROUP BY` expression.
236    #[must_use]
237    pub fn group_by(mut self, expr: Expr) -> Self {
238        self.group_by.push(expr);
239        self
240    }
241
242    /// Adds a condition to `HAVING` with `AND`.
243    #[must_use]
244    pub fn and_having(mut self, cond: impl IntoCondition) -> Self {
245        self.having = std::mem::take(&mut self.having).add(cond);
246        self
247    }
248
249    /// Adds an `ORDER BY column`.
250    #[must_use]
251    pub fn order_by(mut self, column: impl Into<ColumnRef>, order: Order) -> Self {
252        self.order_by.push((Expr::Column(column.into()), order));
253        self
254    }
255
256    /// Adds an `ORDER BY expr`.
257    #[must_use]
258    pub fn order_by_expr(mut self, expr: Expr, order: Order) -> Self {
259        self.order_by.push((expr, order));
260        self
261    }
262
263    /// Removes the ordering.
264    #[must_use]
265    pub fn clear_order_by(mut self) -> Self {
266        self.order_by.clear();
267        self
268    }
269
270    /// Sets `LIMIT`.
271    #[must_use]
272    pub fn limit(mut self, limit: u64) -> Self {
273        self.limit = Some(limit);
274        self
275    }
276
277    /// Removes `LIMIT`.
278    #[must_use]
279    pub fn reset_limit(mut self) -> Self {
280        self.limit = None;
281        self
282    }
283
284    /// Sets `OFFSET`.
285    #[must_use]
286    pub fn offset(mut self, offset: u64) -> Self {
287        self.offset = Some(offset);
288        self
289    }
290
291    /// Removes `OFFSET`.
292    #[must_use]
293    pub fn reset_offset(mut self) -> Self {
294        self.offset = None;
295        self
296    }
297
298    /// The `FROM` tables.
299    pub fn from_tables(&self) -> &[TableRef] {
300        &self.from
301    }
302
303    /// The join clauses, in order.
304    pub fn joins(&self) -> &[Join] {
305        &self.joins
306    }
307}
308
309/// An `ON CONFLICT` clause for inserts.
310#[derive(Clone, Debug, PartialEq)]
311pub struct OnConflict {
312    /// The conflict target columns; empty renders a bare `ON CONFLICT`.
313    pub(crate) target: Vec<Ident>,
314    /// What to do on conflict.
315    pub(crate) action: ConflictAction,
316}
317
318/// The action part of an `ON CONFLICT` clause.
319#[derive(Clone, Debug, PartialEq)]
320pub(crate) enum ConflictAction {
321    /// `DO NOTHING`.
322    Nothing,
323    /// `DO UPDATE SET column = expr, ...`.
324    Update(Vec<(Ident, Expr)>),
325}
326
327impl OnConflict {
328    /// Builds `ON CONFLICT(columns) DO NOTHING`.
329    pub fn do_nothing<C: IntoIden>(columns: impl IntoIterator<Item = C>) -> Self {
330        Self {
331            target: columns.into_iter().map(IntoIden::into_iden).collect(),
332            action: ConflictAction::Nothing,
333        }
334    }
335
336    /// Builds `ON CONFLICT(columns) DO UPDATE SET c = excluded.c, ...` for
337    /// every column in `update`.
338    pub fn update_columns<C: IntoIden, U: IntoIden>(
339        columns: impl IntoIterator<Item = C>,
340        update: impl IntoIterator<Item = U>,
341    ) -> Self {
342        let sets = update
343            .into_iter()
344            .map(|c| {
345                let c = c.into_iden();
346                let excluded =
347                    Expr::Column(ColumnRef::TableColumn("excluded".into_iden(), c.clone()));
348                (c, excluded)
349            })
350            .collect();
351        Self {
352            target: columns.into_iter().map(IntoIden::into_iden).collect(),
353            action: ConflictAction::Update(sets),
354        }
355    }
356
357    /// Builds `ON CONFLICT(columns) DO UPDATE SET` with explicit expressions.
358    pub fn update_exprs<C: IntoIden, U: IntoIden>(
359        columns: impl IntoIterator<Item = C>,
360        sets: impl IntoIterator<Item = (U, Expr)>,
361    ) -> Self {
362        Self {
363            target: columns.into_iter().map(IntoIden::into_iden).collect(),
364            action: ConflictAction::Update(
365                sets.into_iter().map(|(c, e)| (c.into_iden(), e)).collect(),
366            ),
367        }
368    }
369}
370
371/// An `INSERT` statement.
372#[derive(Clone, Debug, Default, PartialEq)]
373pub struct Insert {
374    /// The target table.
375    pub(crate) table: Option<TableRef>,
376    /// The column list.
377    pub(crate) columns: Vec<Ident>,
378    /// The `VALUES` rows, one expression per column.
379    pub(crate) rows: Vec<Vec<Expr>>,
380    /// Whether to render `DEFAULT VALUES` instead of rows.
381    pub(crate) default_values: bool,
382    /// The `ON CONFLICT` clause.
383    pub(crate) on_conflict: Option<OnConflict>,
384    /// The `RETURNING` clause.
385    pub(crate) returning: Returning,
386    /// A `SELECT` source rendered instead of `VALUES` when set.
387    pub(crate) select: Option<Box<Select>>,
388}
389
390impl Insert {
391    /// Sets `INSERT INTO table`.
392    #[must_use]
393    pub fn into_table(mut self, table: impl Into<TableRef>) -> Self {
394        self.table = Some(table.into());
395        self
396    }
397
398    /// Sets the column list.
399    #[must_use]
400    pub fn columns<C: IntoIden>(mut self, columns: impl IntoIterator<Item = C>) -> Self {
401        self.columns = columns.into_iter().map(IntoIden::into_iden).collect();
402        self
403    }
404
405    /// Adds a row of values, one per column.
406    #[must_use]
407    pub fn values<V: Into<Expr>>(mut self, row: impl IntoIterator<Item = V>) -> Self {
408        self.rows.push(row.into_iter().map(Into::into).collect());
409        self
410    }
411
412    /// Sets `INSERT INTO table DEFAULT VALUES`.
413    #[must_use]
414    pub fn default_values(mut self) -> Self {
415        self.default_values = true;
416        self
417    }
418
419    /// Sets `INSERT INTO table (...) SELECT ...`.
420    #[must_use]
421    pub fn select_from(mut self, select: Select) -> Self {
422        self.select = Some(Box::new(select));
423        self
424    }
425
426    /// Sets the `ON CONFLICT` clause.
427    #[must_use]
428    pub fn on_conflict(mut self, on_conflict: OnConflict) -> Self {
429        self.on_conflict = Some(on_conflict);
430        self
431    }
432
433    /// Sets the `RETURNING` clause.
434    #[must_use]
435    pub fn returning(mut self, returning: Returning) -> Self {
436        self.returning = returning;
437        self
438    }
439
440    /// Sets `RETURNING *`.
441    #[must_use]
442    pub fn returning_all(self) -> Self {
443        self.returning(Returning::All)
444    }
445
446    /// The number of rows added so far.
447    pub fn row_count(&self) -> usize {
448        self.rows.len()
449    }
450}
451
452/// An `UPDATE` statement.
453#[derive(Clone, Debug, Default, PartialEq)]
454pub struct Update {
455    /// The target table.
456    pub(crate) table: Option<TableRef>,
457    /// The `SET` assignments, in order.
458    pub(crate) sets: Vec<(Ident, Expr)>,
459    /// The `WHERE` condition.
460    pub(crate) r#where: Option<Condition>,
461    /// The `RETURNING` clause.
462    pub(crate) returning: Returning,
463    /// The `LIMIT`, written inline since it is not a user value.
464    pub(crate) limit: Option<u64>,
465}
466
467impl Update {
468    /// Sets `UPDATE table`.
469    #[must_use]
470    pub fn table(mut self, table: impl Into<TableRef>) -> Self {
471        self.table = Some(table.into());
472        self
473    }
474
475    /// Adds `SET column = value`.
476    #[must_use]
477    pub fn value(mut self, column: impl IntoIden, value: impl Into<Expr>) -> Self {
478        self.sets.push((column.into_iden(), value.into()));
479        self
480    }
481
482    /// Adds several `SET` assignments.
483    #[must_use]
484    pub fn values<C: IntoIden, V: Into<Expr>>(
485        mut self,
486        sets: impl IntoIterator<Item = (C, V)>,
487    ) -> Self {
488        for (c, v) in sets {
489            self = self.value(c, v);
490        }
491        self
492    }
493
494    /// Adds a condition to `WHERE` with `AND`.
495    #[must_use]
496    pub fn and_where(mut self, cond: impl IntoCondition) -> Self {
497        let current = self.r#where.take().unwrap_or_else(Condition::all);
498        self.r#where = Some(current.add(cond));
499        self
500    }
501
502    /// Sets the `RETURNING` clause.
503    #[must_use]
504    pub fn returning(mut self, returning: Returning) -> Self {
505        self.returning = returning;
506        self
507    }
508
509    /// Sets `RETURNING *`.
510    #[must_use]
511    pub fn returning_all(self) -> Self {
512        self.returning(Returning::All)
513    }
514
515    /// Whether any `SET` assignment was added.
516    pub fn has_sets(&self) -> bool {
517        !self.sets.is_empty()
518    }
519}
520
521/// A `DELETE` statement.
522#[derive(Clone, Debug, Default, PartialEq)]
523pub struct Delete {
524    /// The target table.
525    pub(crate) table: Option<TableRef>,
526    /// The `WHERE` condition.
527    pub(crate) r#where: Option<Condition>,
528    /// The `RETURNING` clause.
529    pub(crate) returning: Returning,
530}
531
532impl Delete {
533    /// Sets `DELETE FROM table`.
534    #[must_use]
535    pub fn from_table(mut self, table: impl Into<TableRef>) -> Self {
536        self.table = Some(table.into());
537        self
538    }
539
540    /// Adds a condition to `WHERE` with `AND`.
541    #[must_use]
542    pub fn and_where(mut self, cond: impl IntoCondition) -> Self {
543        let current = self.r#where.take().unwrap_or_else(Condition::all);
544        self.r#where = Some(current.add(cond));
545        self
546    }
547
548    /// Sets the `RETURNING` clause.
549    #[must_use]
550    pub fn returning(mut self, returning: Returning) -> Self {
551        self.returning = returning;
552        self
553    }
554}
555
556impl From<Value> for SelectItem {
557    fn from(v: Value) -> Self {
558        SelectItem::Expr(Expr::Value(v))
559    }
560}