drizzle_sqlite/builder/
delete.rs

1use crate::values::SQLiteValue;
2use drizzle_core::{SQL, ToSQL};
3use std::fmt::Debug;
4use std::marker::PhantomData;
5
6// Import the ExecutableState trait
7use super::ExecutableState;
8
9//------------------------------------------------------------------------------
10// Type State Markers
11//------------------------------------------------------------------------------
12
13/// Marker for the initial state of DeleteBuilder
14#[derive(Debug, Clone, Copy, Default)]
15pub struct DeleteInitial;
16
17/// Marker for the state after WHERE clause
18#[derive(Debug, Clone, Copy, Default)]
19pub struct DeleteWhereSet;
20
21/// Marker for the state after RETURNING clause
22#[derive(Debug, Clone, Copy, Default)]
23pub struct DeleteReturningSet;
24
25// Mark states that can execute delete queries
26impl ExecutableState for DeleteInitial {}
27impl ExecutableState for DeleteWhereSet {}
28impl ExecutableState for DeleteReturningSet {}
29
30//------------------------------------------------------------------------------
31// DeleteBuilder Definition
32//------------------------------------------------------------------------------
33
34/// Builds a DELETE query specifically for SQLite.
35///
36/// `DeleteBuilder` provides a type-safe, fluent API for constructing DELETE statements
37/// with support for conditional deletions and returning clauses.
38///
39/// ## Type Parameters
40///
41/// - `Schema`: The database schema type, ensuring only valid tables can be referenced
42/// - `State`: The current builder state, enforcing proper query construction order
43/// - `Table`: The table being deleted from
44///
45/// ## Query Building Flow
46///
47/// 1. Start with `QueryBuilder::delete(table)` to specify the target table
48/// 2. Optionally add `where()` to specify which rows to delete
49/// 3. Optionally add `returning()` to get deleted values back
50///
51/// ## Basic Usage
52///
53/// ```rust
54/// use drizzle_sqlite::builder::QueryBuilder;
55/// use drizzle_macros::{SQLiteTable, SQLiteSchema};
56/// use drizzle_core::{ToSQL, expressions::conditions::{eq, lt}};
57///
58/// #[SQLiteTable(name = "users")]
59/// struct User {
60///     #[integer(primary)]
61///     id: i32,
62///     #[text]
63///     name: String,
64///     #[text]
65///     email: Option<String>,
66/// }
67///
68/// #[derive(SQLiteSchema)]
69/// struct Schema {
70///     user: User,
71/// }
72///
73/// let builder = QueryBuilder::new::<Schema>();
74/// let Schema { user } = Schema::new();
75///
76/// // Delete specific row
77/// let query = builder
78///     .delete(user)
79///     .r#where(eq(user.id, 1));
80/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
81///
82/// // Delete multiple rows
83/// let query = builder
84///     .delete(user)
85///     .r#where(lt(user.id, 100));
86/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" < ?"#);
87/// ```
88///
89/// ## Advanced Deletions
90///
91/// ### DELETE with RETURNING
92/// ```rust
93/// # use drizzle_sqlite::builder::QueryBuilder;
94/// # use drizzle_macros::{SQLiteTable, SQLiteSchema};
95/// # use drizzle_core::{ToSQL, expressions::conditions::eq};
96/// # #[SQLiteTable(name = "users")] struct User { #[integer(primary)] id: i32, #[text] name: String }
97/// # #[derive(SQLiteSchema)] struct Schema { user: User }
98/// # let builder = QueryBuilder::new::<Schema>();
99/// # let Schema { user } = Schema::new();
100/// let query = builder
101///     .delete(user)
102///     .r#where(eq(user.id, 1))
103///     .returning((user.id, user.name));
104/// assert_eq!(
105///     query.to_sql().sql(),
106///     r#"DELETE FROM "users" WHERE "users"."id" = ? RETURNING "users"."id", "users"."name""#
107/// );
108/// ```
109///
110/// ### DELETE all rows (use with caution!)
111/// ```rust
112/// # use drizzle_sqlite::builder::QueryBuilder;
113/// # use drizzle_macros::{SQLiteTable, SQLiteSchema};
114/// # use drizzle_core::ToSQL;
115/// # #[SQLiteTable(name = "logs")] struct Log { #[integer(primary)] id: i32, #[text] message: String }
116/// # #[derive(SQLiteSchema)] struct Schema { log: Log }
117/// # let builder = QueryBuilder::new::<Schema>();
118/// # let Schema { log } = Schema::new();
119/// // This deletes ALL rows - be careful!
120/// let query = builder.delete(log);
121/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "logs""#);
122/// ```
123pub type DeleteBuilder<'a, Schema, State, Table> = super::QueryBuilder<'a, Schema, State, Table>;
124
125//------------------------------------------------------------------------------
126// Initial State Implementation
127//------------------------------------------------------------------------------
128
129impl<'a, S, T> DeleteBuilder<'a, S, DeleteInitial, T> {
130    /// Adds a WHERE clause to specify which rows to delete.
131    ///
132    /// **Warning**: Without a WHERE clause, ALL rows in the table will be deleted!
133    /// Always use this method unless you specifically intend to truncate the entire table.
134    ///
135    /// # Examples
136    ///
137    /// ```rust
138    /// # use drizzle_sqlite::builder::QueryBuilder;
139    /// # use drizzle_macros::{SQLiteTable, SQLiteSchema};
140    /// # use drizzle_core::{ToSQL, expressions::conditions::{eq, gt, and, or}};
141    /// # #[SQLiteTable(name = "users")] struct User { #[integer(primary)] id: i32, #[text] name: String, #[integer] age: Option<i32> }
142    /// # #[derive(SQLiteSchema)] struct Schema { user: User }
143    /// # let builder = QueryBuilder::new::<Schema>();
144    /// # let Schema { user } = Schema::new();
145    /// // Delete specific row by ID
146    /// let query = builder
147    ///     .delete(user)
148    ///     .r#where(eq(user.id, 1));
149    /// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
150    ///
151    /// // Delete with complex conditions
152    /// let query = builder
153    ///     .delete(user)
154    ///     .r#where(and([
155    ///         gt(user.id, 100),
156    ///         or([eq(user.name, "test"), eq(user.age, 0)])
157    ///     ]));
158    /// ```
159    #[inline]
160    pub fn r#where(
161        self,
162        condition: SQL<'a, SQLiteValue<'a>>,
163    ) -> DeleteBuilder<'a, S, DeleteWhereSet, T> {
164        let where_sql = crate::helpers::r#where(condition);
165        DeleteBuilder {
166            sql: self.sql.append(where_sql),
167            schema: PhantomData,
168            state: PhantomData,
169            table: PhantomData,
170        }
171    }
172
173    /// Adds a RETURNING clause to the query
174    #[inline]
175    pub fn returning(
176        self,
177        columns: impl ToSQL<'a, SQLiteValue<'a>>,
178    ) -> DeleteBuilder<'a, S, DeleteReturningSet, T> {
179        let returning_sql = crate::helpers::returning(columns);
180        DeleteBuilder {
181            sql: self.sql.append(returning_sql),
182            schema: PhantomData,
183            state: PhantomData,
184            table: PhantomData,
185        }
186    }
187}
188
189//------------------------------------------------------------------------------
190// Post-WHERE Implementation
191//------------------------------------------------------------------------------
192
193impl<'a, S, T> DeleteBuilder<'a, S, DeleteWhereSet, T> {
194    /// Adds a RETURNING clause after WHERE
195    #[inline]
196    pub fn returning(
197        self,
198        columns: impl ToSQL<'a, SQLiteValue<'a>>,
199    ) -> DeleteBuilder<'a, S, DeleteReturningSet, T> {
200        let returning_sql = crate::helpers::returning(columns);
201        DeleteBuilder {
202            sql: self.sql.append(returning_sql),
203            schema: PhantomData,
204            state: PhantomData,
205            table: PhantomData,
206        }
207    }
208}