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][crate::CommonTableExpression]
263 /// or [WithClause] to execute this query with.
264 ///
265 /// # Examples
266 ///
267 /// ```
268 /// use sea_query::{IntoCondition, IntoIden, audit::*, tests_cfg::*, *};
269 ///
270 /// let select = SelectStatement::new()
271 /// .columns([Glyph::Id])
272 /// .from(Glyph::Table)
273 /// .and_where(Expr::col(Glyph::Image).like("0%"))
274 /// .to_owned();
275 /// let cte = CommonTableExpression::new()
276 /// .query(select)
277 /// .column(Glyph::Id)
278 /// .table_name("cte")
279 /// .to_owned();
280 /// let with_clause = WithClause::new().cte(cte).to_owned();
281 /// let query = DeleteStatement::new()
282 /// .with_cte(with_clause)
283 /// .from_table(Glyph::Table)
284 /// .and_where(Expr::col(Glyph::Id).in_subquery(SelectStatement::new().column(Glyph::Id).from("cte").to_owned()))
285 /// .to_owned();
286 ///
287 /// assert_eq!(
288 /// query.to_string(MysqlQueryBuilder),
289 /// r#"WITH `cte` (`id`) AS (SELECT `id` FROM `glyph` WHERE `image` LIKE '0%') DELETE FROM `glyph` WHERE `id` IN (SELECT `id` FROM `cte`)"#
290 /// );
291 /// assert_eq!(
292 /// query.to_string(PostgresQueryBuilder),
293 /// r#"WITH "cte" ("id") AS (SELECT "id" FROM "glyph" WHERE "image" LIKE '0%') DELETE FROM "glyph" WHERE "id" IN (SELECT "id" FROM "cte")"#
294 /// );
295 /// assert_eq!(
296 /// query.to_string(SqliteQueryBuilder),
297 /// r#"WITH "cte" ("id") AS (SELECT "id" FROM "glyph" WHERE "image" LIKE '0%') DELETE FROM "glyph" WHERE "id" IN (SELECT "id" FROM "cte")"#
298 /// );
299 /// assert_eq!(
300 /// query.audit_unwrap().deleted_tables(),
301 /// [Glyph::Table.into_iden()]
302 /// );
303 /// assert_eq!(
304 /// query.audit_unwrap().selected_tables(),
305 /// [Glyph::Table.into_iden()]
306 /// );
307 /// ```
308 pub fn with_cte<C: Into<WithClause>>(&mut self, clause: C) -> &mut Self {
309 self.with = Some(clause.into());
310 self
311 }
312}
313
314#[inherent]
315impl QueryStatementBuilder for DeleteStatement {
316 pub fn build_collect_any_into(
317 &self,
318 query_builder: &impl QueryBuilder,
319 sql: &mut impl SqlWriter,
320 ) {
321 query_builder.prepare_delete_statement(self, sql);
322 }
323
324 pub fn build_any(&self, query_builder: &impl QueryBuilder) -> (String, Values);
325 pub fn build_collect_any(
326 &self,
327 query_builder: &impl QueryBuilder,
328 sql: &mut impl SqlWriter,
329 ) -> String;
330}
331
332impl From<DeleteStatement> for QueryStatement {
333 fn from(s: DeleteStatement) -> Self {
334 Self::Delete(s)
335 }
336}
337
338impl From<DeleteStatement> for SubQueryStatement {
339 fn from(s: DeleteStatement) -> Self {
340 Self::DeleteStatement(s)
341 }
342}
343
344#[inherent]
345impl QueryStatementWriter for DeleteStatement {
346 pub fn build_collect_into<T: QueryBuilder>(&self, query_builder: T, sql: &mut impl SqlWriter) {
347 query_builder.prepare_delete_statement(self, sql);
348 }
349
350 pub fn build_collect<T: QueryBuilder>(
351 &self,
352 query_builder: T,
353 sql: &mut impl SqlWriter,
354 ) -> String;
355 pub fn build<T: QueryBuilder>(&self, query_builder: T) -> (String, Values);
356 pub fn to_string<T: QueryBuilder>(&self, query_builder: T) -> String;
357}
358
359#[inherent]
360impl OrderedStatement for DeleteStatement {
361 pub fn add_order_by(&mut self, order: OrderExpr) -> &mut Self {
362 self.orders.push(order);
363 self
364 }
365
366 pub fn clear_order_by(&mut self) -> &mut Self {
367 self.orders = Vec::new();
368 self
369 }
370
371 pub fn order_by<T>(&mut self, col: T, order: Order) -> &mut Self
372 where
373 T: IntoColumnRef;
374
375 pub fn order_by_expr(&mut self, expr: Expr, order: Order) -> &mut Self;
376 pub fn order_by_customs<I, T>(&mut self, cols: I) -> &mut Self
377 where
378 T: Into<Cow<'static, str>>,
379 I: IntoIterator<Item = (T, Order)>;
380 pub fn order_by_columns<I, T>(&mut self, cols: I) -> &mut Self
381 where
382 T: IntoColumnRef,
383 I: IntoIterator<Item = (T, Order)>;
384 pub fn order_by_with_nulls<T>(
385 &mut self,
386 col: T,
387 order: Order,
388 nulls: NullOrdering,
389 ) -> &mut Self
390 where
391 T: IntoColumnRef;
392 pub fn order_by_expr_with_nulls(
393 &mut self,
394 expr: Expr,
395 order: Order,
396 nulls: NullOrdering,
397 ) -> &mut Self;
398 pub fn order_by_customs_with_nulls<I, T>(&mut self, cols: I) -> &mut Self
399 where
400 T: Into<Cow<'static, str>>,
401 I: IntoIterator<Item = (T, Order, NullOrdering)>;
402 pub fn order_by_columns_with_nulls<I, T>(&mut self, cols: I) -> &mut Self
403 where
404 T: IntoColumnRef,
405 I: IntoIterator<Item = (T, Order, NullOrdering)>;
406}
407
408#[inherent]
409impl ConditionalStatement for DeleteStatement {
410 pub fn and_or_where(&mut self, condition: LogicalChainOper) -> &mut Self {
411 self.r#where.add_and_or(condition);
412 self
413 }
414
415 pub fn cond_where<C>(&mut self, condition: C) -> &mut Self
416 where
417 C: IntoCondition,
418 {
419 self.r#where.add_condition(condition.into_condition());
420 self
421 }
422
423 pub fn and_where_option(&mut self, other: Option<Expr>) -> &mut Self;
424 pub fn and_where(&mut self, other: Expr) -> &mut Self;
425}