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<'update, T> AsChangeset for &'update Option<T>
42where
43    &'update T: AsChangeset,
44{
45    type Target = <&'update T as AsChangeset>::Target;
46    type Changeset = Option<<&'update T as AsChangeset>::Changeset>;
47
48    fn as_changeset(self) -> Self::Changeset {
49        self.as_ref().map(AsChangeset::as_changeset)
50    }
51}
52
53impl<Left, Right> AsChangeset for Eq<Left, Right>
54where
55    Left: AssignmentTarget,
56    Right: AppearsOnTable<Left::Table>,
57{
58    type Target = Left::Table;
59    type Changeset = Assign<<Left as AssignmentTarget>::QueryAstNode, Right>;
60
61    fn as_changeset(self) -> Self::Changeset {
62        Assign {
63            target: self.left.into_target(),
64            expr: self.right,
65        }
66    }
67}
68
69impl<Left, Right> AsChangeset for Grouped<Eq<Left, Right>>
70where
71    Eq<Left, Right>: AsChangeset,
72{
73    type Target = <Eq<Left, Right> as AsChangeset>::Target;
74
75    type Changeset = <Eq<Left, Right> as AsChangeset>::Changeset;
76
77    fn as_changeset(self) -> Self::Changeset {
78        self.0.as_changeset()
79    }
80}
81
82#[derive(Debug, Clone, Copy, QueryId)]
83pub struct Assign<Target, Expr> {
84    target: Target,
85    expr: Expr,
86}
87
88impl<T, U, DB> QueryFragment<DB> for Assign<T, U>
89where
90    DB: Backend,
91    T: QueryFragment<DB>,
92    U: QueryFragment<DB>,
93{
94    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
95        QueryFragment::walk_ast(&self.target, out.reborrow())?;
96        out.push_sql(" = ");
97        QueryFragment::walk_ast(&self.expr, out.reborrow())
98    }
99}
100
101/// Represents the left hand side of an assignment expression for an
102/// assignment in [AsChangeset]. The vast majority of the time, this will
103/// be a [Column]. However, in certain database backends, it's possible to
104/// assign to an expression. For example, in Postgres, it's possible to
105/// "UPDATE TABLE SET array_column\[1\] = 'foo'".
106pub trait AssignmentTarget {
107    /// Table the assignment is to
108    type Table: Table;
109    /// A wrapper around a type to assign to (this wrapper should implement
110    /// [QueryFragment]).
111    type QueryAstNode;
112
113    /// Move this in to the AST node which should implement [QueryFragment].
114    fn into_target(self) -> Self::QueryAstNode;
115}
116
117/// Represents a `Column` as an `AssignmentTarget`. The vast majority of
118/// targets in an update statement will be `Column`s.
119#[derive(Debug, Clone, Copy)]
120pub struct ColumnWrapperForUpdate<C>(pub C);
121
122impl<DB, C> QueryFragment<DB> for ColumnWrapperForUpdate<C>
123where
124    DB: Backend + DieselReserveSpecialization,
125    C: Column,
126{
127    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
128        out.push_identifier(C::NAME)
129    }
130}
131
132impl<C> AssignmentTarget for C
133where
134    C: Column,
135{
136    type Table = C::Table;
137    type QueryAstNode = ColumnWrapperForUpdate<C>;
138
139    fn into_target(self) -> Self::QueryAstNode {
140        ColumnWrapperForUpdate(self)
141    }
142}