Skip to main content

keelson_sqlite/statement/
delete.rs

1use keelson_core::clause::{HasReturning, HasWhere, HasWith, Returning, TableRef, Where, With};
2use keelson_core::expr::{Expr, IntoExpr, IntoExprList};
3use keelson_core::{Dialect, Error, Expression, Mod, Query, QueryExtensions, QueryType, SqlWriter};
4
5use super::HasTargetTable;
6use crate::Sqlite;
7
8/// A SQLite `DELETE`.
9///
10/// From <https://www.sqlite.org/lang_delete.html>:
11///
12/// ```text
13/// [ WITH [ RECURSIVE ] common-table-expression [, ...] ]
14/// DELETE FROM qualified-table-name
15///     [ WHERE expr ]
16///     [ RETURNING result-column [, ...] ]
17/// ```
18///
19/// That is the whole statement — the shortest of the four by a wide margin.
20/// PostgreSQL's `USING` has no counterpart, so there is no from-item, no join and
21/// no `HasTableRef` here; a delete driven by another table is written with a
22/// sub-query in the `WHERE`, which is what SQLite gives instead. There is also no
23/// `OR` clause: SQLite's `conflict-clause` is offered on `INSERT` and `UPDATE`
24/// only, since a delete cannot violate a uniqueness constraint.
25#[derive(Debug, Clone, Default)]
26pub struct DeleteQuery {
27    /// `WITH …`.
28    pub with: With,
29    /// The table rows are deleted from.
30    pub table: TableRef,
31    /// `WHERE …`.
32    pub where_: Where,
33    /// `RETURNING …`. SQLite 3.35 and later.
34    pub returning: Returning,
35}
36
37impl DeleteQuery {
38    /// A `DELETE` with nothing set yet.
39    pub fn new() -> DeleteQuery {
40        DeleteQuery::default()
41    }
42
43    /// Apply more mods to an existing query.
44    pub fn apply(&mut self, mods: impl Mod<DeleteQuery>) {
45        mods.apply(self);
46    }
47}
48
49impl Expression for DeleteQuery {
50    fn write_sql(&self, w: &mut SqlWriter<'_>) {
51        w.write_if(!self.with.is_empty(), "", &self.with, " ");
52
53        if self.table.is_empty() {
54            w.record_error(Error::Incomplete("the table of a DELETE"));
55            return;
56        }
57
58        w.push_str("DELETE FROM ");
59        w.write_expr(&self.table);
60
61        w.write_if(!self.where_.is_empty(), " ", &self.where_, "");
62        w.write_if(!self.returning.is_empty(), " ", &self.returning, "");
63    }
64}
65
66impl Query for DeleteQuery {
67    fn query_type(&self) -> QueryType {
68        QueryType::Delete
69    }
70
71    fn dialect(&self) -> &dyn Dialect {
72        &Sqlite
73    }
74}
75
76impl<H, L, M> QueryExtensions<H, L, M> for DeleteQuery {}
77
78impl IntoExpr for DeleteQuery {
79    fn into_expr(self) -> Expr {
80        crate::query(self)
81    }
82}
83
84impl IntoExprList for DeleteQuery {
85    fn into_expr_list(self) -> Vec<Expr> {
86        vec![self.into_expr()]
87    }
88}
89
90impl HasWith for DeleteQuery {
91    fn with_mut(&mut self) -> &mut With {
92        &mut self.with
93    }
94}
95
96impl HasTargetTable for DeleteQuery {
97    fn target_table_mut(&mut self) -> &mut TableRef {
98        &mut self.table
99    }
100}
101
102impl HasWhere for DeleteQuery {
103    fn where_mut(&mut self) -> &mut Where {
104        &mut self.where_
105    }
106}
107
108impl HasReturning for DeleteQuery {
109    fn returning_mut(&mut self) -> &mut Returning {
110        &mut self.returning
111    }
112}