diesel/query_builder/update_statement/
changeset.rs1use 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
12pub trait AsChangeset {
17 type Target: QuerySource;
19
20 type Changeset;
22
23 #[doc(hidden)]
25 const SET_CLAUSE: SetClause = SetClause::Immediate;
26
27 #[allow(clippy::wrong_self_convention)]
31 fn as_changeset(self) -> Self::Changeset;
32}
33
34#[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
108pub trait AssignmentTarget {
114 type Table: Table;
116 type QueryAstNode;
119
120 fn into_target(self) -> Self::QueryAstNode;
122}
123
124#[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 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 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}