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};
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::{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
77impl<T: QuerySource, U, V, Ret> UpdateStatement<T, U, V, Ret> {
78 pub fn filter<Predicate>(self, predicate: Predicate) -> Filter<Self, Predicate>
106 where
107 Self: FilterDsl<Predicate>,
108 {
109 FilterDsl::filter(self, predicate)
110 }
111
112 pub fn into_boxed<'a, DB>(self) -> IntoBoxed<'a, Self, DB>
155 where
156 DB: Backend,
157 Self: BoxedDsl<'a, DB>,
158 {
159 BoxedDsl::internal_into_boxed(self)
160 }
161}
162
163impl<T, U, V, Ret, Predicate> FilterDsl<Predicate> for UpdateStatement<T, U, V, Ret>
164where
165 T: QuerySource,
166 U: WhereAnd<Predicate>,
167 Predicate: AppearsOnTable<T>,
168{
169 type Output = UpdateStatement<T, U::Output, V, Ret>;
170
171 fn filter(self, predicate: Predicate) -> Self::Output {
172 UpdateStatement {
173 from_clause: self.from_clause,
174 where_clause: self.where_clause.and(predicate),
175 set_clause: self.set_clause,
176 values: self.values,
177 returning: self.returning,
178 }
179 }
180}
181
182impl<'a, T, U, V, Ret, DB> BoxedDsl<'a, DB> for UpdateStatement<T, U, V, Ret>
183where
184 T: QuerySource,
185 U: Into<BoxedWhereClause<'a, DB>>,
186{
187 type Output = BoxedUpdateStatement<'a, DB, T, V, Ret>;
188
189 fn internal_into_boxed(self) -> Self::Output {
190 UpdateStatement {
191 from_clause: self.from_clause,
192 where_clause: self.where_clause.into(),
193 set_clause: self.set_clause,
194 values: self.values,
195 returning: self.returning,
196 }
197 }
198}
199
200impl<T, U, V, Ret, DB> QueryFragment<DB> for UpdateStatement<T, U, V, Ret>
201where
202 DB: Backend + DieselReserveSpecialization,
203 T: Table,
204 T::FromClause: QueryFragment<DB>,
205 U: QueryFragment<DB>,
206 V: QueryFragment<DB> + AllowFilterForUpdate<U>,
207 Ret: QueryFragment<DB>,
208{
209 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
210 if self.values.is_noop(out.backend())? {
211 return Err(QueryBuilderError(Box::new(EmptyChangeset)));
212 }
213
214 out.unsafe_to_cache_prepared();
215 out.push_sql("UPDATE ");
216 self.from_clause.walk_ast(out.reborrow())?;
217 self.set_clause.walk_ast(out.reborrow())?;
218 self.values.walk_ast(out.reborrow())?;
219 self.where_clause.walk_ast(out.reborrow())?;
220 self.returning.walk_ast(out.reborrow())?;
221 Ok(())
222 }
223}
224
225impl<T, U, V, Ret> QueryId for UpdateStatement<T, U, V, Ret>
226where
227 T: QuerySource,
228{
229 type QueryId = ();
230
231 const HAS_STATIC_QUERY_ID: bool = false;
232}
233
234impl<T, U, V> AsQuery for UpdateStatement<T, U, V, NoReturningClause>
235where
236 T: Table,
237 UpdateStatement<T, U, V, ReturningClause<T::AllColumns>>: Query,
238 T::AllColumns: SelectableExpression<ReturningQuerySource<UpdateStmt, T>> + ValidGrouping<()>,
239 <T::AllColumns as ValidGrouping<()>>::IsAggregate:
240 MixedAggregates<is_aggregate::No, Output = is_aggregate::No>,
241{
242 type SqlType = <Self::Query as Query>::SqlType;
243 type Query = UpdateStatement<T, U, V, ReturningClause<T::AllColumns>>;
244
245 fn as_query(self) -> Self::Query {
246 self.returning(T::all_columns())
247 }
248}
249
250impl<T, U, V, Ret> Query for UpdateStatement<T, U, V, ReturningClause<Ret>>
251where
252 T: Table,
253 Ret: SelectableExpression<ReturningQuerySource<UpdateStmt, T>> + ValidGrouping<()>,
254 Ret::IsAggregate: MixedAggregates<is_aggregate::No, Output = is_aggregate::No>,
255{
256 type SqlType = <Ret as Expression>::SqlType;
257}
258
259impl<T: QuerySource, U, V, Ret> RunQueryDslSupport for UpdateStatement<T, U, V, Ret> {}
260
261impl<T: QuerySource, U, V> UpdateStatement<T, U, V, NoReturningClause> {
262 pub fn returning<E>(self, returns: E) -> UpdateStatement<T, U, V, ReturningClause<E>>
313 where
314 T: Table,
315 UpdateStatement<T, U, V, ReturningClause<E>>: Query,
316 {
317 UpdateStatement {
318 from_clause: self.from_clause,
319 where_clause: self.where_clause,
320 set_clause: self.set_clause,
321 values: self.values,
322 returning: ReturningClause(returns),
323 }
324 }
325}
326
327#[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)]
329pub struct SetNotCalled;
330
331pub(crate) mod private {
332 use crate::backend::Backend;
333 use crate::query_builder::where_clause::{BoxedWhereClause, NoWhereClause, WhereClause};
334
335 use super::changeset::Assign;
336
337 #[allow(unreachable_pub)]
343 pub trait SetAutoTypeHelper<Changes> {
344 type Out;
345 }
346
347 impl<T, W, Changes> SetAutoTypeHelper<Changes> for crate::query_builder::UpdateStatement<T, W>
348 where
349 T: crate::QuerySource,
350 Changes: crate::AsChangeset,
351 {
352 type Out = crate::query_builder::UpdateStatement<T, W, Changes::Changeset>;
353 }
354
355 #[diagnostic::on_unimplemented(
357 message = "cannot apply a `WHERE` clause to batch updates",
358 note = "the information about which rows to update are provided as part of the values"
359 )]
360 pub trait AllowFilterForUpdate<P> {}
361
362 impl<U> AllowFilterForUpdate<NoWhereClause> for U {}
363
364 impl<W, C, B> AllowFilterForUpdate<WhereClause<W>> for Assign<C, B> {}
365 impl<W, T> AllowFilterForUpdate<WhereClause<W>> for Option<T> where
366 T: AllowFilterForUpdate<WhereClause<W>>
367 {
368 }
369
370 impl<'a, DB, C, B> AllowFilterForUpdate<BoxedWhereClause<'a, DB>> for Assign<C, B> where DB: Backend {}
371 impl<'a, DB, T> AllowFilterForUpdate<BoxedWhereClause<'a, DB>> for Option<T>
372 where
373 DB: Backend,
374 T: AllowFilterForUpdate<BoxedWhereClause<'a, DB>>,
375 {
376 }
377}
378
379#[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)]
392pub enum SetClause {
393 Immediate,
394 Delegated,
395}
396
397impl<DB> QueryFragment<DB> for SetClause
398where
399 DB: Backend,
400{
401 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
402 if let SetClause::Immediate = self {
403 out.push_sql(" SET ");
404 }
405 Ok(())
406 }
407}