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