1use std::marker::PhantomData;
4
5use crate::dialect::Dialect;
6use crate::expr::{AssignsTo, Column, ColumnKey, ExprKind, IntoExpr, Value, Writable};
7use crate::render::{QuerySink, Sink, render_and_list, render_expr, render_ident};
8use crate::scope::{BaseTable, Superset, Table};
9use crate::select::{Condition, Predicate};
10use crate::statement::{Statement, WrittenTable};
11
12pub trait UpdateRow: private::Sealed {
17 type Table: Table;
18 fn sets(self) -> Vec<(&'static str, Value)>;
19}
20
21mod private {
22 pub trait Sealed {}
26}
27
28#[doc(hidden)]
29pub use private::Sealed as UpdateRowSealed;
30
31pub struct Assignments<T> {
37 sets: Vec<(&'static str, ExprKind)>,
38 _marker: PhantomData<fn() -> T>,
39}
40
41impl<T> Clone for Assignments<T> {
45 fn clone(&self) -> Self {
46 Assignments {
47 sets: self.sets.clone(),
48 _marker: PhantomData,
49 }
50 }
51}
52
53impl<T> std::fmt::Debug for Assignments<T> {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 f.debug_struct("Assignments")
56 .field("sets", &self.sets)
57 .finish()
58 }
59}
60
61impl<T: Table> Assignments<T> {
62 pub fn set_to<C, V, Idxs>(_column: Column<C>, value: V) -> Self
67 where
68 C: ColumnKey<Table = T> + Writable,
69 V: IntoExpr,
70 V::Sql: AssignsTo<C::Sql>,
71 WrittenTable<T>: Superset<V::Req, Idxs>,
72 {
73 Assignments {
74 sets: vec![(<C as crate::row::Named>::NAME, value.into_expr().kind)],
75 _marker: PhantomData,
76 }
77 }
78
79 pub fn and_set_to<C, V, Idxs>(mut self, _column: Column<C>, value: V) -> Self
81 where
82 C: ColumnKey<Table = T> + Writable,
83 V: IntoExpr,
84 V::Sql: AssignsTo<C::Sql>,
85 WrittenTable<T>: Superset<V::Req, Idxs>,
86 {
87 let name = <C as crate::row::Named>::NAME;
91 self.sets.retain(|(col, _)| *col != name);
92 self.sets.push((name, value.into_expr().kind));
93 self
94 }
95}
96
97impl<T> Assignments<T> {
98 pub(crate) fn render_into<D: Dialect>(&self, sink: &mut dyn Sink) {
101 for (i, (col, value)) in self.sets.iter().enumerate() {
102 if i > 0 {
103 sink.text(", ");
104 }
105 render_ident::<D>(sink, col);
106 sink.text(" = ");
107 render_expr::<D>(value, sink);
108 }
109 }
110
111 pub fn from_row<R: UpdateRow<Table = T>>(row: R) -> Result<Self, NothingToSet> {
116 let mut sets: Vec<(&'static str, ExprKind)> = Vec::new();
117 for (col, value) in row.sets() {
118 sets.retain(|(name, _)| *name != col);
122 sets.push((col, ExprKind::Value(value)));
123 }
124 if sets.is_empty() {
125 return Err(NothingToSet);
126 }
127 Ok(Assignments {
128 sets,
129 _marker: PhantomData,
130 })
131 }
132}
133
134#[derive(Debug, Clone, Copy, PartialEq, Eq)]
138pub struct NothingToSet;
139
140impl std::fmt::Display for NothingToSet {
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 f.write_str("an UPDATE must set at least one column, but every field of this `*Update` is untouched")
143 }
144}
145impl std::error::Error for NothingToSet {}
146
147pub struct UpdateSeed<D, T> {
148 _marker: PhantomData<fn() -> (D, T)>,
149}
150
151pub fn update<D, T: BaseTable>(_table: T) -> UpdateSeed<D, T> {
152 UpdateSeed {
153 _marker: PhantomData,
154 }
155}
156
157impl<D, T: Table> UpdateSeed<D, T> {
158 pub fn correlated<S, InnerSel>(
162 &self,
163 source: S,
164 selection: InnerSel,
165 ) -> crate::select::Select<
166 D,
167 crate::scope::Cons<
168 crate::scope::TableSlot<S::Table, crate::scope::NotNull>,
169 WrittenTable<T>,
170 >,
171 InnerSel,
172 WrittenTable<T>,
173 >
174 where
175 S: crate::select::JoinSource<D>,
176 {
177 crate::select::correlated_with(source, selection)
178 }
179
180 pub fn set_to<C, V, Idxs>(self, column: Column<C>, value: V) -> Update<D, T>
184 where
185 C: ColumnKey<Table = T> + Writable,
186 V: IntoExpr,
187 V::Sql: AssignsTo<C::Sql>,
188 WrittenTable<T>: Superset<V::Req, Idxs>,
189 {
190 Update {
191 sets: Assignments::set_to(column, value),
192 wheres: Vec::new(),
193 _marker: PhantomData,
194 }
195 }
196
197 pub fn set(self, sets: Assignments<T>) -> Update<D, T> {
202 Update {
203 sets,
204 wheres: Vec::new(),
205 _marker: PhantomData,
206 }
207 }
208}
209
210fn render_set_clause<D: Dialect, T: Table>(
211 sets: &Assignments<T>,
212 wheres: &[ExprKind],
213) -> QuerySink<D> {
214 let mut sink = QuerySink::<D>::new();
215 sink.text("UPDATE ");
216 render_ident::<D>(&mut sink, T::NAME);
217 sink.text(" SET ");
218 sets.render_into::<D>(&mut sink);
219
220 render_and_list::<D>(&mut sink, " WHERE ", wheres);
221
222 sink
223}
224
225pub struct Update<D, T: Table> {
226 sets: Assignments<T>,
227 wheres: Vec<ExprKind>,
228 _marker: PhantomData<fn() -> (D, T)>,
229}
230
231impl<D, T: Table> Update<D, T> {
232 pub fn correlated<S, InnerSel>(
236 &self,
237 source: S,
238 selection: InnerSel,
239 ) -> crate::select::Select<
240 D,
241 crate::scope::Cons<
242 crate::scope::TableSlot<S::Table, crate::scope::NotNull>,
243 WrittenTable<T>,
244 >,
245 InnerSel,
246 WrittenTable<T>,
247 >
248 where
249 S: crate::select::JoinSource<D>,
250 {
251 crate::select::correlated_with(source, selection)
252 }
253
254 pub fn filter<C: Condition<D, WrittenTable<T>, Idxs>, Idxs>(mut self, cond: C) -> Self {
255 self.wheres.push(cond.into_predicate().into_kind());
256 self
257 }
258
259 pub fn filter_all(
263 mut self,
264 conds: impl IntoIterator<Item = Predicate<D, WrittenTable<T>>>,
265 ) -> Self {
266 self.wheres
267 .extend(conds.into_iter().map(Predicate::into_kind));
268 self
269 }
270}
271
272impl<D, T: Table> Update<D, T> {
273 pub fn set_to<C, V, Idxs>(mut self, column: Column<C>, value: V) -> Self
276 where
277 C: ColumnKey<Table = T> + Writable,
278 V: IntoExpr,
279 V::Sql: AssignsTo<C::Sql>,
280 WrittenTable<T>: Superset<V::Req, Idxs>,
281 {
282 self.sets = self.sets.and_set_to(column, value);
283 self
284 }
285}
286
287impl<D: Dialect, T: Table> crate::statement::private::Sealed for Update<D, T> {}
288
289impl<D: Dialect, T: Table> Statement for Update<D, T> {
290 type Dialect = D;
291 type Table = T;
292 fn render(&self) -> QuerySink<D> {
293 render_set_clause::<D, T>(&self.sets, &self.wheres)
294 }
295}