diesel/query_builder/update_statement/
mod.rs1pub(crate) mod changeset;
2pub(super) mod target;
3
4use crate::QuerySource;
5use crate::backend::DieselReserveSpecialization;
6use crate::dsl::{Filter, IntoBoxed};
7use crate::expression::{
8 AppearsOnTable, Expression, MixedAggregates, SelectableExpression, ValidGrouping, is_aggregate,
9};
10use crate::query_builder::returning::{
11 NoReturningClause, ReturningClause, ReturningQuerySource, UpdateStmt,
12};
13use crate::query_builder::where_clause::*;
14use crate::query_builder::*;
15use crate::query_dsl::RunQueryDsl;
16use crate::query_dsl::methods::{BoxedDsl, FilterDsl};
17use crate::query_source::Table;
18use crate::result::EmptyChangeset;
19use crate::result::Error::QueryBuilderError;
20
21pub(crate) use self::private::SetAutoTypeHelper;
22
23impl<T: QuerySource, U> UpdateStatement<T, U, SetNotCalled> {
24 pub(crate) fn new(target: UpdateTarget<T, U>) -> Self {
25 UpdateStatement {
26 from_clause: target.table.from_clause(),
27 where_clause: target.where_clause,
28 values: SetNotCalled,
29 returning: NoReturningClause,
30 }
31 }
32
33 pub fn set<V>(self, values: V) -> crate::dsl::Set<Self, V>
39 where
40 T: Table,
41 V: changeset::AsChangeset<Target = T>,
42 UpdateStatement<T, U, V::Changeset>: AsQuery,
43 {
44 UpdateStatement {
45 from_clause: self.from_clause,
46 where_clause: self.where_clause,
47 values: values.as_changeset(),
48 returning: self.returning,
49 }
50 }
51}
52
53#[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),
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_field4_finish(f,
"UpdateStatement", "from_clause", &self.from_clause,
"where_clause", &self.where_clause, "values", &self.values,
"returning", &&self.returning)
}
}Debug)]
54#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
55pub struct UpdateStatement<T: QuerySource, U, V = SetNotCalled, Ret = NoReturningClause> {
61 from_clause: T::FromClause,
62 where_clause: U,
63 values: V,
64 returning: Ret,
65}
66
67pub type BoxedUpdateStatement<'a, DB, T, V = SetNotCalled, Ret = NoReturningClause> =
69 UpdateStatement<T, BoxedWhereClause<'a, DB>, V, Ret>;
70
71impl<T: QuerySource, U, V, Ret> UpdateStatement<T, U, V, Ret> {
72 pub fn filter<Predicate>(self, predicate: Predicate) -> Filter<Self, Predicate>
100 where
101 Self: FilterDsl<Predicate>,
102 {
103 FilterDsl::filter(self, predicate)
104 }
105
106 pub fn into_boxed<'a, DB>(self) -> IntoBoxed<'a, Self, DB>
149 where
150 DB: Backend,
151 Self: BoxedDsl<'a, DB>,
152 {
153 BoxedDsl::internal_into_boxed(self)
154 }
155}
156
157impl<T, U, V, Ret, Predicate> FilterDsl<Predicate> for UpdateStatement<T, U, V, Ret>
158where
159 T: QuerySource,
160 U: WhereAnd<Predicate>,
161 Predicate: AppearsOnTable<T>,
162{
163 type Output = UpdateStatement<T, U::Output, V, Ret>;
164
165 fn filter(self, predicate: Predicate) -> Self::Output {
166 UpdateStatement {
167 from_clause: self.from_clause,
168 where_clause: self.where_clause.and(predicate),
169 values: self.values,
170 returning: self.returning,
171 }
172 }
173}
174
175impl<'a, T, U, V, Ret, DB> BoxedDsl<'a, DB> for UpdateStatement<T, U, V, Ret>
176where
177 T: QuerySource,
178 U: Into<BoxedWhereClause<'a, DB>>,
179{
180 type Output = BoxedUpdateStatement<'a, DB, T, V, Ret>;
181
182 fn internal_into_boxed(self) -> Self::Output {
183 UpdateStatement {
184 from_clause: self.from_clause,
185 where_clause: self.where_clause.into(),
186 values: self.values,
187 returning: self.returning,
188 }
189 }
190}
191
192impl<T, U, V, Ret, DB> QueryFragment<DB> for UpdateStatement<T, U, V, Ret>
193where
194 DB: Backend + DieselReserveSpecialization,
195 T: Table,
196 T::FromClause: QueryFragment<DB>,
197 U: QueryFragment<DB>,
198 V: QueryFragment<DB>,
199 Ret: QueryFragment<DB>,
200{
201 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
202 if self.values.is_noop(out.backend())? {
203 return Err(QueryBuilderError(Box::new(EmptyChangeset)));
204 }
205
206 out.unsafe_to_cache_prepared();
207 out.push_sql("UPDATE ");
208 self.from_clause.walk_ast(out.reborrow())?;
209 out.push_sql(" SET ");
210 self.values.walk_ast(out.reborrow())?;
211 self.where_clause.walk_ast(out.reborrow())?;
212 self.returning.walk_ast(out.reborrow())?;
213 Ok(())
214 }
215}
216
217impl<T, U, V, Ret> QueryId for UpdateStatement<T, U, V, Ret>
218where
219 T: QuerySource,
220{
221 type QueryId = ();
222
223 const HAS_STATIC_QUERY_ID: bool = false;
224}
225
226impl<T, U, V> AsQuery for UpdateStatement<T, U, V, NoReturningClause>
227where
228 T: Table,
229 UpdateStatement<T, U, V, ReturningClause<T::AllColumns>>: Query,
230 T::AllColumns: SelectableExpression<ReturningQuerySource<UpdateStmt, T>> + ValidGrouping<()>,
231 <T::AllColumns as ValidGrouping<()>>::IsAggregate:
232 MixedAggregates<is_aggregate::No, Output = is_aggregate::No>,
233{
234 type SqlType = <Self::Query as Query>::SqlType;
235 type Query = UpdateStatement<T, U, V, ReturningClause<T::AllColumns>>;
236
237 fn as_query(self) -> Self::Query {
238 self.returning(T::all_columns())
239 }
240}
241
242impl<T, U, V, Ret> Query for UpdateStatement<T, U, V, ReturningClause<Ret>>
243where
244 T: Table,
245 Ret: SelectableExpression<ReturningQuerySource<UpdateStmt, T>> + ValidGrouping<()>,
246 Ret::IsAggregate: MixedAggregates<is_aggregate::No, Output = is_aggregate::No>,
247{
248 type SqlType = <Ret as Expression>::SqlType;
249}
250
251impl<T: QuerySource, U, V, Ret, Conn> RunQueryDsl<Conn> for UpdateStatement<T, U, V, Ret> {}
252
253impl<T: QuerySource, U, V> UpdateStatement<T, U, V, NoReturningClause> {
254 pub fn returning<E>(self, returns: E) -> UpdateStatement<T, U, V, ReturningClause<E>>
305 where
306 T: Table,
307 UpdateStatement<T, U, V, ReturningClause<E>>: Query,
308 {
309 UpdateStatement {
310 from_clause: self.from_clause,
311 where_clause: self.where_clause,
312 values: self.values,
313 returning: ReturningClause(returns),
314 }
315 }
316}
317
318#[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)]
320pub struct SetNotCalled;
321
322mod private {
323 #[allow(unreachable_pub)]
329 pub trait SetAutoTypeHelper<Changes> {
330 type Out;
331 }
332
333 impl<T, W, Changes> SetAutoTypeHelper<Changes> for crate::query_builder::UpdateStatement<T, W>
334 where
335 T: crate::QuerySource,
336 Changes: crate::AsChangeset,
337 {
338 type Out = crate::query_builder::UpdateStatement<T, W, Changes::Changeset>;
339 }
340}