1pub(crate) mod batch_update;
2pub(crate) mod changeset;
3pub(super) mod target;
4
5use private::AllowFilterForUpdate;
6
7use crate::QuerySource;
8use crate::backend::DieselReserveSpecialization;
9use crate::dsl::{Filter, IntoBoxed, IntoBoxedClone};
10use crate::expression::{
11 AppearsOnTable, Expression, MixedAggregates, SelectableExpression, ValidGrouping, is_aggregate,
12};
13use crate::query_builder::returning::{
14 NoReturningClause, ReturningClause, ReturningQuerySource, UpdateStmt,
15};
16use crate::query_builder::where_clause::*;
17use crate::query_builder::*;
18use crate::query_dsl::RunQueryDslSupport;
19use crate::query_dsl::methods::{BoxedCloneDsl, BoxedDsl, FilterDsl};
20use crate::query_source::Table;
21use crate::result::EmptyChangeset;
22use crate::result::Error::QueryBuilderError;
23
24pub(crate) use self::private::SetAutoTypeHelper;
25
26impl<T: QuerySource, U> UpdateStatement<T, U, SetNotCalled> {
27 pub(crate) fn new(target: UpdateTarget<T, U>) -> Self {
28 UpdateStatement {
29 from_clause: target.table.from_clause(),
30 where_clause: target.where_clause,
31 set_clause: SetClause::Immediate,
32 values: SetNotCalled,
33 returning: NoReturningClause,
34 }
35 }
36
37 pub fn set<V>(self, values: V) -> crate::dsl::Set<Self, V>
43 where
44 T: Table,
45 V: changeset::AsChangeset<Target = T>,
46 UpdateStatement<T, U, V::Changeset>: AsQuery,
47 {
48 UpdateStatement {
49 from_clause: self.from_clause,
50 where_clause: self.where_clause,
51 set_clause: <V as AsChangeset>::SET_CLAUSE,
52 values: values.as_changeset(),
53 returning: self.returning,
54 }
55 }
56}
57
58#[derive(#[automatically_derived]
impl<T: ::core::clone::Clone + QuerySource, U: ::core::clone::Clone,
V: ::core::clone::Clone, Ret: ::core::clone::Clone> ::core::clone::Clone
for UpdateStatement<T, U, V, Ret> where
T::FromClause: ::core::clone::Clone {
#[inline]
fn clone(&self) -> UpdateStatement<T, U, V, Ret> {
UpdateStatement {
from_clause: ::core::clone::Clone::clone(&self.from_clause),
where_clause: ::core::clone::Clone::clone(&self.where_clause),
set_clause: ::core::clone::Clone::clone(&self.set_clause),
values: ::core::clone::Clone::clone(&self.values),
returning: ::core::clone::Clone::clone(&self.returning),
}
}
}Clone, #[automatically_derived]
impl<T: ::core::fmt::Debug + QuerySource, U: ::core::fmt::Debug,
V: ::core::fmt::Debug, Ret: ::core::fmt::Debug> ::core::fmt::Debug for
UpdateStatement<T, U, V, Ret> where T::FromClause: ::core::fmt::Debug {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field5_finish(f,
"UpdateStatement", "from_clause", &self.from_clause,
"where_clause", &self.where_clause, "set_clause",
&self.set_clause, "values", &self.values, "returning",
&&self.returning)
}
}Debug)]
59#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
60pub struct UpdateStatement<T: QuerySource, U, V = SetNotCalled, Ret = NoReturningClause> {
66 from_clause: T::FromClause,
67 where_clause: U,
68 set_clause: SetClause,
69 values: V,
70 returning: Ret,
71}
72
73pub type BoxedUpdateStatement<'a, DB, T, V = SetNotCalled, Ret = NoReturningClause> =
75 UpdateStatement<T, BoxedWhereClause<'a, DB>, V, Ret>;
76
77pub type BoxedCloneUpdateStatement<'a, DB, T, V = SetNotCalled, Ret = NoReturningClause> =
79 UpdateStatement<T, BoxedCloneWhereClause<'a, DB>, V, Ret>;
80
81impl<T: QuerySource, U, V, Ret> UpdateStatement<T, U, V, Ret> {
82 pub fn filter<Predicate>(self, predicate: Predicate) -> Filter<Self, Predicate>
110 where
111 Self: FilterDsl<Predicate>,
112 {
113 FilterDsl::filter(self, predicate)
114 }
115
116 pub fn into_boxed<'a, DB>(self) -> IntoBoxed<'a, Self, DB>
159 where
160 DB: Backend,
161 Self: BoxedDsl<'a, DB>,
162 {
163 BoxedDsl::internal_into_boxed(self)
164 }
165
166 pub fn into_boxed_clone<'a, DB>(self) -> IntoBoxedClone<'a, Self, DB>
210 where
211 DB: Backend,
212 Self: BoxedCloneDsl<'a, DB>,
213 {
214 BoxedCloneDsl::internal_into_boxed_clone(self)
215 }
216}
217
218impl<T, U, V, Ret, Predicate> FilterDsl<Predicate> for UpdateStatement<T, U, V, Ret>
219where
220 T: QuerySource,
221 U: WhereAnd<Predicate>,
222 Predicate: AppearsOnTable<T>,
223{
224 type Output = UpdateStatement<T, U::Output, V, Ret>;
225
226 fn filter(self, predicate: Predicate) -> Self::Output {
227 UpdateStatement {
228 from_clause: self.from_clause,
229 where_clause: self.where_clause.and(predicate),
230 set_clause: self.set_clause,
231 values: self.values,
232 returning: self.returning,
233 }
234 }
235}
236
237impl<'a, T, U, V, Ret, DB> BoxedDsl<'a, DB> for UpdateStatement<T, U, V, Ret>
238where
239 T: QuerySource,
240 U: Into<BoxedWhereClause<'a, DB>>,
241{
242 type Output = BoxedUpdateStatement<'a, DB, T, V, Ret>;
243
244 fn internal_into_boxed(self) -> Self::Output {
245 UpdateStatement {
246 from_clause: self.from_clause,
247 where_clause: self.where_clause.into(),
248 set_clause: self.set_clause,
249 values: self.values,
250 returning: self.returning,
251 }
252 }
253}
254
255impl<'a, T, U, V, Ret, DB> BoxedCloneDsl<'a, DB> for UpdateStatement<T, U, V, Ret>
256where
257 T: QuerySource,
258 U: Into<BoxedCloneWhereClause<'a, DB>>,
259{
260 type Output = BoxedCloneUpdateStatement<'a, DB, T, V, Ret>;
261
262 fn internal_into_boxed_clone(self) -> Self::Output {
263 UpdateStatement {
264 from_clause: self.from_clause,
265 where_clause: self.where_clause.into(),
266 set_clause: self.set_clause,
267 values: self.values,
268 returning: self.returning,
269 }
270 }
271}
272
273impl<T, U, V, Ret, DB> QueryFragment<DB> for UpdateStatement<T, U, V, Ret>
274where
275 DB: Backend + DieselReserveSpecialization,
276 T: Table,
277 T::FromClause: QueryFragment<DB>,
278 U: QueryFragment<DB>,
279 V: QueryFragment<DB> + AllowFilterForUpdate<U>,
280 Ret: QueryFragment<DB>,
281{
282 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
283 if self.values.is_noop(out.backend())? {
284 return Err(QueryBuilderError(Box::new(EmptyChangeset)));
285 }
286
287 out.unsafe_to_cache_prepared();
288 out.push_sql("UPDATE ");
289 self.from_clause.walk_ast(out.reborrow())?;
290 self.set_clause.walk_ast(out.reborrow())?;
291 self.values.walk_ast(out.reborrow())?;
292 self.where_clause.walk_ast(out.reborrow())?;
293 self.returning.walk_ast(out.reborrow())?;
294 Ok(())
295 }
296}
297
298impl<T, U, V, Ret> QueryId for UpdateStatement<T, U, V, Ret>
299where
300 T: QuerySource,
301{
302 type QueryId = ();
303
304 const HAS_STATIC_QUERY_ID: bool = false;
305}
306
307impl<T, U, V> AsQuery for UpdateStatement<T, U, V, NoReturningClause>
308where
309 T: Table,
310 UpdateStatement<T, U, V, ReturningClause<T::AllColumns>>: Query,
311 T::AllColumns: SelectableExpression<ReturningQuerySource<UpdateStmt, T>> + ValidGrouping<()>,
312 <T::AllColumns as ValidGrouping<()>>::IsAggregate:
313 MixedAggregates<is_aggregate::No, Output = is_aggregate::No>,
314{
315 type SqlType = <Self::Query as Query>::SqlType;
316 type Query = UpdateStatement<T, U, V, ReturningClause<T::AllColumns>>;
317
318 fn as_query(self) -> Self::Query {
319 self.returning(T::all_columns())
320 }
321}
322
323impl<T, U, V, Ret> Query for UpdateStatement<T, U, V, ReturningClause<Ret>>
324where
325 T: Table,
326 Ret: SelectableExpression<ReturningQuerySource<UpdateStmt, T>> + ValidGrouping<()>,
327 Ret::IsAggregate: MixedAggregates<is_aggregate::No, Output = is_aggregate::No>,
328{
329 type SqlType = <Ret as Expression>::SqlType;
330}
331
332impl<T: QuerySource, U, V, Ret> RunQueryDslSupport for UpdateStatement<T, U, V, Ret> {}
333
334impl<T: QuerySource, U, V> UpdateStatement<T, U, V, NoReturningClause> {
335 pub fn returning<E>(self, returns: E) -> UpdateStatement<T, U, V, ReturningClause<E>>
386 where
387 T: Table,
388 UpdateStatement<T, U, V, ReturningClause<E>>: Query,
389 {
390 UpdateStatement {
391 from_clause: self.from_clause,
392 where_clause: self.where_clause,
393 set_clause: self.set_clause,
394 values: self.values,
395 returning: ReturningClause(returns),
396 }
397 }
398}
399
400#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SetNotCalled {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "SetNotCalled")
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SetNotCalled {
#[inline]
fn clone(&self) -> SetNotCalled { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for SetNotCalled { }Copy)]
402pub struct SetNotCalled;
403
404pub(crate) mod private {
405 use crate::backend::Backend;
406 use crate::query_builder::where_clause::{
407 BoxedCloneWhereClause, BoxedWhereClause, NoWhereClause, WhereClause,
408 };
409
410 use super::changeset::Assign;
411
412 #[allow(unreachable_pub)]
418 pub trait SetAutoTypeHelper<Changes> {
419 type Out;
420 }
421
422 impl<T, W, Changes> SetAutoTypeHelper<Changes> for crate::query_builder::UpdateStatement<T, W>
423 where
424 T: crate::QuerySource,
425 Changes: crate::AsChangeset,
426 {
427 type Out = crate::query_builder::UpdateStatement<T, W, Changes::Changeset>;
428 }
429
430 #[diagnostic::on_unimplemented(
432 message = "cannot apply a `WHERE` clause to batch updates",
433 note = "the information about which rows to update are provided as part of the values"
434 )]
435 pub trait AllowFilterForUpdate<P> {}
436
437 impl<U> AllowFilterForUpdate<NoWhereClause> for U {}
438
439 impl<W, C, B> AllowFilterForUpdate<WhereClause<W>> for Assign<C, B> {}
440 impl<W, T> AllowFilterForUpdate<WhereClause<W>> for Option<T> where
441 T: AllowFilterForUpdate<WhereClause<W>>
442 {
443 }
444
445 impl<'a, DB, C, B> AllowFilterForUpdate<BoxedWhereClause<'a, DB>> for Assign<C, B> where DB: Backend {}
446 impl<'a, DB, T> AllowFilterForUpdate<BoxedWhereClause<'a, DB>> for Option<T>
447 where
448 DB: Backend,
449 T: AllowFilterForUpdate<BoxedWhereClause<'a, DB>>,
450 {
451 }
452
453 impl<'a, DB, C, B> AllowFilterForUpdate<BoxedCloneWhereClause<'a, DB>> for Assign<C, B> where
454 DB: Backend
455 {
456 }
457 impl<'a, DB, T> AllowFilterForUpdate<BoxedCloneWhereClause<'a, DB>> for Option<T>
458 where
459 DB: Backend,
460 T: AllowFilterForUpdate<BoxedCloneWhereClause<'a, DB>>,
461 {
462 }
463}
464
465#[derive(#[automatically_derived]
impl ::core::clone::Clone for SetClause {
#[inline]
fn clone(&self) -> SetClause { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for SetClause { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for SetClause {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
SetClause::Immediate => "Immediate",
SetClause::Delegated => "Delegated",
})
}
}Debug)]
478pub enum SetClause {
479 Immediate,
480 Delegated,
481}
482
483impl<DB> QueryFragment<DB> for SetClause
484where
485 DB: Backend,
486{
487 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
488 if let SetClause::Immediate = self {
489 out.push_sql(" SET ");
490 }
491 Ok(())
492 }
493}