Skip to main content

drizzle_sqlite/builder/
delete.rs

1//! The DELETE builder: [`DeleteBuilder`] and its states.
2//!
3//! Start a DELETE with [`QueryBuilder::delete`](super::QueryBuilder::delete).
4
5use crate::values::SQLiteValue;
6use core::marker::PhantomData;
7use drizzle_core::ToSQL;
8
9//------------------------------------------------------------------------------
10// Type State Markers
11//------------------------------------------------------------------------------
12
13pub use drizzle_core::builder::{DeleteInitial, DeleteReturningSet, DeleteWhereSet};
14
15//------------------------------------------------------------------------------
16// DeleteBuilder Definition
17//------------------------------------------------------------------------------
18
19/// A DELETE query being built for `SQLite`.
20///
21/// This is [`QueryBuilder`](super::QueryBuilder) in one of the `Delete*`
22/// states. Start it with [`QueryBuilder::delete`](super::QueryBuilder::delete).
23///
24/// # Clause order
25///
26/// 1. Optionally `where`. Without it, every row is deleted.
27/// 2. Optionally [`returning`](Self::returning).
28///
29/// The WHERE condition and the RETURNING columns may only reference the
30/// table being deleted from; other tables do not compile.
31///
32/// # Examples
33///
34/// ```rust
35/// # mod drizzle {
36/// #     pub mod core { pub use drizzle_core::*; }
37/// #     pub mod error { pub use drizzle_core::error::*; }
38/// #     pub mod types { pub use drizzle_types::*; }
39/// #     pub mod migrations { pub use drizzle_migrations::*; }
40/// #     pub use drizzle_types::Dialect;
41/// #     pub use drizzle_types as ddl;
42/// #     pub mod sqlite {
43/// #             pub use drizzle_sqlite::{*, attrs::*};
44/// #             #[cfg(feature = "rusqlite")]
45/// #             pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
46/// #             #[cfg(feature = "libsql")]
47/// #             pub mod libsql { pub use ::libsql::{Row, Value}; }
48/// #             #[cfg(feature = "turso")]
49/// #             pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
50/// #         pub mod prelude {
51/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
52/// #             pub use drizzle_sqlite::{*, attrs::*};
53/// #             pub use drizzle_core::*;
54/// #         }
55/// #     }
56/// # }
57/// use drizzle::sqlite::prelude::*;
58/// use drizzle::core::expr::{eq, lt};
59/// use drizzle::sqlite::builder::QueryBuilder;
60///
61/// #[SQLiteTable(name = "users")]
62/// struct User {
63///     #[column(primary)]
64///     id: i32,
65///     name: String,
66///     email: Option<String>,
67/// }
68///
69/// #[derive(SQLiteSchema)]
70/// struct Schema {
71///     user: User,
72/// }
73///
74/// let builder = QueryBuilder::new::<Schema>();
75/// let Schema { user } = Schema::new();
76///
77/// // Delete specific row
78/// let query = builder
79///     .delete(user)
80///     .r#where(eq(user.id, 1));
81/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
82///
83/// // Delete multiple rows
84/// let query = builder
85///     .delete(user)
86///     .r#where(lt(user.id, 100));
87/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" < ?"#);
88/// ```
89///
90/// With RETURNING:
91///
92/// ```rust
93/// # mod drizzle {
94/// #     pub mod core { pub use drizzle_core::*; }
95/// #     pub mod error { pub use drizzle_core::error::*; }
96/// #     pub mod types { pub use drizzle_types::*; }
97/// #     pub mod migrations { pub use drizzle_migrations::*; }
98/// #     pub use drizzle_types::Dialect;
99/// #     pub use drizzle_types as ddl;
100/// #     pub mod sqlite {
101/// #             pub use drizzle_sqlite::{*, attrs::*};
102/// #             #[cfg(feature = "rusqlite")]
103/// #             pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
104/// #             #[cfg(feature = "libsql")]
105/// #             pub mod libsql { pub use ::libsql::{Row, Value}; }
106/// #             #[cfg(feature = "turso")]
107/// #             pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
108/// #         pub mod prelude {
109/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
110/// #             pub use drizzle_sqlite::{*, attrs::*};
111/// #             pub use drizzle_core::*;
112/// #         }
113/// #     }
114/// # }
115/// # use drizzle::sqlite::prelude::*;
116/// # use drizzle::core::expr::eq;
117/// # use drizzle::sqlite::builder::QueryBuilder;
118/// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String }
119/// # #[derive(SQLiteSchema)] struct Schema { user: User }
120/// # let builder = QueryBuilder::new::<Schema>();
121/// # let Schema { user } = Schema::new();
122/// let query = builder
123///     .delete(user)
124///     .r#where(eq(user.id, 1))
125///     .returning((user.id, user.name));
126/// assert_eq!(
127///     query.to_sql().sql(),
128///     r#"DELETE FROM "users" WHERE "users"."id" = ? RETURNING "users"."id", "users"."name""#
129/// );
130/// ```
131///
132/// Without WHERE, every row is deleted:
133///
134/// ```rust
135/// # mod drizzle {
136/// #     pub mod core { pub use drizzle_core::*; }
137/// #     pub mod error { pub use drizzle_core::error::*; }
138/// #     pub mod types { pub use drizzle_types::*; }
139/// #     pub mod migrations { pub use drizzle_migrations::*; }
140/// #     pub use drizzle_types::Dialect;
141/// #     pub use drizzle_types as ddl;
142/// #     pub mod sqlite {
143/// #             pub use drizzle_sqlite::{*, attrs::*};
144/// #             #[cfg(feature = "rusqlite")]
145/// #             pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
146/// #             #[cfg(feature = "libsql")]
147/// #             pub mod libsql { pub use ::libsql::{Row, Value}; }
148/// #             #[cfg(feature = "turso")]
149/// #             pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
150/// #         pub mod prelude {
151/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
152/// #             pub use drizzle_sqlite::{*, attrs::*};
153/// #             pub use drizzle_core::*;
154/// #         }
155/// #     }
156/// # }
157/// # use drizzle::sqlite::prelude::*;
158/// # use drizzle::sqlite::builder::QueryBuilder;
159/// # #[SQLiteTable(name = "logs")] struct Log { #[column(primary)] id: i32, message: String }
160/// # #[derive(SQLiteSchema)] struct Schema { log: Log }
161/// # let builder = QueryBuilder::new::<Schema>();
162/// # let Schema { log } = Schema::new();
163/// let query = builder.delete(log);
164/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "logs""#);
165/// ```
166pub type DeleteBuilder<'a, Schema, State, Table, Marker = (), Row = ()> =
167    super::QueryBuilder<'a, Schema, State, Table, Marker, Row>;
168
169type ReturningMarker<Table, Columns> = drizzle_core::Scoped<
170    <Columns as drizzle_core::IntoSelectTarget>::Marker,
171    drizzle_core::Cons<Table, drizzle_core::Nil>,
172>;
173
174type ReturningRow<Table, Columns> =
175    <<Columns as drizzle_core::IntoSelectTarget>::Marker as drizzle_core::ResolveRow<Table>>::Row;
176
177type ReturningBuilder<'a, S, T, Columns> = DeleteBuilder<
178    'a,
179    S,
180    DeleteReturningSet,
181    T,
182    ReturningMarker<T, Columns>,
183    ReturningRow<T, Columns>,
184>;
185
186//------------------------------------------------------------------------------
187// Initial State Implementation
188//------------------------------------------------------------------------------
189
190impl<'a, S, T> DeleteBuilder<'a, S, DeleteInitial, T> {
191    /// Adds a WHERE clause that picks the rows to delete.
192    ///
193    /// Without it, every row in the table is deleted. The condition must be a
194    /// boolean expression over the target table's columns.
195    ///
196    /// # Examples
197    ///
198    /// ```rust
199    /// # mod drizzle {
200    /// #     pub mod core { pub use drizzle_core::*; }
201    /// #     pub mod error { pub use drizzle_core::error::*; }
202    /// #     pub mod types { pub use drizzle_types::*; }
203    /// #     pub mod migrations { pub use drizzle_migrations::*; }
204    /// #     pub use drizzle_types::Dialect;
205    /// #     pub use drizzle_types as ddl;
206    /// #     pub mod sqlite {
207    /// #         pub use drizzle_sqlite::*;
208    /// #         #[cfg(feature = "rusqlite")]
209    /// #         pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
210    /// #         #[cfg(feature = "libsql")]
211    /// #         pub mod libsql { pub use ::libsql::{Row, Value}; }
212    /// #         #[cfg(feature = "turso")]
213    /// #         pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
214    /// #         pub mod prelude {
215    /// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
216    /// #             pub use drizzle_sqlite::{*, attrs::*};
217    /// #             pub use drizzle_core::*;
218    /// #         }
219    /// #     }
220    /// # }
221    /// # use drizzle::sqlite::prelude::*;
222    /// # use drizzle::core::expr::{eq, gt, and, or};
223    /// # use drizzle::sqlite::builder::QueryBuilder;
224    /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String, age: Option<i32> }
225    /// # #[derive(SQLiteSchema)] struct Schema { user: User }
226    /// # let builder = QueryBuilder::new::<Schema>();
227    /// # let Schema { user } = Schema::new();
228    /// // Delete specific row by ID
229    /// let query = builder
230    ///     .delete(user)
231    ///     .r#where(eq(user.id, 1));
232    /// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
233    ///
234    /// // Delete with complex conditions
235    /// let query = builder
236    ///     .delete(user)
237    ///     .r#where(and(
238    ///         gt(user.id, 100),
239    ///         or(eq(user.name, "test"), eq(user.age, 0))
240    ///     ));
241    /// assert_eq!(
242    ///     query.to_sql().sql(),
243    ///     r#"DELETE FROM "users" WHERE ("users"."id" > ? AND ("users"."name" = ? OR "users"."age" = ?))"#
244    /// );
245    /// ```
246    #[inline]
247    pub fn r#where<E, ScopeProof>(self, condition: E) -> DeleteBuilder<'a, S, DeleteWhereSet, T>
248    where
249        E: drizzle_core::expr::ExprSources,
250        E::Sources:
251            drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
252        E: drizzle_core::expr::Expr<'a, SQLiteValue<'a>>,
253        E::SQLType: drizzle_core::types::BooleanLike,
254    {
255        let where_sql = crate::helpers::r#where(condition);
256        DeleteBuilder {
257            sql: self.sql.append(where_sql),
258            schema: PhantomData,
259            state: PhantomData,
260            table: PhantomData,
261            marker: PhantomData,
262            row: PhantomData,
263            grouped: PhantomData,
264        }
265    }
266
267    /// Adds a RETURNING clause that reads columns of the deleted rows.
268    ///
269    /// Pass one column or expression, a tuple, or `()` for every column.
270    /// Only columns of the target table may be used.
271    #[inline]
272    pub fn returning<Columns, ScopeProof>(
273        self,
274        columns: Columns,
275    ) -> ReturningBuilder<'a, S, T, Columns>
276    where
277        Columns: drizzle_core::expr::ExprSources,
278        Columns::Sources:
279            drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
280        Columns: ToSQL<'a, SQLiteValue<'a>> + drizzle_core::IntoSelectTarget,
281        Columns::Marker: drizzle_core::ResolveRow<T>,
282    {
283        let returning_sql = crate::helpers::returning(columns);
284        DeleteBuilder {
285            sql: self.sql.append(returning_sql),
286            schema: PhantomData,
287            state: PhantomData,
288            table: PhantomData,
289            marker: PhantomData,
290            row: PhantomData,
291            grouped: PhantomData,
292        }
293    }
294}
295
296//------------------------------------------------------------------------------
297// Post-WHERE Implementation
298//------------------------------------------------------------------------------
299
300impl<'a, S, T> DeleteBuilder<'a, S, DeleteWhereSet, T> {
301    /// Adds a RETURNING clause after WHERE. See
302    /// [`returning`](DeleteBuilder::returning).
303    #[inline]
304    pub fn returning<Columns, ScopeProof>(
305        self,
306        columns: Columns,
307    ) -> ReturningBuilder<'a, S, T, Columns>
308    where
309        Columns: drizzle_core::expr::ExprSources,
310        Columns::Sources:
311            drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
312        Columns: ToSQL<'a, SQLiteValue<'a>> + drizzle_core::IntoSelectTarget,
313        Columns::Marker: drizzle_core::ResolveRow<T>,
314    {
315        let returning_sql = crate::helpers::returning(columns);
316        DeleteBuilder {
317            sql: self.sql.append(returning_sql),
318            schema: PhantomData,
319            state: PhantomData,
320            table: PhantomData,
321            marker: PhantomData,
322            row: PhantomData,
323            grouped: PhantomData,
324        }
325    }
326}