sea_query/query/delete.rs
1use crate::{
2 Expr, QueryStatement, QueryStatementBuilder, QueryStatementWriter, ReturningClause,
3 SubQueryStatement, WithClause, WithQuery,
4 backend::QueryBuilder,
5 prepare::*,
6 query::{OrderedStatement, condition::*},
7 types::*,
8 value::*,
9};
10use inherent::inherent;
11
12/// Delete existing rows from the table
13///
14/// # Examples
15///
16/// ```
17/// use sea_query::{tests_cfg::*, *};
18///
19/// let query = Query::delete()
20/// .from_table(Glyph::Table)
21/// .cond_where(any![
22/// Expr::col(Glyph::Id).lt(1),
23/// Expr::col(Glyph::Id).gt(10),
24/// ])
25/// .to_owned();
26///
27/// assert_eq!(
28/// query.to_string(MysqlQueryBuilder),
29/// r#"DELETE FROM `glyph` WHERE `id` < 1 OR `id` > 10"#
30/// );
31/// assert_eq!(
32/// query.to_string(PostgresQueryBuilder),
33/// r#"DELETE FROM "glyph" WHERE "id" < 1 OR "id" > 10"#
34/// );
35/// assert_eq!(
36/// query.to_string(SqliteQueryBuilder),
37/// r#"DELETE FROM "glyph" WHERE "id" < 1 OR "id" > 10"#
38/// );
39/// ```
40#[derive(Default, Debug, Clone, PartialEq)]
41pub struct DeleteStatement {
42 pub(crate) table: Option<Box<TableRef>>,
43 pub(crate) r#where: ConditionHolder,
44 pub(crate) orders: Vec<OrderExpr>,
45 pub(crate) limit: Option<Value>,
46 pub(crate) returning: Option<ReturningClause>,
47 pub(crate) with: Option<WithClause>,
48}
49
50impl DeleteStatement {
51 /// Construct a new [`DeleteStatement`]
52 pub fn new() -> Self {
53 Self::default()
54 }
55
56 pub fn take(&mut self) -> Self {
57 Self {
58 table: self.table.take(),
59 r#where: std::mem::take(&mut self.r#where),
60 orders: std::mem::take(&mut self.orders),
61 limit: self.limit.take(),
62 returning: self.returning.take(),
63 with: self.with.take(),
64 }
65 }
66
67 /// Specify which table to delete from.
68 ///
69 /// # Examples
70 ///
71 /// ```
72 /// use sea_query::{audit::*, tests_cfg::*, *};
73 ///
74 /// let query = Query::delete()
75 /// .from_table(Glyph::Table)
76 /// .and_where(Expr::col(Glyph::Id).eq(1))
77 /// .to_owned();
78 ///
79 /// assert_eq!(
80 /// query.to_string(MysqlQueryBuilder),
81 /// r#"DELETE FROM `glyph` WHERE `id` = 1"#
82 /// );
83 /// assert_eq!(
84 /// query.to_string(PostgresQueryBuilder),
85 /// r#"DELETE FROM "glyph" WHERE "id" = 1"#
86 /// );
87 /// assert_eq!(
88 /// query.to_string(SqliteQueryBuilder),
89 /// r#"DELETE FROM "glyph" WHERE "id" = 1"#
90 /// );
91 /// assert_eq!(
92 /// query.audit_unwrap().deleted_tables(),
93 /// [Glyph::Table.into_iden()]
94 /// );
95 /// assert_eq!(query.audit_unwrap().selected_tables(), []);
96 /// ```
97 #[allow(clippy::wrong_self_convention)]
98 pub fn from_table<T>(&mut self, tbl_ref: T) -> &mut Self
99 where
100 T: IntoTableRef,
101 {
102 self.table = Some(Box::new(tbl_ref.into_table_ref()));
103 self
104 }
105
106 /// Limit number of updated rows.
107 pub fn limit(&mut self, limit: u64) -> &mut Self {
108 self.limit = Some(limit.into());
109 self
110 }
111
112 /// RETURNING expressions.
113 ///
114 /// # Examples
115 ///
116 /// ```
117 /// use sea_query::{audit::*, tests_cfg::*, *};
118 ///
119 /// let query = Query::delete()
120 /// .from_table(Glyph::Table)
121 /// .and_where(Expr::col(Glyph::Id).eq(1))
122 /// .returning(Query::returning().columns([Glyph::Id]))
123 /// .to_owned();
124 ///
125 /// assert_eq!(
126 /// query.to_string(MysqlQueryBuilder),
127 /// r#"DELETE FROM `glyph` WHERE `id` = 1"#
128 /// );
129 /// assert_eq!(
130 /// query.to_string(PostgresQueryBuilder),
131 /// r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING "id""#
132 /// );
133 /// assert_eq!(
134 /// query.to_string(SqliteQueryBuilder),
135 /// r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING "id""#
136 /// );
137 /// assert_eq!(
138 /// query.audit_unwrap().deleted_tables(),
139 /// [Glyph::Table.into_iden()]
140 /// );
141 /// assert_eq!(
142 /// query.audit_unwrap().selected_tables(),
143 /// [Glyph::Table.into_iden()]
144 /// );
145 /// ```
146 pub fn returning(&mut self, returning_cols: ReturningClause) -> &mut Self {
147 self.returning = Some(returning_cols);
148 self
149 }
150
151 /// RETURNING expressions for a column.
152 ///
153 /// # Examples
154 ///
155 /// ```
156 /// use sea_query::{tests_cfg::*, *};
157 ///
158 /// let query = Query::delete()
159 /// .from_table(Glyph::Table)
160 /// .and_where(Expr::col(Glyph::Id).eq(1))
161 /// .returning_col(Glyph::Id)
162 /// .to_owned();
163 ///
164 /// assert_eq!(
165 /// query.to_string(MysqlQueryBuilder),
166 /// r#"DELETE FROM `glyph` WHERE `id` = 1"#
167 /// );
168 /// assert_eq!(
169 /// query.to_string(PostgresQueryBuilder),
170 /// r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING "id""#
171 /// );
172 /// assert_eq!(
173 /// query.to_string(SqliteQueryBuilder),
174 /// r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING "id""#
175 /// );
176 /// ```
177 pub fn returning_col<C>(&mut self, col: C) -> &mut Self
178 where
179 C: IntoColumnRef,
180 {
181 self.returning(ReturningClause::Columns(vec![col.into_column_ref()]))
182 }
183
184 /// RETURNING expressions all columns.
185 ///
186 /// # Examples
187 ///
188 /// ```
189 /// use sea_query::{tests_cfg::*, *};
190 ///
191 /// let query = Query::delete()
192 /// .from_table(Glyph::Table)
193 /// .and_where(Expr::col(Glyph::Id).eq(1))
194 /// .returning_all()
195 /// .to_owned();
196 ///
197 /// assert_eq!(
198 /// query.to_string(MysqlQueryBuilder),
199 /// r#"DELETE FROM `glyph` WHERE `id` = 1"#
200 /// );
201 /// assert_eq!(
202 /// query.to_string(PostgresQueryBuilder),
203 /// r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING *"#
204 /// );
205 /// assert_eq!(
206 /// query.to_string(SqliteQueryBuilder),
207 /// r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING *"#
208 /// );
209 /// ```
210 pub fn returning_all(&mut self) -> &mut Self {
211 self.returning(ReturningClause::All)
212 }
213
214 /// Create a [WithQuery] by specifying a [WithClause] to execute this query with.
215 ///
216 /// # Examples
217 ///
218 /// ```
219 /// use sea_query::{IntoCondition, IntoIden, audit::*, tests_cfg::*, *};
220 ///
221 /// let select = SelectStatement::new()
222 /// .columns([Glyph::Id])
223 /// .from(Glyph::Table)
224 /// .and_where(Expr::col(Glyph::Image).like("0%"))
225 /// .to_owned();
226 /// let cte = CommonTableExpression::new()
227 /// .query(select)
228 /// .column(Glyph::Id)
229 /// .table_name("cte")
230 /// .to_owned();
231 /// let with_clause = WithClause::new().cte(cte).to_owned();
232 /// let update = DeleteStatement::new()
233 /// .from_table(Glyph::Table)
234 /// .and_where(Expr::col(Glyph::Id).in_subquery(SelectStatement::new().column(Glyph::Id).from("cte").to_owned()))
235 /// .to_owned();
236 /// let query = update.with(with_clause);
237 ///
238 /// assert_eq!(
239 /// query.to_string(MysqlQueryBuilder),
240 /// r#"WITH `cte` (`id`) AS (SELECT `id` FROM `glyph` WHERE `image` LIKE '0%') DELETE FROM `glyph` WHERE `id` IN (SELECT `id` FROM `cte`)"#
241 /// );
242 /// assert_eq!(
243 /// query.to_string(PostgresQueryBuilder),
244 /// r#"WITH "cte" ("id") AS (SELECT "id" FROM "glyph" WHERE "image" LIKE '0%') DELETE FROM "glyph" WHERE "id" IN (SELECT "id" FROM "cte")"#
245 /// );
246 /// assert_eq!(
247 /// query.to_string(SqliteQueryBuilder),
248 /// r#"WITH "cte" ("id") AS (SELECT "id" FROM "glyph" WHERE "image" LIKE '0%') DELETE FROM "glyph" WHERE "id" IN (SELECT "id" FROM "cte")"#
249 /// );
250 /// assert_eq!(
251 /// query.audit_unwrap().deleted_tables(),
252 /// [Glyph::Table.into_iden()]
253 /// );
254 /// assert_eq!(
255 /// query.audit_unwrap().selected_tables(),
256 /// [Glyph::Table.into_iden()]
257 /// );
258 /// ```
259 pub fn with(self, clause: WithClause) -> WithQuery {
260 clause.query(self)
261 }
262
263 /// Create a Common Table Expression by specifying a [CommonTableExpression] 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: &dyn QueryBuilder,
319 sql: &mut dyn SqlWriter,
320 ) {
321 query_builder.prepare_delete_statement(self, sql);
322 }
323
324 pub fn build_any(&self, query_builder: &dyn QueryBuilder) -> (String, Values);
325 pub fn build_collect_any(
326 &self,
327 query_builder: &dyn QueryBuilder,
328 sql: &mut dyn 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 dyn 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 dyn 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: ToString,
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: ToString,
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}