Skip to main content

sea_query/query/
delete.rs

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