sea_query/query/
delete.rs

1use inherent::inherent;
2use std::borrow::Cow;
3
4use crate::{
5    ConditionHolder, ConditionalStatement, Expr, IntoColumnRef, IntoCondition, IntoTableRef,
6    LogicalChainOper, NullOrdering, Order, OrderExpr, OrderedStatement, QueryBuilder,
7    QueryStatement, QueryStatementBuilder, QueryStatementWriter, ReturningClause, SqlWriter,
8    SubQueryStatement, TableRef, Value, Values, WithClause, WithQuery,
9};
10
11/// Delete existing rows from the table
12///
13/// # Examples
14///
15/// ```
16/// use sea_query::{tests_cfg::*, *};
17///
18/// let query = Query::delete()
19///     .from_table(Glyph::Table)
20///     .cond_where(any![
21///         Expr::col(Glyph::Id).lt(1),
22///         Expr::col(Glyph::Id).gt(10),
23///     ])
24///     .to_owned();
25///
26/// assert_eq!(
27///     query.to_string(MysqlQueryBuilder),
28///     r#"DELETE FROM `glyph` WHERE `id` < 1 OR `id` > 10"#
29/// );
30/// assert_eq!(
31///     query.to_string(PostgresQueryBuilder),
32///     r#"DELETE FROM "glyph" WHERE "id" < 1 OR "id" > 10"#
33/// );
34/// assert_eq!(
35///     query.to_string(SqliteQueryBuilder),
36///     r#"DELETE FROM "glyph" WHERE "id" < 1 OR "id" > 10"#
37/// );
38/// ```
39#[derive(Default, Debug, Clone, PartialEq)]
40pub struct DeleteStatement {
41    pub(crate) table: Option<Box<TableRef>>,
42    pub(crate) r#where: ConditionHolder,
43    pub(crate) orders: Vec<OrderExpr>,
44    pub(crate) limit: Option<Value>,
45    pub(crate) returning: Option<ReturningClause>,
46    pub(crate) with: Option<WithClause>,
47}
48
49impl DeleteStatement {
50    /// Construct a new [`DeleteStatement`]
51    pub fn new() -> Self {
52        Self::default()
53    }
54
55    pub fn take(&mut self) -> Self {
56        Self {
57            table: self.table.take(),
58            r#where: std::mem::take(&mut self.r#where),
59            orders: std::mem::take(&mut self.orders),
60            limit: self.limit.take(),
61            returning: self.returning.take(),
62            with: self.with.take(),
63        }
64    }
65
66    /// Specify which table to delete from.
67    ///
68    /// # Examples
69    ///
70    /// ```
71    /// use sea_query::{audit::*, tests_cfg::*, *};
72    ///
73    /// let query = Query::delete()
74    ///     .from_table(Glyph::Table)
75    ///     .and_where(Expr::col(Glyph::Id).eq(1))
76    ///     .to_owned();
77    ///
78    /// assert_eq!(
79    ///     query.to_string(MysqlQueryBuilder),
80    ///     r#"DELETE FROM `glyph` WHERE `id` = 1"#
81    /// );
82    /// assert_eq!(
83    ///     query.to_string(PostgresQueryBuilder),
84    ///     r#"DELETE FROM "glyph" WHERE "id" = 1"#
85    /// );
86    /// assert_eq!(
87    ///     query.to_string(SqliteQueryBuilder),
88    ///     r#"DELETE FROM "glyph" WHERE "id" = 1"#
89    /// );
90    /// assert_eq!(
91    ///     query.audit_unwrap().deleted_tables(),
92    ///     [Glyph::Table.into_iden()]
93    /// );
94    /// assert_eq!(query.audit_unwrap().selected_tables(), []);
95    /// ```
96    #[allow(clippy::wrong_self_convention)]
97    pub fn from_table<T>(&mut self, tbl_ref: T) -> &mut Self
98    where
99        T: IntoTableRef,
100    {
101        self.table = Some(Box::new(tbl_ref.into_table_ref()));
102        self
103    }
104
105    /// Limit number of updated rows.
106    pub fn limit(&mut self, limit: u64) -> &mut Self {
107        self.limit = Some(limit.into());
108        self
109    }
110
111    /// RETURNING expressions.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// use sea_query::{audit::*, tests_cfg::*, *};
117    ///
118    /// let query = Query::delete()
119    ///     .from_table(Glyph::Table)
120    ///     .and_where(Expr::col(Glyph::Id).eq(1))
121    ///     .returning(Query::returning().columns([Glyph::Id]))
122    ///     .to_owned();
123    ///
124    /// assert_eq!(
125    ///     query.to_string(MysqlQueryBuilder),
126    ///     r#"DELETE FROM `glyph` WHERE `id` = 1"#
127    /// );
128    /// assert_eq!(
129    ///     query.to_string(PostgresQueryBuilder),
130    ///     r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING "id""#
131    /// );
132    /// assert_eq!(
133    ///     query.to_string(SqliteQueryBuilder),
134    ///     r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING "id""#
135    /// );
136    /// assert_eq!(
137    ///     query.audit_unwrap().deleted_tables(),
138    ///     [Glyph::Table.into_iden()]
139    /// );
140    /// assert_eq!(
141    ///     query.audit_unwrap().selected_tables(),
142    ///     [Glyph::Table.into_iden()]
143    /// );
144    /// ```
145    pub fn returning(&mut self, returning_cols: ReturningClause) -> &mut Self {
146        self.returning = Some(returning_cols);
147        self
148    }
149
150    /// RETURNING expressions for a column.
151    ///
152    /// # Examples
153    ///
154    /// ```
155    /// use sea_query::{tests_cfg::*, *};
156    ///
157    /// let query = Query::delete()
158    ///     .from_table(Glyph::Table)
159    ///     .and_where(Expr::col(Glyph::Id).eq(1))
160    ///     .returning_col(Glyph::Id)
161    ///     .to_owned();
162    ///
163    /// assert_eq!(
164    ///     query.to_string(MysqlQueryBuilder),
165    ///     r#"DELETE FROM `glyph` WHERE `id` = 1"#
166    /// );
167    /// assert_eq!(
168    ///     query.to_string(PostgresQueryBuilder),
169    ///     r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING "id""#
170    /// );
171    /// assert_eq!(
172    ///     query.to_string(SqliteQueryBuilder),
173    ///     r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING "id""#
174    /// );
175    /// ```
176    pub fn returning_col<C>(&mut self, col: C) -> &mut Self
177    where
178        C: IntoColumnRef,
179    {
180        self.returning(ReturningClause::Columns(vec![col.into_column_ref()]))
181    }
182
183    /// RETURNING expressions all columns.
184    ///
185    /// # Examples
186    ///
187    /// ```
188    /// use sea_query::{tests_cfg::*, *};
189    ///
190    /// let query = Query::delete()
191    ///     .from_table(Glyph::Table)
192    ///     .and_where(Expr::col(Glyph::Id).eq(1))
193    ///     .returning_all()
194    ///     .to_owned();
195    ///
196    /// assert_eq!(
197    ///     query.to_string(MysqlQueryBuilder),
198    ///     r#"DELETE FROM `glyph` WHERE `id` = 1"#
199    /// );
200    /// assert_eq!(
201    ///     query.to_string(PostgresQueryBuilder),
202    ///     r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING *"#
203    /// );
204    /// assert_eq!(
205    ///     query.to_string(SqliteQueryBuilder),
206    ///     r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING *"#
207    /// );
208    /// ```
209    pub fn returning_all(&mut self) -> &mut Self {
210        self.returning(ReturningClause::All)
211    }
212
213    /// Create a [WithQuery] by specifying a [WithClause] to execute this query with.
214    ///
215    /// # Examples
216    ///
217    /// ```
218    /// use sea_query::{IntoCondition, IntoIden, audit::*, tests_cfg::*, *};
219    ///
220    /// let select = SelectStatement::new()
221    ///         .columns([Glyph::Id])
222    ///         .from(Glyph::Table)
223    ///         .and_where(Expr::col(Glyph::Image).like("0%"))
224    ///         .to_owned();
225    ///     let cte = CommonTableExpression::new()
226    ///         .query(select)
227    ///         .column(Glyph::Id)
228    ///         .table_name("cte")
229    ///         .to_owned();
230    ///     let with_clause = WithClause::new().cte(cte).to_owned();
231    ///     let update = DeleteStatement::new()
232    ///         .from_table(Glyph::Table)
233    ///         .and_where(Expr::col(Glyph::Id).in_subquery(SelectStatement::new().column(Glyph::Id).from("cte").to_owned()))
234    ///         .to_owned();
235    ///     let query = update.with(with_clause);
236    ///
237    /// assert_eq!(
238    ///     query.to_string(MysqlQueryBuilder),
239    ///     r#"WITH `cte` (`id`) AS (SELECT `id` FROM `glyph` WHERE `image` LIKE '0%') DELETE FROM `glyph` WHERE `id` IN (SELECT `id` FROM `cte`)"#
240    /// );
241    /// assert_eq!(
242    ///     query.to_string(PostgresQueryBuilder),
243    ///     r#"WITH "cte" ("id") AS (SELECT "id" FROM "glyph" WHERE "image" LIKE '0%') DELETE FROM "glyph" WHERE "id" IN (SELECT "id" FROM "cte")"#
244    /// );
245    /// assert_eq!(
246    ///     query.to_string(SqliteQueryBuilder),
247    ///     r#"WITH "cte" ("id") AS (SELECT "id" FROM "glyph" WHERE "image" LIKE '0%') DELETE FROM "glyph" WHERE "id" IN (SELECT "id" FROM "cte")"#
248    /// );
249    /// assert_eq!(
250    ///     query.audit_unwrap().deleted_tables(),
251    ///     [Glyph::Table.into_iden()]
252    /// );
253    /// assert_eq!(
254    ///     query.audit_unwrap().selected_tables(),
255    ///     [Glyph::Table.into_iden()]
256    /// );
257    /// ```
258    pub fn with(self, clause: WithClause) -> WithQuery {
259        clause.query(self)
260    }
261
262    /// Create a Common Table Expression by specifying a [CommonTableExpression] or [WithClause] to execute this query with.
263    ///
264    /// # Examples
265    ///
266    /// ```
267    /// use sea_query::{IntoCondition, IntoIden, audit::*, tests_cfg::*, *};
268    ///
269    /// let select = SelectStatement::new()
270    ///         .columns([Glyph::Id])
271    ///         .from(Glyph::Table)
272    ///         .and_where(Expr::col(Glyph::Image).like("0%"))
273    ///         .to_owned();
274    ///     let cte = CommonTableExpression::new()
275    ///         .query(select)
276    ///         .column(Glyph::Id)
277    ///         .table_name("cte")
278    ///         .to_owned();
279    ///     let with_clause = WithClause::new().cte(cte).to_owned();
280    ///     let query = DeleteStatement::new()
281    ///         .with_cte(with_clause)
282    ///         .from_table(Glyph::Table)
283    ///         .and_where(Expr::col(Glyph::Id).in_subquery(SelectStatement::new().column(Glyph::Id).from("cte").to_owned()))
284    ///         .to_owned();
285    ///
286    /// assert_eq!(
287    ///     query.to_string(MysqlQueryBuilder),
288    ///     r#"WITH `cte` (`id`) AS (SELECT `id` FROM `glyph` WHERE `image` LIKE '0%') DELETE FROM `glyph` WHERE `id` IN (SELECT `id` FROM `cte`)"#
289    /// );
290    /// assert_eq!(
291    ///     query.to_string(PostgresQueryBuilder),
292    ///     r#"WITH "cte" ("id") AS (SELECT "id" FROM "glyph" WHERE "image" LIKE '0%') DELETE FROM "glyph" WHERE "id" IN (SELECT "id" FROM "cte")"#
293    /// );
294    /// assert_eq!(
295    ///     query.to_string(SqliteQueryBuilder),
296    ///     r#"WITH "cte" ("id") AS (SELECT "id" FROM "glyph" WHERE "image" LIKE '0%') DELETE FROM "glyph" WHERE "id" IN (SELECT "id" FROM "cte")"#
297    /// );
298    /// assert_eq!(
299    ///     query.audit_unwrap().deleted_tables(),
300    ///     [Glyph::Table.into_iden()]
301    /// );
302    /// assert_eq!(
303    ///     query.audit_unwrap().selected_tables(),
304    ///     [Glyph::Table.into_iden()]
305    /// );
306    /// ```
307    pub fn with_cte<C: Into<WithClause>>(&mut self, clause: C) -> &mut Self {
308        self.with = Some(clause.into());
309        self
310    }
311}
312
313#[inherent]
314impl QueryStatementBuilder for DeleteStatement {
315    pub fn build_collect_any_into(
316        &self,
317        query_builder: &impl QueryBuilder,
318        sql: &mut impl SqlWriter,
319    ) {
320        query_builder.prepare_delete_statement(self, sql);
321    }
322
323    pub fn build_any(&self, query_builder: &impl QueryBuilder) -> (String, Values);
324    pub fn build_collect_any(
325        &self,
326        query_builder: &impl QueryBuilder,
327        sql: &mut impl SqlWriter,
328    ) -> String;
329}
330
331impl From<DeleteStatement> for QueryStatement {
332    fn from(s: DeleteStatement) -> Self {
333        Self::Delete(s)
334    }
335}
336
337impl From<DeleteStatement> for SubQueryStatement {
338    fn from(s: DeleteStatement) -> Self {
339        Self::DeleteStatement(s)
340    }
341}
342
343#[inherent]
344impl QueryStatementWriter for DeleteStatement {
345    pub fn build_collect_into<T: QueryBuilder>(&self, query_builder: T, sql: &mut impl SqlWriter) {
346        query_builder.prepare_delete_statement(self, sql);
347    }
348
349    pub fn build_collect<T: QueryBuilder>(
350        &self,
351        query_builder: T,
352        sql: &mut impl SqlWriter,
353    ) -> String;
354    pub fn build<T: QueryBuilder>(&self, query_builder: T) -> (String, Values);
355    pub fn to_string<T: QueryBuilder>(&self, query_builder: T) -> String;
356}
357
358#[inherent]
359impl OrderedStatement for DeleteStatement {
360    pub fn add_order_by(&mut self, order: OrderExpr) -> &mut Self {
361        self.orders.push(order);
362        self
363    }
364
365    pub fn clear_order_by(&mut self) -> &mut Self {
366        self.orders = Vec::new();
367        self
368    }
369
370    pub fn order_by<T>(&mut self, col: T, order: Order) -> &mut Self
371    where
372        T: IntoColumnRef;
373
374    pub fn order_by_expr(&mut self, expr: Expr, order: Order) -> &mut Self;
375    pub fn order_by_customs<I, T>(&mut self, cols: I) -> &mut Self
376    where
377        T: Into<Cow<'static, str>>,
378        I: IntoIterator<Item = (T, Order)>;
379    pub fn order_by_columns<I, T>(&mut self, cols: I) -> &mut Self
380    where
381        T: IntoColumnRef,
382        I: IntoIterator<Item = (T, Order)>;
383    pub fn order_by_with_nulls<T>(
384        &mut self,
385        col: T,
386        order: Order,
387        nulls: NullOrdering,
388    ) -> &mut Self
389    where
390        T: IntoColumnRef;
391    pub fn order_by_expr_with_nulls(
392        &mut self,
393        expr: Expr,
394        order: Order,
395        nulls: NullOrdering,
396    ) -> &mut Self;
397    pub fn order_by_customs_with_nulls<I, T>(&mut self, cols: I) -> &mut Self
398    where
399        T: Into<Cow<'static, str>>,
400        I: IntoIterator<Item = (T, Order, NullOrdering)>;
401    pub fn order_by_columns_with_nulls<I, T>(&mut self, cols: I) -> &mut Self
402    where
403        T: IntoColumnRef,
404        I: IntoIterator<Item = (T, Order, NullOrdering)>;
405}
406
407#[inherent]
408impl ConditionalStatement for DeleteStatement {
409    pub fn and_or_where(&mut self, condition: LogicalChainOper) -> &mut Self {
410        self.r#where.add_and_or(condition);
411        self
412    }
413
414    pub fn cond_where<C>(&mut self, condition: C) -> &mut Self
415    where
416        C: IntoCondition,
417    {
418        self.r#where.add_condition(condition.into_condition());
419        self
420    }
421
422    pub fn and_where_option(&mut self, other: Option<Expr>) -> &mut Self;
423    pub fn and_where(&mut self, other: Expr) -> &mut Self;
424}