Skip to main content

drizzle_mysql/builder/
update.rs

1use crate::{common::MySQLSchemaType, values::MySQLValue};
2use drizzle_core::SQLTable;
3
4pub use drizzle_core::builder::{UpdateInitial, UpdateSetClauseSet, UpdateWhereSet};
5
6/// Builder state after `order_by` on an `UPDATE`.
7#[derive(Debug, Clone, Copy, Default)]
8pub struct UpdateOrderSet;
9
10/// Builder state after `limit` on an `UPDATE`.
11#[derive(Debug, Clone, Copy, Default)]
12pub struct UpdateLimitSet;
13
14impl drizzle_core::ExecutableState for UpdateOrderSet {
15    type Rows<R: drizzle_core::row::RowCount> = drizzle_core::row::ZeroOrMore;
16}
17impl drizzle_core::ExecutableState for UpdateLimitSet {
18    type Rows<R: drizzle_core::row::RowCount> = drizzle_core::row::ZeroOrMore;
19}
20
21/// An `UPDATE` query being built for `MySQL`.
22///
23/// This is [`QueryBuilder`](super::QueryBuilder) in one of the `Update*`
24/// states. Start it with [`QueryBuilder::update`](super::QueryBuilder::update).
25///
26/// # Clause order
27///
28/// 1. [`set`](Self::set) (required).
29/// 2. `where` (required): the rows to update. `r#where(true)` updates every
30///    row.
31/// 3. Optionally `order_by`, then optionally `limit`.
32///
33/// `prepare()` is available once `where` is set. The WHERE and ORDER BY may
34/// only reference the updated table; other tables do not compile. `MySQL`
35/// has no `RETURNING`.
36///
37/// # Examples
38///
39/// ```rust
40/// # let _ = r####"
41/// # use drizzle::core::expr::{alias, count, eq, gt};
42/// # use drizzle::mysql::{builder::QueryBuilder, prelude::*};
43/// # #[MySQLTable(NAME = "users")]
44/// # struct Users {
45/// #     #[column(PRIMARY, AUTO_INCREMENT)] id: u64,
46/// #     #[column(VARCHAR(255))] name: String,
47/// #     #[column(DEFAULT = true)] active: bool,
48/// # }
49/// # #[MySQLTable(NAME = "posts")]
50/// # struct Posts {
51/// #     #[column(PRIMARY, AUTO_INCREMENT)] id: u64,
52/// #     #[column(REFERENCES = Users::id)] user_id: u64,
53/// #     title: String,
54/// # }
55/// # #[MySQLIndex] struct UsersNameIdx(Users::name);
56/// # #[MySQLIndex] struct PostsUserIdIdx(Posts::user_id);
57/// # #[derive(MySQLSchema)] struct Schema { users: Users, posts: Posts }
58/// # let builder = QueryBuilder::new::<Schema>();
59/// # let Schema { users, posts } = Schema::new();
60/// let query = builder
61///     .update(users)
62///     .set(UpdateUsers::default().with_name("Bob"))
63///     .r#where(eq(users.active, true))
64///     .order_by(desc(users.id))
65///     .limit(1);
66/// assert_eq!(
67///     query.to_sql().sql(),
68///     "UPDATE `users` SET `name` = ? WHERE `users`.`active` = ? ORDER BY `users`.`id` DESC LIMIT ?"
69/// );
70/// # "####;
71/// ```
72pub type UpdateBuilder<'a, Schema, State, Table, Marker = (), Row = ()> =
73    super::QueryBuilder<'a, Schema, State, Table, Marker, Row>;
74
75impl<'a, Schema, Table> UpdateBuilder<'a, Schema, UpdateInitial, Table>
76where
77    Table: SQLTable<'a, MySQLSchemaType, MySQLValue<'a>>,
78{
79    /// Sets the columns to change, using the table's generated update model.
80    ///
81    /// Start from `UpdateX::default()` and call a `with_*` setter for each
82    /// column to change. Columns you do not set are left as they are.
83    pub fn set(
84        self,
85        values: Table::Update,
86    ) -> UpdateBuilder<'a, Schema, UpdateSetClauseSet, Table> {
87        let sql = crate::helpers::set::<Table, MySQLSchemaType, MySQLValue<'a>>(&values);
88        drop(values);
89        UpdateBuilder::from_sql(self.sql.append(sql))
90    }
91}
92
93impl<'a, S, T> UpdateBuilder<'a, S, UpdateSetClauseSet, T> {
94    /// Adds a WHERE clause that picks the rows to update.
95    ///
96    /// The condition must be a boolean expression over the updated table's
97    /// columns.
98    pub fn r#where<E, ScopeProof>(self, condition: E) -> UpdateBuilder<'a, S, UpdateWhereSet, T>
99    where
100        E: drizzle_core::expr::ExprSources,
101        E::Sources:
102            drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
103        E: drizzle_core::expr::Expr<'a, MySQLValue<'a>>,
104        E::SQLType: drizzle_core::types::BooleanLike,
105    {
106        UpdateBuilder::from_sql(self.sql.append(crate::helpers::r#where(condition)))
107    }
108}
109
110mutation_builder_methods!(
111    UpdateBuilder,
112    prepare: [UpdateWhereSet, UpdateOrderSet, UpdateLimitSet],
113    order_by: [UpdateWhereSet] => UpdateOrderSet,
114    limit: [UpdateWhereSet, UpdateOrderSet] => UpdateLimitSet,
115);