Skip to main content

keelson_models/
mutate.rs

1use std::fmt;
2
3use keelson_core::Mod;
4use keelson_exec::{ExecError, ExecResult, Execute as _, Executor, FromRow, Row};
5
6use crate::Table;
7use crate::delegate::delegate_clause;
8
9fn decode_rows<T: FromRow>(rows: Vec<Row>) -> Result<Vec<T>, ExecError> {
10    rows.into_iter().map(|mut r| T::from_row(&mut r)).collect()
11}
12
13/// A pending model `INSERT`: the three-state setter, held **unbuilt** so
14/// [`Table::before_insert`] can still rewrite it once an executor is in hand.
15///
16/// That deferral is why this wrapper, unlike the others, stores extra mods as
17/// closures ([`with`](ModelInsert::with)) instead of applying them eagerly:
18/// there is no statement to apply them to until the verb runs.
19pub struct ModelInsert<M: Table> {
20    setter: M::Setter,
21    #[allow(clippy::type_complexity)] // a list of deferred mods, spelled out
22    mods: Vec<Box<dyn FnOnce(&mut M::Insert) + Send>>,
23}
24
25impl<M: Table> fmt::Debug for ModelInsert<M> {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        f.debug_struct("ModelInsert")
28            .field("mods", &self.mods.len())
29            .finish_non_exhaustive()
30    }
31}
32
33impl<M: Table> ModelInsert<M> {
34    pub(crate) fn new(setter: M::Setter) -> Self {
35        ModelInsert {
36            setter,
37            mods: Vec::new(),
38        }
39    }
40
41    /// Defer Layer 1 mods onto the eventual `INSERT` statement —
42    /// `.with(insert::on_conflict(…).do_nothing())` is how an upsert or any
43    /// other dialect feature mixes into a typed insert.
44    #[must_use]
45    pub fn with(mut self, mods: impl Mod<M::Insert> + Send + 'static) -> Self {
46        self.mods.push(Box::new(move |q| mods.apply(q)));
47        self
48    }
49
50    async fn build(self, db: &dyn Executor) -> Result<M::Insert, ExecError> {
51        let ModelInsert { mut setter, mods } = self;
52        M::before_insert(db, &mut setter).await?;
53        let mut q = M::insert_query(setter);
54        for m in mods {
55            m(&mut q);
56        }
57        Ok(q)
58    }
59
60    /// Insert and hand back the one inserted row, via the statement's
61    /// `RETURNING`. Zero returned rows is [`ExecError::RowNotFound`] — on a
62    /// dialect without `RETURNING` (MySQL) the generated model supplies its
63    /// own read-back instead of this verb; see the crate docs.
64    pub async fn one(self, db: &dyn Executor) -> Result<M::Row, ExecError> {
65        let q = self.build(db).await?;
66        let mut models: Vec<M::Row> = decode_rows(q.fetch_rows(db).await?)?;
67        match models.len() {
68            0 => Err(ExecError::RowNotFound),
69            1 => {
70                M::after_insert(db, &models).await?;
71                Ok(models.pop().expect("len checked"))
72            }
73            _ => Err(ExecError::TooManyRows),
74        }
75    }
76
77    /// Insert for the side effect. [`Table::after_insert`] still runs, with an
78    /// empty row slice.
79    pub async fn exec(self, db: &dyn Executor) -> Result<ExecResult, ExecError> {
80        let q = self.build(db).await?;
81        let done = q.execute(db).await?;
82        M::after_insert(db, &[]).await?;
83        Ok(done)
84    }
85}
86
87/// A pending model `UPDATE`: the statement (which filters and mods have
88/// already landed on) plus the setter, joined together only at verb time so
89/// [`Table::before_update`] sees the setter first.
90pub struct ModelUpdate<M: Table> {
91    setter: M::Setter,
92    query: M::Update,
93}
94
95impl<M: Table> fmt::Debug for ModelUpdate<M> {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97        f.debug_struct("ModelUpdate")
98            .field("query", &self.query)
99            .finish_non_exhaustive()
100    }
101}
102
103impl<M: Table> ModelUpdate<M> {
104    pub(crate) fn new(setter: M::Setter, mods: impl Mod<Self>) -> Self {
105        let mut u = ModelUpdate {
106            setter,
107            query: M::update_query(),
108        };
109        mods.apply(&mut u);
110        u
111    }
112
113    /// Apply mods written against the concrete dialect statement — the same
114    /// escape hatch as [`ModelSelect::apply`](crate::ModelSelect::apply).
115    pub fn apply(&mut self, mods: impl Mod<M::Update>) {
116        mods.apply(&mut self.query);
117    }
118
119    async fn build(self, db: &dyn Executor) -> Result<M::Update, ExecError> {
120        let ModelUpdate {
121            mut setter,
122            mut query,
123        } = self;
124        M::before_update(db, &mut setter).await?;
125        M::apply_setter(setter, &mut query);
126        Ok(query)
127    }
128
129    /// Update for the side effect; answers how many rows changed.
130    pub async fn exec(self, db: &dyn Executor) -> Result<ExecResult, ExecError> {
131        let q = self.build(db).await?;
132        let done = q.execute(db).await?;
133        M::after_update(db, done.rows_affected).await?;
134        Ok(done)
135    }
136
137    /// Update and decode whatever the statement's `RETURNING` produced —
138    /// which is nothing unless a `returning` mod (or the generated model)
139    /// put one on. The rows come back as this model's row struct.
140    pub async fn all(self, db: &dyn Executor) -> Result<Vec<M::Row>, ExecError> {
141        let q = self.build(db).await?;
142        let models: Vec<M::Row> = decode_rows(q.fetch_rows(db).await?)?;
143        M::after_update(db, models.len() as u64).await?;
144        Ok(models)
145    }
146}
147
148/// A pending model `DELETE`.
149pub struct ModelDelete<M: Table> {
150    query: M::Delete,
151}
152
153impl<M: Table> fmt::Debug for ModelDelete<M> {
154    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155        f.debug_struct("ModelDelete")
156            .field("query", &self.query)
157            .finish()
158    }
159}
160
161impl<M: Table> ModelDelete<M> {
162    pub(crate) fn new(mods: impl Mod<Self>) -> Self {
163        let mut d = ModelDelete {
164            query: M::delete_query(),
165        };
166        mods.apply(&mut d);
167        d
168    }
169
170    /// Apply mods written against the concrete dialect statement.
171    pub fn apply(&mut self, mods: impl Mod<M::Delete>) {
172        mods.apply(&mut self.query);
173    }
174
175    /// Delete for the side effect; answers how many rows went.
176    pub async fn exec(self, db: &dyn Executor) -> Result<ExecResult, ExecError> {
177        M::before_delete(db).await?;
178        let done = self.query.execute(db).await?;
179        M::after_delete(db, done.rows_affected).await?;
180        Ok(done)
181    }
182
183    /// Delete and decode the statement's `RETURNING`, if a mod put one on.
184    pub async fn all(self, db: &dyn Executor) -> Result<Vec<M::Row>, ExecError> {
185        M::before_delete(db).await?;
186        let models: Vec<M::Row> = decode_rows(self.query.fetch_rows(db).await?)?;
187        M::after_delete(db, models.len() as u64).await?;
188        Ok(models)
189    }
190}
191
192// UPDATE: everything an `UPDATE` can carry across the three dialects.
193delegate_clause!(
194    ModelUpdate,
195    Table,
196    Update,
197    HasWith,
198    with_mut,
199    keelson_core::clause::With
200);
201delegate_clause!(
202    ModelUpdate,
203    Table,
204    Update,
205    HasTableRef,
206    table_ref_mut,
207    keelson_core::clause::TableRef
208);
209delegate_clause!(
210    ModelUpdate,
211    Table,
212    Update,
213    HasJoins,
214    joins_mut,
215    Vec<keelson_core::clause::Join>
216);
217delegate_clause!(
218    ModelUpdate,
219    Table,
220    Update,
221    HasWhere,
222    where_mut,
223    keelson_core::clause::Where
224);
225delegate_clause!(
226    ModelUpdate,
227    Table,
228    Update,
229    HasOrderBy,
230    order_by_mut,
231    keelson_core::clause::OrderBy
232);
233delegate_clause!(
234    ModelUpdate,
235    Table,
236    Update,
237    HasLimit,
238    limit_mut,
239    keelson_core::clause::Limit
240);
241delegate_clause!(
242    ModelUpdate,
243    Table,
244    Update,
245    HasSet,
246    set_mut,
247    keelson_core::clause::Set
248);
249delegate_clause!(
250    ModelUpdate,
251    Table,
252    Update,
253    HasReturning,
254    returning_mut,
255    keelson_core::clause::Returning
256);
257
258// DELETE.
259delegate_clause!(
260    ModelDelete,
261    Table,
262    Delete,
263    HasWith,
264    with_mut,
265    keelson_core::clause::With
266);
267delegate_clause!(
268    ModelDelete,
269    Table,
270    Delete,
271    HasTableRef,
272    table_ref_mut,
273    keelson_core::clause::TableRef
274);
275delegate_clause!(
276    ModelDelete,
277    Table,
278    Delete,
279    HasJoins,
280    joins_mut,
281    Vec<keelson_core::clause::Join>
282);
283delegate_clause!(
284    ModelDelete,
285    Table,
286    Delete,
287    HasWhere,
288    where_mut,
289    keelson_core::clause::Where
290);
291delegate_clause!(
292    ModelDelete,
293    Table,
294    Delete,
295    HasOrderBy,
296    order_by_mut,
297    keelson_core::clause::OrderBy
298);
299delegate_clause!(
300    ModelDelete,
301    Table,
302    Delete,
303    HasLimit,
304    limit_mut,
305    keelson_core::clause::Limit
306);
307delegate_clause!(
308    ModelDelete,
309    Table,
310    Delete,
311    HasReturning,
312    returning_mut,
313    keelson_core::clause::Returning
314);