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/// Add `WHERE` (required; `r#where(true)` deletes every row), then
25/// optionally `RETURNING`.
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/// #             pub fn len(&self) -> usize { unimplemented!() }
54/// #         }
55/// #         pub mod prelude {
56/// #             pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
57/// #             pub use drizzle_postgres::attrs::*;
58/// #             pub use drizzle_postgres::common::PostgresSchemaType;
59/// #             pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
60/// #             pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
61/// #             pub use drizzle_core::*;
62/// #         }
63/// #     }
64/// # }
65/// # pub use _drizzle::*;
66/// # pub use const_format;
67/// # fn main() {
68/// # use drizzle::postgres::prelude::*;
69/// # use drizzle::postgres::builder::QueryBuilder;
70/// # #[PostgresTable(name = "users")]
71/// # struct User {
72/// #     #[column(serial, primary)]
73/// #     id: i32,
74/// #     name: String,
75/// #     email: Option<String>,
76/// # }
77/// # #[PostgresTable(name = "posts")]
78/// # struct Post {
79/// #     #[column(serial, primary)]
80/// #     id: i32,
81/// #     #[column(references = User::id)]
82/// #     author_id: i32,
83/// #     title: String,
84/// # }
85/// # #[derive(PostgresSchema)]
86/// # struct Schema {
87/// #     user: User,
88/// #     post: Post,
89/// # }
90/// # let db = QueryBuilder::new::<Schema>();
91/// # let Schema { user, post } = Schema::new();
92/// use drizzle::core::expr::gt;
93///
94/// let query = db
95///     .delete(user)
96///     .r#where(gt(user.id, 10))
97///     .returning(user.id);
98/// assert_eq!(
99///     query.to_sql().sql(),
100///     r#"DELETE FROM "users" WHERE "users"."id" > $1 RETURNING "users"."id""#
101/// );
102/// # }
103/// ```
104pub type DeleteBuilder<'a, Schema, State, Table, Marker = (), Row = ()> =
105    super::QueryBuilder<'a, Schema, State, Table, Marker, Row>;
106
107type ReturningMarker<Table, Columns> = drizzle_core::Scoped<
108    <Columns as drizzle_core::IntoSelectTarget>::Marker,
109    drizzle_core::Cons<Table, drizzle_core::Nil>,
110>;
111
112type ReturningRow<Table, Columns> =
113    <<Columns as drizzle_core::IntoSelectTarget>::Marker as drizzle_core::ResolveRow<Table>>::Row;
114
115type ReturningBuilder<'a, S, T, Columns> = DeleteBuilder<
116    'a,
117    S,
118    DeleteReturningSet,
119    T,
120    ReturningMarker<T, Columns>,
121    ReturningRow<T, Columns>,
122>;
123
124//------------------------------------------------------------------------------
125// Initial State Implementation
126//------------------------------------------------------------------------------
127
128impl<'a, S, T> DeleteBuilder<'a, S, DeleteInitial, T> {
129    /// Adds a `WHERE` condition; only matching rows are deleted.
130    ///
131    /// # Compile-time checks
132    ///
133    /// The condition may only use columns of the table being deleted from.
134    ///
135    /// ```compile_fail
136    /// # extern crate self as drizzle;
137    /// # mod _drizzle {
138    /// #     pub mod core { pub use drizzle_core::*; }
139    /// #     pub mod error { pub use drizzle_core::error::*; }
140    /// #     pub mod types { pub use drizzle_types::*; }
141    /// #     pub mod migrations { pub use drizzle_migrations::*; }
142    /// #     pub use drizzle_types::Dialect;
143    /// #     pub use drizzle_types as ddl;
144    /// #     pub mod postgres {
145    /// #         pub mod values { pub use drizzle_postgres::values::*; }
146    /// #         pub mod traits { pub use drizzle_postgres::traits::*; }
147    /// #         pub mod common { pub use drizzle_postgres::common::*; }
148    /// #         pub mod attrs { pub use drizzle_postgres::attrs::*; }
149    /// #         pub mod builder { pub use drizzle_postgres::builder::*; }
150    /// #         pub mod helpers { pub use drizzle_postgres::helpers::*; }
151    /// #         pub mod expr { pub use drizzle_postgres::expr::*; }
152    /// #         pub mod types { pub use drizzle_postgres::types::*; }
153    /// #         #[cfg(feature = "aws-data-api")]
154    /// #         pub mod aws_data_api { pub use drizzle_postgres::aws_data_api::*; }
155    /// #         pub struct Row;
156    /// #         impl Row {
157    /// #             pub fn get<'a, I, T>(&'a self, _: I) -> T { unimplemented!() }
158    /// #             pub fn try_get<'a, I, T>(&'a self, _: I) -> Result<T, Box<dyn std::error::Error + Sync + Send>> { unimplemented!() }
159    /// #             pub fn len(&self) -> usize { unimplemented!() }
160    /// #         }
161    /// #         pub mod prelude {
162    /// #             pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
163    /// #             pub use drizzle_postgres::attrs::*;
164    /// #             pub use drizzle_postgres::common::PostgresSchemaType;
165    /// #             pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
166    /// #             pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
167    /// #             pub use drizzle_core::*;
168    /// #         }
169    /// #     }
170    /// # }
171    /// # pub use _drizzle::*;
172    /// # pub use const_format;
173    /// # fn main() {
174    /// # use drizzle::postgres::prelude::*;
175    /// # use drizzle::postgres::builder::QueryBuilder;
176    /// # #[PostgresTable(name = "users")]
177    /// # struct User {
178    /// #     #[column(serial, primary)]
179    /// #     id: i32,
180    /// #     name: String,
181    /// #     email: Option<String>,
182    /// # }
183    /// # #[PostgresTable(name = "posts")]
184    /// # struct Post {
185    /// #     #[column(serial, primary)]
186    /// #     id: i32,
187    /// #     #[column(references = User::id)]
188    /// #     author_id: i32,
189    /// #     title: String,
190    /// # }
191    /// # #[derive(PostgresSchema)]
192    /// # struct Schema {
193    /// #     user: User,
194    /// #     post: Post,
195    /// # }
196    /// # let db = QueryBuilder::new::<Schema>();
197    /// # let Schema { user, post } = Schema::new();
198    /// use drizzle::core::expr::eq;
199    ///
200    /// // `posts` is not part of this statement.
201    /// let query = db.delete(user).r#where(eq(post.id, 1));
202    /// # }
203    /// ```
204    #[inline]
205    pub fn r#where<E, ScopeProof>(self, condition: E) -> DeleteBuilder<'a, S, DeleteWhereSet, T>
206    where
207        E: drizzle_core::expr::ExprSources,
208        E::Sources:
209            drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
210        E: drizzle_core::expr::Expr<'a, PostgresValue<'a>>,
211        E::SQLType: drizzle_core::types::BooleanLike,
212    {
213        let where_sql = crate::helpers::r#where(condition);
214        DeleteBuilder {
215            sql: self.sql.append(where_sql),
216            schema: PhantomData,
217            state: PhantomData,
218            table: PhantomData,
219            marker: PhantomData,
220            row: PhantomData,
221            grouped: PhantomData,
222        }
223    }
224}
225
226//------------------------------------------------------------------------------
227// Post-WHERE Implementation
228//------------------------------------------------------------------------------
229
230impl<'a, S, T> DeleteBuilder<'a, S, DeleteWhereSet, T> {
231    /// Adds `RETURNING columns` after `WHERE`.
232    #[inline]
233    pub fn returning<Columns, ScopeProof>(
234        self,
235        columns: Columns,
236    ) -> ReturningBuilder<'a, S, T, Columns>
237    where
238        Columns: drizzle_core::expr::ExprSources,
239        Columns::Sources:
240            drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
241        Columns: ToSQL<'a, PostgresValue<'a>> + drizzle_core::IntoSelectTarget,
242        Columns::Marker: drizzle_core::ResolveRow<T>,
243    {
244        let returning_sql = crate::helpers::returning(columns);
245        DeleteBuilder {
246            sql: self.sql.append(returning_sql),
247            schema: PhantomData,
248            state: PhantomData,
249            table: PhantomData,
250            marker: PhantomData,
251            row: PhantomData,
252            grouped: PhantomData,
253        }
254    }
255}
256
257#[cfg(test)]
258mod tests {
259    use super::*;
260    use drizzle_core::{SQL, ToSQL};
261
262    #[test]
263    fn test_delete_builder_creation() {
264        let builder = DeleteBuilder::<(), DeleteInitial, ()> {
265            sql: SQL::raw("DELETE FROM test"),
266            schema: PhantomData,
267            state: PhantomData,
268            table: PhantomData,
269            marker: PhantomData,
270            row: PhantomData,
271            grouped: PhantomData,
272        };
273
274        assert_eq!(builder.to_sql().sql(), "DELETE FROM test");
275    }
276}