Skip to main content

drizzle_postgres/builder/
delete.rs

1//! `DELETE` builder states and clause methods.
2//!
3//! [`DeleteBuilder`] is the builder returned by `QueryBuilder::delete`.
4//! `WHERE` and `RETURNING` may only read the table being deleted from; this
5//! is checked at the method call.
6
7use crate::values::PostgresValue;
8use core::marker::PhantomData;
9use drizzle_core::ToSQL;
10
11//------------------------------------------------------------------------------
12// Type State Markers
13//------------------------------------------------------------------------------
14
15pub use drizzle_core::builder::{DeleteInitial, DeleteReturningSet, DeleteWhereSet};
16
17//------------------------------------------------------------------------------
18// DeleteBuilder Definition
19//------------------------------------------------------------------------------
20
21/// A `PostgreSQL` `DELETE` being built: a [`QueryBuilder`](super::QueryBuilder)
22/// in one of the `Delete*` states.
23///
24/// Optionally add `WHERE`, then `RETURNING`. Without `WHERE`, every row is
25/// deleted.
26///
27/// # Examples
28///
29/// ```rust
30/// # extern crate self as drizzle;
31/// # mod _drizzle {
32/// #     pub mod core { pub use drizzle_core::*; }
33/// #     pub mod error { pub use drizzle_core::error::*; }
34/// #     pub mod types { pub use drizzle_types::*; }
35/// #     pub mod migrations { pub use drizzle_migrations::*; }
36/// #     pub use drizzle_types::Dialect;
37/// #     pub use drizzle_types as ddl;
38/// #     pub mod postgres {
39/// #         pub mod values { pub use drizzle_postgres::values::*; }
40/// #         pub mod traits { pub use drizzle_postgres::traits::*; }
41/// #         pub mod common { pub use drizzle_postgres::common::*; }
42/// #         pub mod attrs { pub use drizzle_postgres::attrs::*; }
43/// #         pub mod builder { pub use drizzle_postgres::builder::*; }
44/// #         pub mod helpers { pub use drizzle_postgres::helpers::*; }
45/// #         pub mod expr { pub use drizzle_postgres::expr::*; }
46/// #         pub mod types { pub use drizzle_postgres::types::*; }
47/// #         #[cfg(feature = "aws-data-api")]
48/// #         pub mod aws_data_api { pub use drizzle_postgres::aws_data_api::*; }
49/// #         pub struct Row;
50/// #         impl Row {
51/// #             pub fn get<'a, I, T>(&'a self, _: I) -> T { unimplemented!() }
52/// #             pub fn try_get<'a, I, T>(&'a self, _: I) -> Result<T, Box<dyn std::error::Error + Sync + Send>> { unimplemented!() }
53/// #         }
54/// #         pub mod prelude {
55/// #             pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
56/// #             pub use drizzle_postgres::attrs::*;
57/// #             pub use drizzle_postgres::common::PostgresSchemaType;
58/// #             pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
59/// #             pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
60/// #             pub use drizzle_core::*;
61/// #         }
62/// #     }
63/// # }
64/// # pub use _drizzle::*;
65/// # pub use const_format;
66/// # fn main() {
67/// # use drizzle::postgres::prelude::*;
68/// # use drizzle::postgres::builder::QueryBuilder;
69/// # #[PostgresTable(name = "users")]
70/// # struct User {
71/// #     #[column(serial, primary)]
72/// #     id: i32,
73/// #     name: String,
74/// #     email: Option<String>,
75/// # }
76/// # #[PostgresTable(name = "posts")]
77/// # struct Post {
78/// #     #[column(serial, primary)]
79/// #     id: i32,
80/// #     #[column(references = User::id)]
81/// #     author_id: i32,
82/// #     title: String,
83/// # }
84/// # #[derive(PostgresSchema)]
85/// # struct Schema {
86/// #     user: User,
87/// #     post: Post,
88/// # }
89/// # let db = QueryBuilder::new::<Schema>();
90/// # let Schema { user, post } = Schema::new();
91/// use drizzle::core::expr::gt;
92///
93/// let query = db
94///     .delete(user)
95///     .r#where(gt(user.id, 10))
96///     .returning(user.id);
97/// assert_eq!(
98///     query.to_sql().sql(),
99///     r#"DELETE FROM "users" WHERE "users"."id" > $1 RETURNING "users"."id""#
100/// );
101/// # }
102/// ```
103pub type DeleteBuilder<'a, Schema, State, Table, Marker = (), Row = ()> =
104    super::QueryBuilder<'a, Schema, State, Table, Marker, Row>;
105
106type ReturningMarker<Table, Columns> = drizzle_core::Scoped<
107    <Columns as drizzle_core::IntoSelectTarget>::Marker,
108    drizzle_core::Cons<Table, drizzle_core::Nil>,
109>;
110
111type ReturningRow<Table, Columns> =
112    <<Columns as drizzle_core::IntoSelectTarget>::Marker as drizzle_core::ResolveRow<Table>>::Row;
113
114type ReturningBuilder<'a, S, T, Columns> = DeleteBuilder<
115    'a,
116    S,
117    DeleteReturningSet,
118    T,
119    ReturningMarker<T, Columns>,
120    ReturningRow<T, Columns>,
121>;
122
123//------------------------------------------------------------------------------
124// Initial State Implementation
125//------------------------------------------------------------------------------
126
127impl<'a, S, T> DeleteBuilder<'a, S, DeleteInitial, T> {
128    /// Adds a `WHERE` condition; only matching rows are deleted.
129    ///
130    /// # Compile-time checks
131    ///
132    /// The condition may only use columns of the table being deleted from.
133    ///
134    /// ```compile_fail
135    /// # extern crate self as drizzle;
136    /// # mod _drizzle {
137    /// #     pub mod core { pub use drizzle_core::*; }
138    /// #     pub mod error { pub use drizzle_core::error::*; }
139    /// #     pub mod types { pub use drizzle_types::*; }
140    /// #     pub mod migrations { pub use drizzle_migrations::*; }
141    /// #     pub use drizzle_types::Dialect;
142    /// #     pub use drizzle_types as ddl;
143    /// #     pub mod postgres {
144    /// #         pub mod values { pub use drizzle_postgres::values::*; }
145    /// #         pub mod traits { pub use drizzle_postgres::traits::*; }
146    /// #         pub mod common { pub use drizzle_postgres::common::*; }
147    /// #         pub mod attrs { pub use drizzle_postgres::attrs::*; }
148    /// #         pub mod builder { pub use drizzle_postgres::builder::*; }
149    /// #         pub mod helpers { pub use drizzle_postgres::helpers::*; }
150    /// #         pub mod expr { pub use drizzle_postgres::expr::*; }
151    /// #         pub mod types { pub use drizzle_postgres::types::*; }
152    /// #         #[cfg(feature = "aws-data-api")]
153    /// #         pub mod aws_data_api { pub use drizzle_postgres::aws_data_api::*; }
154    /// #         pub struct Row;
155    /// #         impl Row {
156    /// #             pub fn get<'a, I, T>(&'a self, _: I) -> T { unimplemented!() }
157    /// #             pub fn try_get<'a, I, T>(&'a self, _: I) -> Result<T, Box<dyn std::error::Error + Sync + Send>> { unimplemented!() }
158    /// #         }
159    /// #         pub mod prelude {
160    /// #             pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
161    /// #             pub use drizzle_postgres::attrs::*;
162    /// #             pub use drizzle_postgres::common::PostgresSchemaType;
163    /// #             pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
164    /// #             pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
165    /// #             pub use drizzle_core::*;
166    /// #         }
167    /// #     }
168    /// # }
169    /// # pub use _drizzle::*;
170    /// # pub use const_format;
171    /// # fn main() {
172    /// # use drizzle::postgres::prelude::*;
173    /// # use drizzle::postgres::builder::QueryBuilder;
174    /// # #[PostgresTable(name = "users")]
175    /// # struct User {
176    /// #     #[column(serial, primary)]
177    /// #     id: i32,
178    /// #     name: String,
179    /// #     email: Option<String>,
180    /// # }
181    /// # #[PostgresTable(name = "posts")]
182    /// # struct Post {
183    /// #     #[column(serial, primary)]
184    /// #     id: i32,
185    /// #     #[column(references = User::id)]
186    /// #     author_id: i32,
187    /// #     title: String,
188    /// # }
189    /// # #[derive(PostgresSchema)]
190    /// # struct Schema {
191    /// #     user: User,
192    /// #     post: Post,
193    /// # }
194    /// # let db = QueryBuilder::new::<Schema>();
195    /// # let Schema { user, post } = Schema::new();
196    /// use drizzle::core::expr::eq;
197    ///
198    /// // `posts` is not part of this statement.
199    /// let query = db.delete(user).r#where(eq(post.id, 1));
200    /// # }
201    /// ```
202    #[inline]
203    pub fn r#where<E, ScopeProof>(self, condition: E) -> DeleteBuilder<'a, S, DeleteWhereSet, T>
204    where
205        E: drizzle_core::expr::ExprSources,
206        E::Sources:
207            drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
208        E: drizzle_core::expr::Expr<'a, PostgresValue<'a>>,
209        E::SQLType: drizzle_core::types::BooleanLike,
210    {
211        let where_sql = crate::helpers::r#where(condition);
212        DeleteBuilder {
213            sql: self.sql.append(where_sql),
214            schema: PhantomData,
215            state: PhantomData,
216            table: PhantomData,
217            marker: PhantomData,
218            row: PhantomData,
219            grouped: PhantomData,
220        }
221    }
222
223    /// Adds `RETURNING columns`, so the statement returns the deleted rows.
224    #[inline]
225    pub fn returning<Columns, ScopeProof>(
226        self,
227        columns: Columns,
228    ) -> ReturningBuilder<'a, S, T, Columns>
229    where
230        Columns: drizzle_core::expr::ExprSources,
231        Columns::Sources:
232            drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
233        Columns: ToSQL<'a, PostgresValue<'a>> + drizzle_core::IntoSelectTarget,
234        Columns::Marker: drizzle_core::ResolveRow<T>,
235    {
236        let returning_sql = crate::helpers::returning(columns);
237        DeleteBuilder {
238            sql: self.sql.append(returning_sql),
239            schema: PhantomData,
240            state: PhantomData,
241            table: PhantomData,
242            marker: PhantomData,
243            row: PhantomData,
244            grouped: PhantomData,
245        }
246    }
247}
248
249//------------------------------------------------------------------------------
250// Post-WHERE Implementation
251//------------------------------------------------------------------------------
252
253impl<'a, S, T> DeleteBuilder<'a, S, DeleteWhereSet, T> {
254    /// Adds `RETURNING columns` after `WHERE`.
255    #[inline]
256    pub fn returning<Columns, ScopeProof>(
257        self,
258        columns: Columns,
259    ) -> ReturningBuilder<'a, S, T, Columns>
260    where
261        Columns: drizzle_core::expr::ExprSources,
262        Columns::Sources:
263            drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
264        Columns: ToSQL<'a, PostgresValue<'a>> + drizzle_core::IntoSelectTarget,
265        Columns::Marker: drizzle_core::ResolveRow<T>,
266    {
267        let returning_sql = crate::helpers::returning(columns);
268        DeleteBuilder {
269            sql: self.sql.append(returning_sql),
270            schema: PhantomData,
271            state: PhantomData,
272            table: PhantomData,
273            marker: PhantomData,
274            row: PhantomData,
275            grouped: PhantomData,
276        }
277    }
278}
279
280#[cfg(test)]
281mod tests {
282    use super::*;
283    use drizzle_core::{SQL, ToSQL};
284
285    #[test]
286    fn test_delete_builder_creation() {
287        let builder = DeleteBuilder::<(), DeleteInitial, ()> {
288            sql: SQL::raw("DELETE FROM test"),
289            schema: PhantomData,
290            state: PhantomData,
291            table: PhantomData,
292            marker: PhantomData,
293            row: PhantomData,
294            grouped: PhantomData,
295        };
296
297        assert_eq!(builder.to_sql().sql(), "DELETE FROM test");
298    }
299}