diesel/query_builder/update_statement/
changeset.rs

1use crate::backend::DieselReserveSpecialization;
2use crate::expression::grouped::Grouped;
3use crate::expression::operators::Eq;
4use crate::expression::AppearsOnTable;
5use crate::query_builder::*;
6use crate::query_source::{Column, QuerySource};
7use crate::Table;
8
9/// Types which can be passed to
10/// [`update.set`](UpdateStatement::set()).
11///
12/// This trait can be [derived](derive@AsChangeset)
13pub trait AsChangeset {
14    /// The table which `Self::Changeset` will be updating
15    type Target: QuerySource;
16
17    /// The update statement this type represents
18    type Changeset;
19
20    /// Convert `self` into the actual update statement being executed
21    // This method is part of our public API
22    // we won't change it to just appease clippy
23    #[allow(clippy::wrong_self_convention)]
24    fn as_changeset(self) -> Self::Changeset;
25}
26
27// This is a false positive, we reexport it later
28#[allow(unreachable_pub)]
29#[doc(inline)]
30pub use diesel_derives::AsChangeset;
31
32impl<T: AsChangeset> AsChangeset for Option<T> {
33    type Target = T::Target;
34    type Changeset = Option<T::Changeset>;
35
36    fn as_changeset(self) -> Self::Changeset {
37        self.map(AsChangeset::as_changeset)
38    }
39}
40
41impl<Left, Right> AsChangeset for Eq<Left, Right>
42where
43    Left: AssignmentTarget,
44    Right: AppearsOnTable<Left::Table>,
45{
46    type Target = Left::Table;
47    type Changeset = Assign<<Left as AssignmentTarget>::QueryAstNode, Right>;
48
49    fn as_changeset(self) -> Self::Changeset {
50        Assign {
51            target: self.left.into_target(),
52            expr: self.right,
53        }
54    }
55}
56
57impl<Left, Right> AsChangeset for Grouped<Eq<Left, Right>>
58where
59    Eq<Left, Right>: AsChangeset,
60{
61    type Target = <Eq<Left, Right> as AsChangeset>::Target;
62
63    type Changeset = <Eq<Left, Right> as AsChangeset>::Changeset;
64
65    fn as_changeset(self) -> Self::Changeset {
66        self.0.as_changeset()
67    }
68}
69
70#[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)]
71pub struct Assign<Target, Expr> {
72    target: Target,
73    expr: Expr,
74}
75
76impl<T, U, DB> QueryFragment<DB> for Assign<T, U>
77where
78    DB: Backend,
79    T: QueryFragment<DB>,
80    U: QueryFragment<DB>,
81{
82    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
83        QueryFragment::walk_ast(&self.target, out.reborrow())?;
84        out.push_sql(" = ");
85        QueryFragment::walk_ast(&self.expr, out.reborrow())
86    }
87}
88
89/// Represents the left hand side of an assignment expression for an
90/// assignment in [AsChangeset]. The vast majority of the time, this will
91/// be a [Column]. However, in certain database backends, it's possible to
92/// assign to an expression. For example, in Postgres, it's possible to
93/// "UPDATE TABLE SET array_column\[1\] = 'foo'".
94pub trait AssignmentTarget {
95    /// Table the assignment is to
96    type Table: Table;
97    /// A wrapper around a type to assign to (this wrapper should implement
98    /// [QueryFragment]).
99    type QueryAstNode;
100
101    /// Move this in to the AST node which should implement [QueryFragment].
102    fn into_target(self) -> Self::QueryAstNode;
103}
104
105/// Represents a `Column` as an `AssignmentTarget`. The vast majority of
106/// targets in an update statement will be `Column`s.
107#[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)]
108pub struct ColumnWrapperForUpdate<C>(pub C);
109
110impl<DB, C> QueryFragment<DB> for ColumnWrapperForUpdate<C>
111where
112    DB: Backend + DieselReserveSpecialization,
113    C: Column,
114{
115    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
116        out.push_identifier(C::NAME)
117    }
118}
119
120impl<C> AssignmentTarget for C
121where
122    C: Column,
123{
124    type Table = C::Table;
125    type QueryAstNode = ColumnWrapperForUpdate<C>;
126
127    fn into_target(self) -> Self::QueryAstNode {
128        ColumnWrapperForUpdate(self)
129    }
130}