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) -> Self {
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 where_clause set_clause values returning",
&self.from_clause, &self.where_clause, &self.set_clause,
&self.values, &&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>
115 where
116 Self: FilterDsl<Predicate>,
117 {
118 FilterDsl::filter(self, predicate)
119 }
120
121 pub fn into_boxed<'a, DB>(self) -> IntoBoxed<'a, Self, DB>
169 where
170 DB: Backend,
171 Self: BoxedDsl<'a, DB>,
172 {
173 BoxedDsl::internal_into_boxed(self)
174 }
175
176 pub fn into_boxed_clone<'a, DB>(self) -> IntoBoxedClone<'a, Self, DB>
225 where
226 DB: Backend,
227 Self: BoxedCloneDsl<'a, DB>,
228 {
229 BoxedCloneDsl::internal_into_boxed_clone(self)
230 }
231}
232
233impl<T, U, V, Ret, Predicate> FilterDsl<Predicate> for UpdateStatement<T, U, V, Ret>
234where
235 T: QuerySource,
236 U: WhereAnd<Predicate>,
237 Predicate: AppearsOnTable<T>,
238{
239 type Output = UpdateStatement<T, U::Output, V, Ret>;
240
241 fn filter(self, predicate: Predicate) -> Self::Output {
242 UpdateStatement {
243 from_clause: self.from_clause,
244 where_clause: self.where_clause.and(predicate),
245 set_clause: self.set_clause,
246 values: self.values,
247 returning: self.returning,
248 }
249 }
250}
251
252impl<'a, T, U, V, Ret, DB> BoxedDsl<'a, DB> for UpdateStatement<T, U, V, Ret>
253where
254 T: QuerySource,
255 U: Into<BoxedWhereClause<'a, DB>>,
256{
257 type Output = BoxedUpdateStatement<'a, DB, T, V, Ret>;
258
259 fn internal_into_boxed(self) -> Self::Output {
260 UpdateStatement {
261 from_clause: self.from_clause,
262 where_clause: self.where_clause.into(),
263 set_clause: self.set_clause,
264 values: self.values,
265 returning: self.returning,
266 }
267 }
268}
269
270impl<'a, T, U, V, Ret, DB> BoxedCloneDsl<'a, DB> for UpdateStatement<T, U, V, Ret>
271where
272 T: QuerySource,
273 U: Into<BoxedCloneWhereClause<'a, DB>>,
274{
275 type Output = BoxedCloneUpdateStatement<'a, DB, T, V, Ret>;
276
277 fn internal_into_boxed_clone(self) -> Self::Output {
278 UpdateStatement {
279 from_clause: self.from_clause,
280 where_clause: self.where_clause.into(),
281 set_clause: self.set_clause,
282 values: self.values,
283 returning: self.returning,
284 }
285 }
286}
287
288impl<T, U, V, Ret, DB> QueryFragment<DB> for UpdateStatement<T, U, V, Ret>
289where
290 DB: Backend + DieselReserveSpecialization,
291 T: Table,
292 T::FromClause: QueryFragment<DB>,
293 U: QueryFragment<DB>,
294 V: QueryFragment<DB> + AllowFilterForUpdate<U>,
295 Ret: QueryFragment<DB>,
296{
297 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
298 if self.values.is_noop(out.backend())? {
299 return Err(QueryBuilderError(Box::new(EmptyChangeset)));
300 }
301
302 out.unsafe_to_cache_prepared();
303 out.push_sql("UPDATE ");
304 self.from_clause.walk_ast(out.reborrow())?;
305 self.set_clause.walk_ast(out.reborrow())?;
306 self.values.walk_ast(out.reborrow())?;
307 self.where_clause.walk_ast(out.reborrow())?;
308 self.returning.walk_ast(out.reborrow())?;
309 Ok(())
310 }
311}
312
313impl<T, U, V, Ret> QueryId for UpdateStatement<T, U, V, Ret>
314where
315 T: QuerySource,
316{
317 type QueryId = ();
318
319 const HAS_STATIC_QUERY_ID: bool = false;
320}
321
322impl<T, U, V> AsQuery for UpdateStatement<T, U, V, NoReturningClause>
323where
324 T: Table,
325 UpdateStatement<T, U, V, ReturningClause<T::AllColumns>>: Query,
326 T::AllColumns: SelectableExpression<ReturningQuerySource<UpdateStmt, T>> + ValidGrouping<()>,
327 <T::AllColumns as ValidGrouping<()>>::IsAggregate:
328 MixedAggregates<is_aggregate::No, Output = is_aggregate::No>,
329{
330 type SqlType = <Self::Query as Query>::SqlType;
331 type Query = UpdateStatement<T, U, V, ReturningClause<T::AllColumns>>;
332
333 fn as_query(self) -> Self::Query {
334 self.returning(T::all_columns())
335 }
336}
337
338impl<T, U, V, Ret> Query for UpdateStatement<T, U, V, ReturningClause<Ret>>
339where
340 T: Table,
341 Ret: SelectableExpression<ReturningQuerySource<UpdateStmt, T>> + ValidGrouping<()>,
342 Ret::IsAggregate: MixedAggregates<is_aggregate::No, Output = is_aggregate::No>,
343{
344 type SqlType = <Ret as Expression>::SqlType;
345}
346
347impl<T: QuerySource, U, V, Ret> RunQueryDslSupport for UpdateStatement<T, U, V, Ret> {}
348
349impl<T: QuerySource, U, V> UpdateStatement<T, U, V, NoReturningClause> {
350 pub fn returning<E>(self, returns: E) -> UpdateStatement<T, U, V, ReturningClause<E>>
406 where
407 T: Table,
408 UpdateStatement<T, U, V, ReturningClause<E>>: Query,
409 {
410 UpdateStatement {
411 from_clause: self.from_clause,
412 where_clause: self.where_clause,
413 set_clause: self.set_clause,
414 values: self.values,
415 returning: ReturningClause(returns),
416 }
417 }
418}
419
420#[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]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for SetNotCalled {
}
#[automatically_derived]impl ::core::clone::Clone for SetNotCalled {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for SetNotCalled { }Copy)]
422pub struct SetNotCalled;
423
424pub(crate) mod private {
425 use crate::backend::Backend;
426 use crate::query_builder::where_clause::{
427 BoxedCloneWhereClause, BoxedWhereClause, NoWhereClause, WhereClause,
428 };
429
430 use super::changeset::Assign;
431
432 #[allow(unreachable_pub)]
438 pub trait SetAutoTypeHelper<Changes> {
439 type Out;
440 }
441
442 impl<T, W, Changes> SetAutoTypeHelper<Changes> for crate::query_builder::UpdateStatement<T, W>
443 where
444 T: crate::QuerySource,
445 Changes: crate::AsChangeset,
446 {
447 type Out = crate::query_builder::UpdateStatement<T, W, Changes::Changeset>;
448 }
449
450 #[diagnostic::on_unimplemented(
452 message = "cannot apply a `WHERE` clause to batch updates",
453 note = "the information about which rows to update are provided as part of the values"
454 )]
455 pub trait AllowFilterForUpdate<P> {}
456
457 impl<U> AllowFilterForUpdate<NoWhereClause> for U {}
458
459 impl<W, C, B> AllowFilterForUpdate<WhereClause<W>> for Assign<C, B> {}
460 impl<W, T> AllowFilterForUpdate<WhereClause<W>> for Option<T> where
461 T: AllowFilterForUpdate<WhereClause<W>>
462 {
463 }
464
465 impl<'a, DB, C, B> AllowFilterForUpdate<BoxedWhereClause<'a, DB>> for Assign<C, B> where DB: Backend {}
466 impl<'a, DB, T> AllowFilterForUpdate<BoxedWhereClause<'a, DB>> for Option<T>
467 where
468 DB: Backend,
469 T: AllowFilterForUpdate<BoxedWhereClause<'a, DB>>,
470 {
471 }
472
473 impl<'a, DB, C, B> AllowFilterForUpdate<BoxedCloneWhereClause<'a, DB>> for Assign<C, B> where
474 DB: Backend
475 {
476 }
477 impl<'a, DB, T> AllowFilterForUpdate<BoxedCloneWhereClause<'a, DB>> for Option<T>
478 where
479 DB: Backend,
480 T: AllowFilterForUpdate<BoxedCloneWhereClause<'a, DB>>,
481 {
482 }
483}
484
485#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for SetClause {
}
#[automatically_derived]impl ::core::clone::Clone for SetClause {
#[inline]
fn clone(&self) -> Self { *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)]
498pub enum SetClause {
499 Immediate,
500 Delegated,
501}
502
503impl<DB> QueryFragment<DB> for SetClause
504where
505 DB: Backend,
506{
507 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
508 if let SetClause::Immediate = self {
509 out.push_sql(" SET ");
510 }
511 Ok(())
512 }
513}