1pub mod changeset;
2pub mod target;
3
4pub use self::changeset::AsChangeset;
5pub use self::target::{IntoUpdateTarget, UpdateTarget};
6
7use backend::Backend;
8use dsl::{Filter, IntoBoxed};
9use expression::{AppearsOnTable, Expression, NonAggregate, SelectableExpression};
10use query_builder::returning_clause::*;
11use query_builder::where_clause::*;
12use query_builder::*;
13use query_dsl::methods::{BoxedDsl, FilterDsl};
14use query_dsl::RunQueryDsl;
15use query_source::Table;
16use result::Error::QueryBuilderError;
17use result::QueryResult;
18
19#[deprecated(since = "1.2.0", note = "Use `UpdateStatement<T, U>` instead")]
22#[cfg(feature = "with-deprecated")]
23pub type IncompleteUpdateStatement<T, U> = UpdateStatement<T, U>;
24
25impl<T, U> UpdateStatement<T, U, SetNotCalled> {
26 pub(crate) fn new(target: UpdateTarget<T, U>) -> Self {
27 UpdateStatement {
28 table: target.table,
29 where_clause: target.where_clause,
30 values: SetNotCalled,
31 returning: NoReturningClause,
32 }
33 }
34
35 pub fn set<V>(self, values: V) -> UpdateStatement<T, U, V::Changeset>
41 where
42 T: Table,
43 V: changeset::AsChangeset<Target = T>,
44 UpdateStatement<T, U, V::Changeset>: AsQuery,
45 {
46 UpdateStatement {
47 table: self.table,
48 where_clause: self.where_clause,
49 values: values.as_changeset(),
50 returning: self.returning,
51 }
52 }
53}
54
55#[derive(Debug, Copy, Clone)]
56#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
57pub struct UpdateStatement<T, U, V = SetNotCalled, Ret = NoReturningClause> {
63 table: T,
64 where_clause: U,
65 values: V,
66 returning: Ret,
67}
68
69pub type BoxedUpdateStatement<'a, DB, T, V = SetNotCalled, Ret = NoReturningClause> =
71 UpdateStatement<T, BoxedWhereClause<'a, DB>, V, Ret>;
72
73impl<T, U, V, Ret> UpdateStatement<T, U, V, Ret> {
74 pub fn filter<Predicate>(self, predicate: Predicate) -> Filter<Self, Predicate>
103 where
104 Self: FilterDsl<Predicate>,
105 {
106 FilterDsl::filter(self, predicate)
107 }
108
109 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 U: WhereAnd<Predicate>,
166 Predicate: AppearsOnTable<T>,
167{
168 type Output = UpdateStatement<T, U::Output, V, Ret>;
169
170 fn filter(self, predicate: Predicate) -> Self::Output {
171 UpdateStatement {
172 table: self.table,
173 where_clause: self.where_clause.and(predicate),
174 values: self.values,
175 returning: self.returning,
176 }
177 }
178}
179
180impl<'a, T, U, V, Ret, DB> BoxedDsl<'a, DB> for UpdateStatement<T, U, V, Ret>
181where
182 U: Into<BoxedWhereClause<'a, DB>>,
183{
184 type Output = BoxedUpdateStatement<'a, DB, T, V, Ret>;
185
186 fn internal_into_boxed(self) -> Self::Output {
187 UpdateStatement {
188 table: self.table,
189 where_clause: self.where_clause.into(),
190 values: self.values,
191 returning: self.returning,
192 }
193 }
194}
195
196impl<T, U, V, Ret, DB> QueryFragment<DB> for UpdateStatement<T, U, V, Ret>
197where
198 DB: Backend,
199 T: Table,
200 T::FromClause: QueryFragment<DB>,
201 U: QueryFragment<DB>,
202 V: QueryFragment<DB>,
203 Ret: QueryFragment<DB>,
204{
205 fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
206 if self.values.is_noop()? {
207 return Err(QueryBuilderError(
208 "There are no changes to save. This query cannot be built".into(),
209 ));
210 }
211
212 out.unsafe_to_cache_prepared();
213 out.push_sql("UPDATE ");
214 self.table.from_clause().walk_ast(out.reborrow())?;
215 out.push_sql(" SET ");
216 self.values.walk_ast(out.reborrow())?;
217 self.where_clause.walk_ast(out.reborrow())?;
218 self.returning.walk_ast(out.reborrow())?;
219 Ok(())
220 }
221}
222
223impl<T, U, V, Ret> QueryId for UpdateStatement<T, U, V, Ret> {
224 type QueryId = ();
225
226 const HAS_STATIC_QUERY_ID: bool = false;
227}
228
229impl<T, U, V> AsQuery for UpdateStatement<T, U, V, NoReturningClause>
230where
231 T: Table,
232 UpdateStatement<T, U, V, ReturningClause<T::AllColumns>>: Query,
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: Expression + SelectableExpression<T> + NonAggregate,
246{
247 type SqlType = Ret::SqlType;
248}
249
250impl<T, U, V, Ret, Conn> RunQueryDsl<Conn> for UpdateStatement<T, U, V, Ret> {}
251
252impl<T, U, V> UpdateStatement<T, U, V, NoReturningClause> {
253 pub fn returning<E>(self, returns: E) -> UpdateStatement<T, U, V, ReturningClause<E>>
276 where
277 T: Table,
278 UpdateStatement<T, U, V, ReturningClause<E>>: Query,
279 {
280 UpdateStatement {
281 table: self.table,
282 where_clause: self.where_clause,
283 values: self.values,
284 returning: ReturningClause(returns),
285 }
286 }
287}
288
289#[derive(Debug, Clone, Copy)]
291pub struct SetNotCalled;