Skip to main content

drizzle_sqlite/builder/
delete.rs

1use crate::values::SQLiteValue;
2use core::fmt::Debug;
3use core::marker::PhantomData;
4use drizzle_core::{SQL, ToSQL};
5
6// Import the ExecutableState trait
7use super::ExecutableState;
8
9#[inline]
10fn append_sql<'a>(
11    mut base: SQL<'a, SQLiteValue<'a>>,
12    fragment: SQL<'a, SQLiteValue<'a>>,
13) -> SQL<'a, SQLiteValue<'a>> {
14    base.append_mut(fragment);
15    base
16}
17
18//------------------------------------------------------------------------------
19// Type State Markers
20//------------------------------------------------------------------------------
21
22/// Marker for the initial state of `DeleteBuilder`
23#[derive(Debug, Clone, Copy, Default)]
24pub struct DeleteInitial;
25
26/// Marker for the state after WHERE clause
27#[derive(Debug, Clone, Copy, Default)]
28pub struct DeleteWhereSet;
29
30/// Marker for the state after RETURNING clause
31#[derive(Debug, Clone, Copy, Default)]
32pub struct DeleteReturningSet;
33
34// Mark states that can execute delete queries
35impl ExecutableState for DeleteInitial {}
36impl ExecutableState for DeleteWhereSet {}
37impl ExecutableState for DeleteReturningSet {}
38
39//------------------------------------------------------------------------------
40// DeleteBuilder Definition
41//------------------------------------------------------------------------------
42
43/// Builds a DELETE query specifically for `SQLite`.
44///
45/// `DeleteBuilder` provides a type-safe, fluent API for constructing DELETE statements
46/// with support for conditional deletions and returning clauses.
47///
48/// ## Type Parameters
49///
50/// - `Schema`: The database schema type, ensuring only valid tables can be referenced
51/// - `State`: The current builder state, enforcing proper query construction order
52/// - `Table`: The table being deleted from
53///
54/// ## Query Building Flow
55///
56/// 1. Start with `QueryBuilder::delete(table)` to specify the target table
57/// 2. Optionally add `where()` to specify which rows to delete
58/// 3. Optionally add `returning()` to get deleted values back
59///
60/// ## Basic Usage
61///
62/// ```rust
63/// # mod drizzle {
64/// #     pub mod core { pub use drizzle_core::*; }
65/// #     pub mod error { pub use drizzle_core::error::*; }
66/// #     pub mod types { pub use drizzle_types::*; }
67/// #     pub mod migrations { pub use drizzle_migrations::*; }
68/// #     pub use drizzle_types::Dialect;
69/// #     pub use drizzle_types as ddl;
70/// #     pub mod sqlite {
71/// #             pub use drizzle_sqlite::{*, attrs::*};
72/// #         pub mod prelude {
73/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
74/// #             pub use drizzle_sqlite::{*, attrs::*};
75/// #             pub use drizzle_core::*;
76/// #         }
77/// #     }
78/// # }
79/// use drizzle::sqlite::prelude::*;
80/// use drizzle::core::expr::{eq, lt};
81/// use drizzle::sqlite::builder::QueryBuilder;
82///
83/// #[SQLiteTable(name = "users")]
84/// struct User {
85///     #[column(primary)]
86///     id: i32,
87///     name: String,
88///     email: Option<String>,
89/// }
90///
91/// #[derive(SQLiteSchema)]
92/// struct Schema {
93///     user: User,
94/// }
95///
96/// let builder = QueryBuilder::new::<Schema>();
97/// let Schema { user } = Schema::new();
98///
99/// // Delete specific row
100/// let query = builder
101///     .delete(user)
102///     .r#where(eq(user.id, 1));
103/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
104///
105/// // Delete multiple rows
106/// let query = builder
107///     .delete(user)
108///     .r#where(lt(user.id, 100));
109/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" < ?"#);
110/// ```
111///
112/// ## Advanced Deletions
113///
114/// ### DELETE with RETURNING
115/// ```rust
116/// # mod drizzle {
117/// #     pub mod core { pub use drizzle_core::*; }
118/// #     pub mod error { pub use drizzle_core::error::*; }
119/// #     pub mod types { pub use drizzle_types::*; }
120/// #     pub mod migrations { pub use drizzle_migrations::*; }
121/// #     pub use drizzle_types::Dialect;
122/// #     pub use drizzle_types as ddl;
123/// #     pub mod sqlite {
124/// #             pub use drizzle_sqlite::{*, attrs::*};
125/// #         pub mod prelude {
126/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
127/// #             pub use drizzle_sqlite::{*, attrs::*};
128/// #             pub use drizzle_core::*;
129/// #         }
130/// #     }
131/// # }
132/// # use drizzle::sqlite::prelude::*;
133/// # use drizzle::core::expr::eq;
134/// # use drizzle::sqlite::builder::QueryBuilder;
135/// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String }
136/// # #[derive(SQLiteSchema)] struct Schema { user: User }
137/// # let builder = QueryBuilder::new::<Schema>();
138/// # let Schema { user } = Schema::new();
139/// let query = builder
140///     .delete(user)
141///     .r#where(eq(user.id, 1))
142///     .returning((user.id, user.name));
143/// assert_eq!(
144///     query.to_sql().sql(),
145///     r#"DELETE FROM "users" WHERE "users"."id" = ? RETURNING "users"."id", "users"."name""#
146/// );
147/// ```
148///
149/// ### DELETE all rows (use with caution!)
150/// ```rust
151/// # mod drizzle {
152/// #     pub mod core { pub use drizzle_core::*; }
153/// #     pub mod error { pub use drizzle_core::error::*; }
154/// #     pub mod types { pub use drizzle_types::*; }
155/// #     pub mod migrations { pub use drizzle_migrations::*; }
156/// #     pub use drizzle_types::Dialect;
157/// #     pub use drizzle_types as ddl;
158/// #     pub mod sqlite {
159/// #             pub use drizzle_sqlite::{*, attrs::*};
160/// #         pub mod prelude {
161/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
162/// #             pub use drizzle_sqlite::{*, attrs::*};
163/// #             pub use drizzle_core::*;
164/// #         }
165/// #     }
166/// # }
167/// # use drizzle::sqlite::prelude::*;
168/// # use drizzle::sqlite::builder::QueryBuilder;
169/// # #[SQLiteTable(name = "logs")] struct Log { #[column(primary)] id: i32, message: String }
170/// # #[derive(SQLiteSchema)] struct Schema { log: Log }
171/// # let builder = QueryBuilder::new::<Schema>();
172/// # let Schema { log } = Schema::new();
173/// // This deletes ALL rows - be careful!
174/// let query = builder.delete(log);
175/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "logs""#);
176/// ```
177pub type DeleteBuilder<'a, Schema, State, Table> = super::QueryBuilder<'a, Schema, State, Table>;
178
179//------------------------------------------------------------------------------
180// Initial State Implementation
181//------------------------------------------------------------------------------
182
183impl<'a, S, T> DeleteBuilder<'a, S, DeleteInitial, T> {
184    /// Adds a WHERE clause to specify which rows to delete.
185    ///
186    /// **Warning**: Without a WHERE clause, ALL rows in the table will be deleted!
187    /// Always use this method unless you specifically intend to truncate the entire table.
188    ///
189    /// # Examples
190    ///
191    /// ```rust
192    /// # mod drizzle {
193    /// #     pub mod core { pub use drizzle_core::*; }
194    /// #     pub mod error { pub use drizzle_core::error::*; }
195    /// #     pub mod types { pub use drizzle_types::*; }
196    /// #     pub mod migrations { pub use drizzle_migrations::*; }
197    /// #     pub use drizzle_types::Dialect;
198    /// #     pub use drizzle_types as ddl;
199    /// #     pub mod sqlite {
200    /// #         pub use drizzle_sqlite::*;
201    /// #         pub mod prelude {
202    /// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
203    /// #             pub use drizzle_sqlite::{*, attrs::*};
204    /// #             pub use drizzle_core::*;
205    /// #         }
206    /// #     }
207    /// # }
208    /// # use drizzle::sqlite::prelude::*;
209    /// # use drizzle::core::expr::{eq, gt, and, or};
210    /// # use drizzle::sqlite::builder::QueryBuilder;
211    /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String, age: Option<i32> }
212    /// # #[derive(SQLiteSchema)] struct Schema { user: User }
213    /// # let builder = QueryBuilder::new::<Schema>();
214    /// # let Schema { user } = Schema::new();
215    /// // Delete specific row by ID
216    /// let query = builder
217    ///     .delete(user)
218    ///     .r#where(eq(user.id, 1));
219    /// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
220    ///
221    /// // Delete with complex conditions
222    /// let query = builder
223    ///     .delete(user)
224    ///     .r#where(and(
225    ///         gt(user.id, 100),
226    ///         or(eq(user.name, "test"), eq(user.age, 0))
227    ///     ));
228    /// ```
229    #[inline]
230    pub fn r#where<E>(self, condition: E) -> DeleteBuilder<'a, S, DeleteWhereSet, T>
231    where
232        E: drizzle_core::expr::Expr<'a, SQLiteValue<'a>>,
233        E::SQLType: drizzle_core::types::BooleanLike,
234    {
235        let where_sql = crate::helpers::r#where(condition);
236        DeleteBuilder {
237            sql: append_sql(self.sql, where_sql),
238            schema: PhantomData,
239            state: PhantomData,
240            table: PhantomData,
241            marker: PhantomData,
242            row: PhantomData,
243            grouped: PhantomData,
244        }
245    }
246
247    /// Adds a RETURNING clause to the query
248    #[inline]
249    pub fn returning(
250        self,
251        columns: impl ToSQL<'a, SQLiteValue<'a>>,
252    ) -> DeleteBuilder<'a, S, DeleteReturningSet, T> {
253        let returning_sql = crate::helpers::returning(columns);
254        DeleteBuilder {
255            sql: append_sql(self.sql, returning_sql),
256            schema: PhantomData,
257            state: PhantomData,
258            table: PhantomData,
259            marker: PhantomData,
260            row: PhantomData,
261            grouped: PhantomData,
262        }
263    }
264}
265
266//------------------------------------------------------------------------------
267// Post-WHERE Implementation
268//------------------------------------------------------------------------------
269
270impl<'a, S, T> DeleteBuilder<'a, S, DeleteWhereSet, T> {
271    /// Adds a RETURNING clause after WHERE
272    #[inline]
273    pub fn returning(
274        self,
275        columns: impl ToSQL<'a, SQLiteValue<'a>>,
276    ) -> DeleteBuilder<'a, S, DeleteReturningSet, T> {
277        let returning_sql = crate::helpers::returning(columns);
278        DeleteBuilder {
279            sql: append_sql(self.sql, returning_sql),
280            schema: PhantomData,
281            state: PhantomData,
282            table: PhantomData,
283            marker: PhantomData,
284            row: PhantomData,
285            grouped: PhantomData,
286        }
287    }
288}