Skip to main content

keelson_psql/statement/
delete.rs

1use keelson_core::clause::{
2    HasJoins, HasReturning, HasTableRef, HasWhere, HasWith, Join, Returning, TableRef, Where, With,
3};
4use keelson_core::expr::{Expr, IntoExpr, IntoExprList};
5use keelson_core::{Dialect, Error, Expression, Mod, Query, QueryExtensions, QueryType, SqlWriter};
6
7use super::{HasExtraTables, HasTargetTable, write_from_list};
8use crate::Psql;
9
10/// A PostgreSQL `DELETE`.
11///
12/// From <https://www.postgresql.org/docs/17/sql-delete.html>:
13///
14/// ```text
15/// [ WITH [ RECURSIVE ] with_query [, ...] ]
16/// DELETE FROM [ ONLY ] table_name [ * ] [ [ AS ] alias ]
17///     [ USING from_item [, ...] ]
18///     [ WHERE condition | WHERE CURRENT OF cursor_name ]
19///     [ RETURNING … ]
20/// ```
21///
22/// `USING` is a `FROM` list under another keyword, which is why it is the
23/// [`HasTableRef`] slot here and the deleted-from table is the
24/// [`HasTargetTable`](super::HasTargetTable) one.
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    /// The first `USING` item, with its joins.
32    pub using: TableRef,
33    /// Further comma-separated `USING` items.
34    pub extra_using: Vec<TableRef>,
35    /// `WHERE …`.
36    pub where_: Where,
37    /// `RETURNING …`.
38    pub returning: Returning,
39}
40
41impl DeleteQuery {
42    /// A `DELETE` with nothing set yet.
43    pub fn new() -> DeleteQuery {
44        DeleteQuery::default()
45    }
46
47    /// Apply more mods to an existing query.
48    pub fn apply(&mut self, mods: impl Mod<DeleteQuery>) {
49        mods.apply(self);
50    }
51}
52
53impl Expression for DeleteQuery {
54    fn write_sql(&self, w: &mut SqlWriter<'_>) {
55        w.write_if(!self.with.is_empty(), "", &self.with, " ");
56
57        if self.table.is_empty() {
58            w.record_error(Error::Incomplete("the table of a DELETE"));
59            return;
60        }
61
62        w.push_str("DELETE FROM ");
63        w.write_expr(&self.table);
64
65        write_from_list(
66            w,
67            " USING ",
68            &self.using,
69            &self.extra_using,
70            "the USING item its joins attach to",
71        );
72
73        w.write_if(!self.where_.is_empty(), " ", &self.where_, "");
74        w.write_if(!self.returning.is_empty(), " ", &self.returning, "");
75    }
76}
77
78impl Query for DeleteQuery {
79    fn query_type(&self) -> QueryType {
80        QueryType::Delete
81    }
82
83    fn dialect(&self) -> &dyn Dialect {
84        &Psql
85    }
86}
87
88impl<H, L, M> QueryExtensions<H, L, M> for DeleteQuery {}
89
90impl IntoExpr for DeleteQuery {
91    fn into_expr(self) -> Expr {
92        crate::query(self)
93    }
94}
95
96impl IntoExprList for DeleteQuery {
97    fn into_expr_list(self) -> Vec<Expr> {
98        vec![self.into_expr()]
99    }
100}
101
102impl HasWith for DeleteQuery {
103    fn with_mut(&mut self) -> &mut With {
104        &mut self.with
105    }
106}
107
108impl HasTargetTable for DeleteQuery {
109    fn target_table_mut(&mut self) -> &mut TableRef {
110        &mut self.table
111    }
112}
113
114impl HasTableRef for DeleteQuery {
115    fn table_ref_mut(&mut self) -> &mut TableRef {
116        &mut self.using
117    }
118}
119
120impl HasExtraTables for DeleteQuery {
121    fn extra_tables_mut(&mut self) -> &mut Vec<TableRef> {
122        &mut self.extra_using
123    }
124}
125
126impl HasJoins for DeleteQuery {
127    fn joins_mut(&mut self) -> &mut Vec<Join> {
128        &mut self.using.joins
129    }
130}
131
132impl HasWhere for DeleteQuery {
133    fn where_mut(&mut self) -> &mut Where {
134        &mut self.where_
135    }
136}
137
138impl HasReturning for DeleteQuery {
139    fn returning_mut(&mut self) -> &mut Returning {
140        &mut self.returning
141    }
142}