drizzle_sqlite/builder/
update.rs

1use crate::common::SQLiteSchemaType;
2use crate::traits::SQLiteTable;
3use crate::values::SQLiteValue;
4use drizzle_core::ToSQL;
5use std::fmt::Debug;
6use std::marker::PhantomData;
7
8// Import the ExecutableState trait
9use super::ExecutableState;
10
11//------------------------------------------------------------------------------
12// Type State Markers
13//------------------------------------------------------------------------------
14
15/// Marker for the initial state of UpdateBuilder
16#[derive(Debug, Clone, Copy, Default)]
17pub struct UpdateInitial;
18
19/// Marker for the state after SET clause
20#[derive(Debug, Clone, Copy, Default)]
21pub struct UpdateSetClauseSet;
22
23/// Marker for the state after WHERE clause
24#[derive(Debug, Clone, Copy, Default)]
25pub struct UpdateWhereSet;
26
27/// Marker for the state after RETURNING clause
28#[derive(Debug, Clone, Copy, Default)]
29pub struct UpdateReturningSet;
30
31// Mark states that can execute update queries
32impl ExecutableState for UpdateSetClauseSet {}
33impl ExecutableState for UpdateWhereSet {}
34impl ExecutableState for UpdateReturningSet {}
35
36//------------------------------------------------------------------------------
37// UpdateBuilder Definition
38//------------------------------------------------------------------------------
39
40/// Builds an UPDATE query specifically for SQLite.
41///
42/// `UpdateBuilder` provides a type-safe, fluent API for constructing UPDATE statements
43/// with support for conditional updates, returning clauses, and precise column targeting.
44///
45/// ## Type Parameters
46///
47/// - `Schema`: The database schema type, ensuring only valid tables can be referenced
48/// - `State`: The current builder state, enforcing proper query construction order
49/// - `Table`: The table being updated
50///
51/// ## Query Building Flow
52///
53/// 1. Start with `QueryBuilder::update(table)` to specify the target table
54/// 2. Add `set()` to specify which columns to update and their new values
55/// 3. Optionally add `where()` to limit which rows are updated
56/// 4. Optionally add `returning()` to get updated values back
57///
58/// ## Basic Usage
59///
60/// ```rust
61/// # mod drizzle {
62/// #     pub mod core { pub use drizzle_core::*; }
63/// #     pub mod error { pub use drizzle_core::error::*; }
64/// #     pub mod types { pub use drizzle_types::*; }
65/// #     pub mod migrations { pub use drizzle_migrations::*; }
66/// #     pub use drizzle_types::Dialect;
67/// #     pub use drizzle_types as ddl;
68/// #     pub mod sqlite {
69/// #         pub use drizzle_sqlite::*;
70/// #         pub mod prelude {
71/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
72/// #             pub use drizzle_sqlite::{*, attrs::*};
73/// #             pub use drizzle_core::*;
74/// #         }
75/// #     }
76/// # }
77/// use drizzle::sqlite::prelude::*;
78/// use drizzle::core::expr::eq;
79/// use drizzle::sqlite::builder::QueryBuilder;
80///
81/// #[SQLiteTable(name = "users")]
82/// struct User {
83///     #[column(primary)]
84///     id: i32,
85///     name: String,
86///     email: Option<String>,
87/// }
88///
89/// #[derive(SQLiteSchema)]
90/// struct Schema {
91///     user: User,
92/// }
93///
94/// let builder = QueryBuilder::new::<Schema>();
95/// let Schema { user } = Schema::new();
96///
97/// // Basic UPDATE
98/// let query = builder
99///     .update(user)
100///     .set(UpdateUser::default().with_name("Alice Updated"))
101///     .r#where(eq(user.id, 1));
102/// assert_eq!(
103///     query.to_sql().sql(),
104///     r#"UPDATE "users" SET "name" = ? WHERE "users"."id" = ?"#
105/// );
106/// ```
107///
108/// ## Advanced Updates
109///
110/// ### Multiple Column Updates
111/// ```rust,no_run
112/// # mod drizzle {
113/// #     pub mod core { pub use drizzle_core::*; }
114/// #     pub mod error { pub use drizzle_core::error::*; }
115/// #     pub mod types { pub use drizzle_types::*; }
116/// #     pub mod migrations { pub use drizzle_migrations::*; }
117/// #     pub use drizzle_types::Dialect;
118/// #     pub use drizzle_types as ddl;
119/// #     pub mod sqlite {
120/// #         pub use drizzle_sqlite::*;
121/// #         pub mod prelude {
122/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
123/// #             pub use drizzle_sqlite::{*, attrs::*};
124/// #             pub use drizzle_core::*;
125/// #         }
126/// #     }
127/// # }
128/// # use drizzle::sqlite::prelude::*;
129/// # use drizzle::core::expr::eq;
130/// # use drizzle::sqlite::builder::QueryBuilder;
131/// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String, email: Option<String> }
132/// # #[derive(SQLiteSchema)] struct Schema { user: User }
133/// # let builder = QueryBuilder::new::<Schema>();
134/// # let Schema { user } = Schema::new();
135/// let query = builder
136///     .update(user)
137///     .set(UpdateUser::default()
138///         .with_name("Alice Updated")
139///         .with_email("alice.new@example.com"))
140///     .r#where(eq(user.id, 1));
141/// ```
142///
143/// ### UPDATE with RETURNING
144/// ```rust,no_run
145/// # mod drizzle {
146/// #     pub mod core { pub use drizzle_core::*; }
147/// #     pub mod error { pub use drizzle_core::error::*; }
148/// #     pub mod types { pub use drizzle_types::*; }
149/// #     pub mod migrations { pub use drizzle_migrations::*; }
150/// #     pub use drizzle_types::Dialect;
151/// #     pub use drizzle_types as ddl;
152/// #     pub mod sqlite {
153/// #         pub use drizzle_sqlite::*;
154/// #         pub mod prelude {
155/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
156/// #             pub use drizzle_sqlite::{*, attrs::*};
157/// #             pub use drizzle_core::*;
158/// #         }
159/// #     }
160/// # }
161/// # use drizzle::sqlite::prelude::*;
162/// # use drizzle::core::expr::eq;
163/// # use drizzle::sqlite::builder::QueryBuilder;
164/// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String, age: Option<i32> }
165/// # #[derive(SQLiteSchema)] struct Schema { user: User }
166/// # let builder = QueryBuilder::new::<Schema>();
167/// # let Schema { user } = Schema::new();
168/// let query = builder
169///     .update(user)
170///     .set(UpdateUser::default().with_name("Alice Updated"))
171///     .r#where(eq(user.id, 1))
172///     .returning((user.id, user.name));
173/// ```
174pub type UpdateBuilder<'a, Schema, State, Table> = super::QueryBuilder<'a, Schema, State, Table>;
175
176//------------------------------------------------------------------------------
177// Initial State Implementation
178//------------------------------------------------------------------------------
179
180impl<'a, Schema, Table> UpdateBuilder<'a, Schema, UpdateInitial, Table>
181where
182    Table: SQLiteTable<'a>,
183{
184    /// Specifies which columns to update and their new values.
185    ///
186    /// This method accepts update expressions that specify which columns should
187    /// be modified. You can update single or multiple columns using condition
188    /// functions from `drizzle_core::expressions::conditions`.
189    ///
190    /// # Examples
191    ///
192    /// ```rust
193    /// # mod drizzle {
194    /// #     pub mod core { pub use drizzle_core::*; }
195    /// #     pub mod error { pub use drizzle_core::error::*; }
196    /// #     pub mod types { pub use drizzle_types::*; }
197    /// #     pub mod migrations { pub use drizzle_migrations::*; }
198    /// #     pub use drizzle_types::Dialect;
199    /// #     pub use drizzle_types as ddl;
200    /// #     pub mod sqlite {
201    /// #         pub use drizzle_sqlite::*;
202    /// #         pub mod prelude {
203    /// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
204    /// #             pub use drizzle_sqlite::{*, attrs::*};
205    /// #             pub use drizzle_core::*;
206    /// #         }
207    /// #     }
208    /// # }
209    /// # use drizzle::sqlite::prelude::*;
210    /// # use drizzle::sqlite::builder::QueryBuilder;
211    /// # use drizzle::core::{ToSQL, expr::{eq, and}};
212    /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String, email: Option<String> }
213    /// # #[derive(SQLiteSchema)] struct Schema { user: User }
214    /// # let builder = QueryBuilder::new::<Schema>();
215    /// # let Schema { user } = Schema::new();
216    /// // Update single column
217    /// let query = builder
218    ///     .update(user)
219    ///     .set(UpdateUser::default().with_name("New Name"));
220    /// assert_eq!(query.to_sql().sql(), r#"UPDATE "users" SET "name" = ?"#);
221    ///
222    /// // Update multiple columns
223    /// let query = builder
224    ///     .update(user)
225    ///     .set(UpdateUser::default().with_name("New Name").with_email("new@example.com"));
226    /// ```
227    #[inline]
228    pub fn set(
229        self,
230        values: Table::Update,
231    ) -> UpdateBuilder<'a, Schema, UpdateSetClauseSet, Table> {
232        let sql = crate::helpers::set::<'a, Table, SQLiteSchemaType, SQLiteValue<'a>>(values);
233        UpdateBuilder {
234            sql: self.sql.append(sql),
235            schema: PhantomData,
236            state: PhantomData,
237            table: PhantomData,
238        }
239    }
240}
241
242//------------------------------------------------------------------------------
243// Post-SET Implementation
244//------------------------------------------------------------------------------
245
246impl<'a, S, T> UpdateBuilder<'a, S, UpdateSetClauseSet, T> {
247    /// Adds a WHERE clause to specify which rows to update.
248    ///
249    /// Without a WHERE clause, all rows in the table would be updated. This method
250    /// allows you to specify conditions to limit which rows are affected by the update.
251    ///
252    /// # Examples
253    ///
254    /// ```rust
255    /// # mod drizzle {
256    /// #     pub mod core { pub use drizzle_core::*; }
257    /// #     pub mod error { pub use drizzle_core::error::*; }
258    /// #     pub mod types { pub use drizzle_types::*; }
259    /// #     pub mod migrations { pub use drizzle_migrations::*; }
260    /// #     pub use drizzle_types::Dialect;
261    /// #     pub use drizzle_types as ddl;
262    /// #     pub mod sqlite {
263    /// #         pub use drizzle_sqlite::*;
264    /// #         pub mod prelude {
265    /// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
266    /// #             pub use drizzle_sqlite::{*, attrs::*};
267    /// #             pub use drizzle_core::*;
268    /// #         }
269    /// #     }
270    /// # }
271    /// # use drizzle::sqlite::prelude::*;
272    /// # use drizzle::core::expr::{eq, gt, and};
273    /// # use drizzle::sqlite::builder::QueryBuilder;
274    /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String, age: Option<i32> }
275    /// # #[derive(SQLiteSchema)] struct Schema { user: User }
276    /// # let builder = QueryBuilder::new::<Schema>();
277    /// # let Schema { user } = Schema::new();
278    /// // Update specific row by ID
279    /// let query = builder
280    ///     .update(user)
281    ///     .set(UpdateUser::default().with_name("Updated Name"))
282    ///     .r#where(eq(user.id, 1));
283    /// assert_eq!(
284    ///     query.to_sql().sql(),
285    ///     r#"UPDATE "users" SET "name" = ? WHERE "users"."id" = ?"#
286    /// );
287    ///
288    /// // Update multiple rows with complex condition
289    /// let query = builder
290    ///     .update(user)
291    ///     .set(UpdateUser::default().with_name("Updated"))
292    ///     .r#where(and([gt(user.id, 10), eq(user.age, 25)]));
293    /// ```
294    #[inline]
295    pub fn r#where(
296        self,
297        condition: impl ToSQL<'a, SQLiteValue<'a>>,
298    ) -> UpdateBuilder<'a, S, UpdateWhereSet, T> {
299        let where_sql = crate::helpers::r#where(condition);
300        UpdateBuilder {
301            sql: self.sql.append(where_sql),
302            schema: PhantomData,
303            state: PhantomData,
304            table: PhantomData,
305        }
306    }
307
308    /// Adds a RETURNING clause and transitions to the ReturningSet state
309    #[inline]
310    pub fn returning(
311        self,
312        columns: impl ToSQL<'a, SQLiteValue<'a>>,
313    ) -> UpdateBuilder<'a, S, UpdateReturningSet, T> {
314        let returning_sql = crate::helpers::returning(columns);
315        UpdateBuilder {
316            sql: self.sql.append(returning_sql),
317            schema: PhantomData,
318            state: PhantomData,
319            table: PhantomData,
320        }
321    }
322}
323
324//------------------------------------------------------------------------------
325// Post-WHERE Implementation
326//------------------------------------------------------------------------------
327
328impl<'a, S, T> UpdateBuilder<'a, S, UpdateWhereSet, T> {
329    /// Adds a RETURNING clause after WHERE
330    #[inline]
331    pub fn returning(
332        self,
333        columns: impl ToSQL<'a, SQLiteValue<'a>>,
334    ) -> UpdateBuilder<'a, S, UpdateReturningSet, T> {
335        let returning_sql = crate::helpers::returning(columns);
336        UpdateBuilder {
337            sql: self.sql.append(returning_sql),
338            schema: PhantomData,
339            state: PhantomData,
340            table: PhantomData,
341        }
342    }
343}