Skip to main content

diesel/query_builder/update_statement/
changeset.rs

1use super::{SetClause, batch_update::*};
2use crate::associations::HasTable;
3use crate::backend::DieselReserveSpecialization;
4use crate::expression::AppearsOnTable;
5use crate::expression::grouped::Grouped;
6use crate::expression::operators::Eq;
7use crate::query_builder::*;
8use crate::query_source::{Column, QuerySource};
9use crate::{Identifiable, Table};
10use alloc::borrow::ToOwned;
11
12/// Types which can be passed to
13/// [`update.set`](UpdateStatement::set()).
14///
15/// This trait can be [derived](derive@AsChangeset)
16pub trait AsChangeset {
17    /// The table which `Self::Changeset` will be updating
18    type Target: QuerySource;
19
20    /// The update statement this type represents
21    type Changeset;
22
23    /// Return the associated Update type. Defaults to Single row Updates.
24    #[doc(hidden)]
25    const SET_CLAUSE: SetClause = SetClause::Immediate;
26
27    /// Convert `self` into the actual update statement being executed
28    // This method is part of our public API
29    // we won't change it to just appease clippy
30    #[allow(clippy::wrong_self_convention)]
31    fn as_changeset(self) -> Self::Changeset;
32}
33
34// This is a false positive, we reexport it later
35#[allow(unreachable_pub)]
36#[doc(inline)]
37pub use diesel_derives::AsChangeset;
38
39impl<T: AsChangeset> AsChangeset for Option<T> {
40    type Target = T::Target;
41    type Changeset = Option<T::Changeset>;
42
43    fn as_changeset(self) -> Self::Changeset {
44        self.map(AsChangeset::as_changeset)
45    }
46}
47
48impl<'update, T> AsChangeset for &'update Option<T>
49where
50    &'update T: AsChangeset,
51{
52    type Target = <&'update T as AsChangeset>::Target;
53    type Changeset = Option<<&'update T as AsChangeset>::Changeset>;
54
55    fn as_changeset(self) -> Self::Changeset {
56        self.as_ref().map(AsChangeset::as_changeset)
57    }
58}
59
60impl<Left, Right> AsChangeset for Eq<Left, Right>
61where
62    Left: AssignmentTarget,
63    Right: AppearsOnTable<Left::Table>,
64{
65    type Target = Left::Table;
66    type Changeset = Assign<<Left as AssignmentTarget>::QueryAstNode, Right>;
67
68    fn as_changeset(self) -> Self::Changeset {
69        Assign {
70            target: self.left.into_target(),
71            expr: self.right,
72        }
73    }
74}
75
76impl<Left, Right> AsChangeset for Grouped<Eq<Left, Right>>
77where
78    Eq<Left, Right>: AsChangeset,
79{
80    type Target = <Eq<Left, Right> as AsChangeset>::Target;
81
82    type Changeset = <Eq<Left, Right> as AsChangeset>::Changeset;
83
84    fn as_changeset(self) -> Self::Changeset {
85        self.0.as_changeset()
86    }
87}
88
89#[derive(#[automatically_derived]
impl<Target: ::core::fmt::Debug, Expr: ::core::fmt::Debug> ::core::fmt::Debug
    for Assign<Target, Expr> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "Assign",
            "target", &self.target, "expr", &&self.expr)
    }
}Debug, #[automatically_derived]
impl<Target: ::core::clone::Clone, Expr: ::core::clone::Clone>
    ::core::clone::Clone for Assign<Target, Expr> {
    #[inline]
    fn clone(&self) -> Assign<Target, Expr> {
        Assign {
            target: ::core::clone::Clone::clone(&self.target),
            expr: ::core::clone::Clone::clone(&self.expr),
        }
    }
}Clone, #[automatically_derived]
impl<Target: ::core::marker::Copy, Expr: ::core::marker::Copy>
    ::core::marker::Copy for Assign<Target, Expr> {
}Copy, const _: () =
    {
        use diesel;
        #[allow(non_camel_case_types)]
        impl<Target: diesel::query_builder::QueryId,
            Expr: diesel::query_builder::QueryId>
            diesel::query_builder::QueryId for Assign<Target, Expr> {
            type QueryId =
                Assign<<Target as diesel::query_builder::QueryId>::QueryId,
                <Expr as diesel::query_builder::QueryId>::QueryId>;
            const HAS_STATIC_QUERY_ID: bool =
                <Target as
                            diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID &&
                        <Expr as
                            diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID &&
                    true;
            const IS_WINDOW_FUNCTION: bool =
                <Target as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION
                        ||
                        <Expr as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION
                    || false;
        }
    };QueryId)]
90pub struct Assign<Target, Expr> {
91    pub(crate) target: Target,
92    expr: Expr,
93}
94
95impl<T, U, DB> QueryFragment<DB> for Assign<T, U>
96where
97    DB: Backend,
98    T: QueryFragment<DB>,
99    U: QueryFragment<DB>,
100{
101    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
102        QueryFragment::walk_ast(&self.target, out.reborrow())?;
103        out.push_sql(" = ");
104        QueryFragment::walk_ast(&self.expr, out.reborrow())
105    }
106}
107
108/// Represents the left hand side of an assignment expression for an
109/// assignment in [AsChangeset]. The vast majority of the time, this will
110/// be a [Column]. However, in certain database backends, it's possible to
111/// assign to an expression. For example, in Postgres, it's possible to
112/// "UPDATE TABLE SET array_column\[1\] = 'foo'".
113pub trait AssignmentTarget {
114    /// Table the assignment is to
115    type Table: Table;
116    /// A wrapper around a type to assign to (this wrapper should implement
117    /// [QueryFragment]).
118    type QueryAstNode;
119
120    /// Move this in to the AST node which should implement [QueryFragment].
121    fn into_target(self) -> Self::QueryAstNode;
122}
123
124/// Represents a `Column` as an `AssignmentTarget`. The vast majority of
125/// targets in an update statement will be `Column`s.
126#[derive(#[automatically_derived]
impl<C: ::core::fmt::Debug> ::core::fmt::Debug for ColumnWrapperForUpdate<C> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "ColumnWrapperForUpdate", &&self.0)
    }
}Debug, #[automatically_derived]
impl<C: ::core::clone::Clone> ::core::clone::Clone for
    ColumnWrapperForUpdate<C> {
    #[inline]
    fn clone(&self) -> ColumnWrapperForUpdate<C> {
        ColumnWrapperForUpdate(::core::clone::Clone::clone(&self.0))
    }
}Clone, #[automatically_derived]
impl<C: ::core::marker::Copy> ::core::marker::Copy for
    ColumnWrapperForUpdate<C> {
}Copy)]
127pub struct ColumnWrapperForUpdate<C>(pub C);
128
129impl<DB, C> QueryFragment<DB> for ColumnWrapperForUpdate<C>
130where
131    DB: Backend + DieselReserveSpecialization,
132    C: Column,
133{
134    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
135        out.push_identifier(C::NAME)
136    }
137}
138
139impl<C> AssignmentTarget for C
140where
141    C: Column,
142{
143    type Table = C::Table;
144    type QueryAstNode = ColumnWrapperForUpdate<C>;
145
146    fn into_target(self) -> Self::QueryAstNode {
147        ColumnWrapperForUpdate(self)
148    }
149}
150
151#[cfg(any(
152    feature = "__sqlite-shared",
153    feature = "postgres_backend",
154    feature = "mysql_backend",
155    feature = "mariadb_backend"
156))]
157impl<C, T, DB> BatchValueHelper<DB> for Assign<ColumnWrapperForUpdate<C>, T>
158where
159    DB: Backend + DieselReserveSpecialization,
160    C: Column + QueryFragment<DB>,
161    T: QueryFragment<DB>,
162    Self: BatchAssignHelper<DB>,
163{
164    fn assign<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
165        self.batch_assign_identifier(out.reborrow())?;
166        out.push_sql(" = ");
167        out.push_identifier(BATCH_UPDATE_ALIAS)?;
168        out.push_sql(".");
169        out.push_identifier(C::NAME)?;
170        Ok(())
171    }
172
173    fn column_name<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
174        self.target.walk_ast(out)
175    }
176
177    fn bind_value<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
178        self.expr.walk_ast(out)
179    }
180}
181
182impl<'a, U, I, C, PK> AsChangeset for &'a [U]
183where
184    U: AsChangeset + HasTable<Table = U::Target>,
185    U::Target: Table<PrimaryKey = PK>,
186    &'a U: AsChangeset<Target = U::Target, Changeset = C> + Identifiable<Table = U::Target, Id = I>,
187{
188    type Target = U::Target;
189    type Changeset = BatchUpdate<I, C, PK, U::Target>;
190    const SET_CLAUSE: SetClause = SetClause::Delegated;
191
192    fn as_changeset(self) -> Self::Changeset {
193        let values = self
194            .iter()
195            .map(|value| (Identifiable::id(value), AsChangeset::as_changeset(value)))
196            .collect::<Vec<_>>();
197        BatchUpdate::new(values, U::table().primary_key())
198    }
199}
200
201impl<'a, U> AsChangeset for &'a Vec<U>
202where
203    U: AsChangeset,
204    &'a [U]: AsChangeset,
205{
206    type Target = U::Target;
207    type Changeset = <&'a [U] as AsChangeset>::Changeset;
208    const SET_CLAUSE: SetClause = <&'a [U] as AsChangeset>::SET_CLAUSE;
209
210    fn as_changeset(self) -> Self::Changeset {
211        (&**self).as_changeset()
212    }
213}
214
215impl<'a, U, const N: usize> AsChangeset for &'a [U; N]
216where
217    &'a [U]: AsChangeset,
218{
219    type Target = <&'a [U] as AsChangeset>::Target;
220    type Changeset = <&'a [U] as AsChangeset>::Changeset;
221    const SET_CLAUSE: SetClause = <&'a [U] as AsChangeset>::SET_CLAUSE;
222
223    fn as_changeset(self) -> Self::Changeset {
224        self.as_slice().as_changeset()
225    }
226}
227
228impl<U> AsChangeset for Vec<U>
229where
230    Box<[U]>: AsChangeset,
231{
232    type Target = <Box<[U]> as AsChangeset>::Target;
233    type Changeset = <Box<[U]> as AsChangeset>::Changeset;
234    const SET_CLAUSE: SetClause = <Box<[U]> as AsChangeset>::SET_CLAUSE;
235
236    fn as_changeset(self) -> Self::Changeset {
237        self.into_boxed_slice().as_changeset()
238    }
239}
240
241impl<U, const N: usize> AsChangeset for Box<[U; N]>
242where
243    Box<[U]>: AsChangeset,
244{
245    type Target = <Box<[U]> as AsChangeset>::Target;
246    type Changeset = <Box<[U]> as AsChangeset>::Changeset;
247    const SET_CLAUSE: SetClause = <Box<[U]> as AsChangeset>::SET_CLAUSE;
248
249    fn as_changeset(self) -> Self::Changeset {
250        (self as Box<[U]>).as_changeset()
251    }
252}
253
254impl<U, I, C, PK> AsChangeset for Box<[U]>
255where
256    U: AsChangeset<Changeset = C> + HasTable<Table = U::Target>,
257    U::Target: Table<PrimaryKey = PK>,
258    for<'a> &'a U: Identifiable<Id: IntoOwned<Owned = I>>,
259{
260    type Target = U::Target;
261    type Changeset = BatchUpdate<I, C, PK, U::Target>;
262    const SET_CLAUSE: SetClause = SetClause::Delegated;
263
264    fn as_changeset(self) -> Self::Changeset {
265        let values = self
266            .into_iter()
267            .map(|v| {
268                // this clone is not that great, but we do not have
269                // many other options. On the other hand the primary key
270                // is often cheap to clone, especially compared
271                // to sending an large set of updates to the DB, so it shouldn't
272                // matter that much
273                let id = v.id().into_owned();
274                let changes = v.as_changeset();
275                (id, changes)
276            })
277            .collect();
278        BatchUpdate::new(values, U::table().primary_key())
279    }
280}
281
282impl<U, I, C, PK, const N: usize> AsChangeset for [U; N]
283where
284    U: AsChangeset<Changeset = C> + HasTable<Table = U::Target>,
285    U::Target: Table<PrimaryKey = PK>,
286    for<'a> &'a U: Identifiable<Id: IntoOwned<Owned = I>>,
287{
288    type Target = U::Target;
289    type Changeset = BatchUpdate<I, C, PK, U::Target>;
290    const SET_CLAUSE: SetClause = SetClause::Delegated;
291
292    fn as_changeset(self) -> Self::Changeset {
293        let values = self
294            .into_iter()
295            .map(|v| {
296                // this clone is not that great, but we do not have
297                // many other options. On the other hand the primary key
298                // is often cheap to clone, especially compared
299                // to sending an large set of updates to the DB, so it shouldn't
300                // matter that much
301                let id = v.id().into_owned();
302                let changes = v.as_changeset();
303                (id, changes)
304            })
305            .collect();
306        BatchUpdate::new(values, U::table().primary_key())
307    }
308}
309
310pub(crate) trait IntoOwned {
311    type Owned;
312
313    fn into_owned(self) -> Self::Owned;
314}
315
316impl<T> IntoOwned for &T
317where
318    T: ToOwned,
319{
320    type Owned = T::Owned;
321
322    fn into_owned(self) -> Self::Owned {
323        (*self).to_owned()
324    }
325}