Skip to main content

dinoco/methods/
transactions.rs

1use std::future::Future;
2use std::pin::Pin;
3
4use dinoco_engine::{DinocoAdapter, DinocoClient, DinocoResult, DinocoTransactionAdapter};
5
6use super::count::Count;
7use super::delete::DeleteWithCond;
8use super::delete_many::DeleteMany;
9use super::find_and_update::FindAndUpdate;
10use super::find_first::FindFirst;
11use super::find_many::FindMany;
12use super::insert_into::{
13    Insert, InsertReturning, InsertWithConnection, InsertWithConnectionReturning, InsertWithRelation,
14    InsertWithRelationReturning,
15};
16use super::insert_many::{
17    InsertMany, InsertManyReturning, InsertManyWithConnection, InsertManyWithConnectionReturning,
18    InsertManyWithConnections, InsertManyWithConnectionsReturning, InsertManyWithRelation,
19    InsertManyWithRelationReturning, InsertManyWithRelations, InsertManyWithRelationsReturning,
20};
21use super::update::{Update, UpdateReturning};
22use super::update_many::{UpdateMany, UpdateManyReturning};
23use crate::{InsertPayload, Projection, UpdateModel, UpdatePayload};
24
25type TransactionFuture<'a> = Pin<Box<dyn Future<Output = DinocoResult<()>> + Send + 'a>>;
26
27trait TransactionRunnable<A: DinocoAdapter>: Send {
28    fn run<'a>(self: Box<Self>, client: &'a DinocoClient<A>) -> TransactionFuture<'a>;
29}
30
31struct TransactionClosure<F> {
32    closure: Option<F>,
33}
34
35impl<A, F> TransactionRunnable<A> for TransactionClosure<F>
36where
37    A: DinocoAdapter,
38    F: for<'a> FnOnce(&'a DinocoClient<A>) -> TransactionFuture<'a> + Send + 'static,
39{
40    fn run<'a>(mut self: Box<Self>, client: &'a DinocoClient<A>) -> TransactionFuture<'a> {
41        let closure = self.closure.take().expect("transaction action already consumed");
42
43        closure(client)
44    }
45}
46
47pub struct TransactionAction<A: DinocoAdapter> {
48    runnable: Box<dyn TransactionRunnable<A>>,
49}
50
51impl<A> TransactionAction<A>
52where
53    A: DinocoAdapter,
54{
55    fn new<F>(closure: F) -> Self
56    where
57        F: for<'a> FnOnce(&'a DinocoClient<A>) -> TransactionFuture<'a> + Send + 'static,
58    {
59        Self { runnable: Box::new(TransactionClosure { closure: Some(closure) }) }
60    }
61
62    fn run<'a>(self, client: &'a DinocoClient<A>) -> TransactionFuture<'a> {
63        self.runnable.run(client)
64    }
65}
66
67pub trait IntoTransactionAction<A: DinocoAdapter> {
68    fn into_transaction_action(self) -> TransactionAction<A>;
69}
70
71pub trait TransactionActionExt<A: DinocoAdapter>: Sized {
72    fn tx(self) -> TransactionAction<A>
73    where
74        Self: IntoTransactionAction<A>,
75    {
76        self.into_transaction_action()
77    }
78}
79
80impl<A, T> TransactionActionExt<A> for T where A: DinocoAdapter {}
81
82pub fn tx<A, T>(action: T) -> TransactionAction<A>
83where
84    A: DinocoAdapter,
85    T: IntoTransactionAction<A>,
86{
87    action.into_transaction_action()
88}
89
90pub struct Transactions<A: DinocoAdapter> {
91    actions: Vec<TransactionAction<A>>,
92}
93
94pub fn transactions<A>(actions: Vec<TransactionAction<A>>) -> Transactions<A>
95where
96    A: DinocoAdapter,
97{
98    Transactions { actions }
99}
100
101impl<A> Transactions<A>
102where
103    A: DinocoAdapter + DinocoTransactionAdapter + Send + Sync,
104{
105    pub fn execute<'a>(self, client: &'a DinocoClient<A>) -> impl Future<Output = DinocoResult<()>> + Send + 'a
106    where
107        A: 'a,
108    {
109        async move {
110            let mut actions = self.actions;
111
112            client
113                .primary()
114                .with_transaction(move || {
115                    Box::pin(async move {
116                        for action in actions.drain(..) {
117                            action.run(client).await?;
118                        }
119
120                        Ok(())
121                    })
122                })
123                .await
124        }
125    }
126}
127
128impl<A, M> IntoTransactionAction<A> for Count<M>
129where
130    A: DinocoAdapter + Send + Sync + 'static,
131    M: crate::Model + Send + Sync + 'static,
132{
133    fn into_transaction_action(self) -> TransactionAction<A> {
134        TransactionAction::new(move |client| {
135            Box::pin(async move {
136                self.read_in_primary().execute(client).await?;
137
138                Ok(())
139            })
140        })
141    }
142}
143
144impl<A, M> IntoTransactionAction<A> for DeleteWithCond<M>
145where
146    A: DinocoAdapter + Send + Sync + 'static,
147    M: crate::Model + Send + Sync + 'static,
148{
149    fn into_transaction_action(self) -> TransactionAction<A> {
150        TransactionAction::new(move |client| Box::pin(async move { self.execute(client).await }))
151    }
152}
153
154impl<A, M> IntoTransactionAction<A> for DeleteMany<M>
155where
156    A: DinocoAdapter + Send + Sync + 'static,
157    M: crate::Model + Send + Sync + 'static,
158{
159    fn into_transaction_action(self) -> TransactionAction<A> {
160        TransactionAction::new(move |client| Box::pin(async move { self.execute(client).await }))
161    }
162}
163
164impl<A, M> IntoTransactionAction<A> for FindAndUpdate<M>
165where
166    A: DinocoAdapter + Send + Sync + 'static,
167    M: crate::FindAndUpdateModel + Send + Sync + 'static,
168{
169    fn into_transaction_action(self) -> TransactionAction<A> {
170        TransactionAction::new(move |client| {
171            Box::pin(async move {
172                self.execute(client).await?;
173
174                Ok(())
175            })
176        })
177    }
178}
179
180impl<A, M, S> IntoTransactionAction<A> for FindFirst<M, S>
181where
182    A: DinocoAdapter + Send + Sync + 'static,
183    M: crate::Model + Send + Sync + 'static,
184    S: Projection<M> + Send + Sync + 'static,
185{
186    fn into_transaction_action(self) -> TransactionAction<A> {
187        TransactionAction::new(move |client| {
188            Box::pin(async move {
189                self.read_in_primary().execute(client).await?;
190
191                Ok(())
192            })
193        })
194    }
195}
196
197impl<A, M, S> IntoTransactionAction<A> for FindMany<M, S>
198where
199    A: DinocoAdapter + Send + Sync + 'static,
200    M: crate::Model + Send + Sync + 'static,
201    S: Projection<M> + Send + Sync + 'static,
202{
203    fn into_transaction_action(self) -> TransactionAction<A> {
204        TransactionAction::new(move |client| {
205            Box::pin(async move {
206                self.read_in_primary().execute(client).await?;
207
208                Ok(())
209            })
210        })
211    }
212}
213
214impl<A, M, V> IntoTransactionAction<A> for Insert<M, V>
215where
216    A: DinocoAdapter + Send + Sync + 'static,
217    M: crate::InsertModel + Projection<M> + Send + Sync + 'static,
218    V: InsertPayload<M> + Send + 'static,
219    <V as InsertPayload<M>>::Nested: Send + 'static,
220{
221    fn into_transaction_action(self) -> TransactionAction<A> {
222        TransactionAction::new(move |client| Box::pin(async move { self.execute(client).await }))
223    }
224}
225
226impl<A, M, V, S> IntoTransactionAction<A> for InsertReturning<M, V, S>
227where
228    A: DinocoAdapter + Send + Sync + 'static,
229    M: crate::InsertModel + Projection<M> + Send + Sync + 'static,
230    V: InsertPayload<M> + Send + 'static,
231    <V as InsertPayload<M>>::Nested: Send + 'static,
232    S: Projection<M> + Send + Sync + 'static,
233{
234    fn into_transaction_action(self) -> TransactionAction<A> {
235        TransactionAction::new(move |client| {
236            Box::pin(async move {
237                self.execute(client).await?;
238
239                Ok(())
240            })
241        })
242    }
243}
244
245impl<A, M, R> IntoTransactionAction<A> for InsertWithRelation<M, R>
246where
247    A: DinocoAdapter + Send + Sync + 'static,
248    M: crate::InsertModel + crate::InsertRelation<R> + Projection<M> + Clone + Send + Sync + 'static,
249    R: crate::InsertModel + Projection<R> + Send + Sync + 'static,
250{
251    fn into_transaction_action(self) -> TransactionAction<A> {
252        TransactionAction::new(move |client| Box::pin(async move { self.execute(client).await }))
253    }
254}
255
256impl<A, M, R, S> IntoTransactionAction<A> for InsertWithRelationReturning<M, R, S>
257where
258    A: DinocoAdapter + Send + Sync + 'static,
259    M: crate::InsertModel + crate::InsertRelation<R> + Projection<M> + Clone + Send + Sync + 'static,
260    R: crate::InsertModel + Projection<R> + Send + Sync + 'static,
261    S: Projection<M> + Send + Sync + 'static,
262{
263    fn into_transaction_action(self) -> TransactionAction<A> {
264        TransactionAction::new(move |client| {
265            Box::pin(async move {
266                self.execute(client).await?;
267
268                Ok(())
269            })
270        })
271    }
272}
273
274impl<A, M, R> IntoTransactionAction<A> for InsertWithConnection<M, R>
275where
276    A: DinocoAdapter + Send + Sync + 'static,
277    M: crate::InsertModel + crate::InsertConnection<R> + Projection<M> + Send + Sync + 'static,
278    R: Send + Sync + 'static,
279{
280    fn into_transaction_action(self) -> TransactionAction<A> {
281        TransactionAction::new(move |client| Box::pin(async move { self.execute(client).await }))
282    }
283}
284
285impl<A, M, R, S> IntoTransactionAction<A> for InsertWithConnectionReturning<M, R, S>
286where
287    A: DinocoAdapter + Send + Sync + 'static,
288    M: crate::InsertModel + crate::InsertConnection<R> + Projection<M> + Clone + Send + Sync + 'static,
289    R: Send + Sync + 'static,
290    S: Projection<M> + Send + Sync + 'static,
291{
292    fn into_transaction_action(self) -> TransactionAction<A> {
293        TransactionAction::new(move |client| {
294            Box::pin(async move {
295                self.execute(client).await?;
296
297                Ok(())
298            })
299        })
300    }
301}
302
303impl<A, M, V> IntoTransactionAction<A> for InsertMany<M, V>
304where
305    A: DinocoAdapter + Send + Sync + 'static,
306    M: crate::InsertModel + Projection<M> + Send + Sync + 'static,
307    V: InsertPayload<M> + Send + 'static,
308    <V as InsertPayload<M>>::Nested: Send + 'static,
309{
310    fn into_transaction_action(self) -> TransactionAction<A> {
311        TransactionAction::new(move |client| Box::pin(async move { self.execute(client).await }))
312    }
313}
314
315impl<A, M, V, S> IntoTransactionAction<A> for InsertManyReturning<M, V, S>
316where
317    A: DinocoAdapter + Send + Sync + 'static,
318    M: crate::InsertModel + Projection<M> + Send + Sync + 'static,
319    V: InsertPayload<M> + Send + 'static,
320    <V as InsertPayload<M>>::Nested: Send + 'static,
321    S: Projection<M> + Send + Sync + 'static,
322{
323    fn into_transaction_action(self) -> TransactionAction<A> {
324        TransactionAction::new(move |client| {
325            Box::pin(async move {
326                self.execute(client).await?;
327
328                Ok(())
329            })
330        })
331    }
332}
333
334impl<A, M, R> IntoTransactionAction<A> for InsertManyWithRelation<M, R>
335where
336    A: DinocoAdapter + Send + Sync + 'static,
337    M: crate::InsertModel + crate::InsertRelation<R> + Projection<M> + Clone + Send + Sync + 'static,
338    R: crate::InsertModel + Projection<R> + Send + Sync + 'static,
339{
340    fn into_transaction_action(self) -> TransactionAction<A> {
341        TransactionAction::new(move |client| Box::pin(async move { self.execute(client).await }))
342    }
343}
344
345impl<A, M, R, S> IntoTransactionAction<A> for InsertManyWithRelationReturning<M, R, S>
346where
347    A: DinocoAdapter + Send + Sync + 'static,
348    M: crate::InsertModel + crate::InsertRelation<R> + Projection<M> + Clone + Send + Sync + 'static,
349    R: crate::InsertModel + Projection<R> + Send + Sync + 'static,
350    S: Projection<M> + Send + Sync + 'static,
351{
352    fn into_transaction_action(self) -> TransactionAction<A> {
353        TransactionAction::new(move |client| {
354            Box::pin(async move {
355                self.execute(client).await?;
356
357                Ok(())
358            })
359        })
360    }
361}
362
363impl<A, M, R> IntoTransactionAction<A> for InsertManyWithRelations<M, R>
364where
365    A: DinocoAdapter + Send + Sync + 'static,
366    M: crate::InsertModel + crate::InsertRelation<R> + Projection<M> + Clone + Send + Sync + 'static,
367    R: crate::InsertModel + Projection<R> + Clone + Send + Sync + 'static,
368{
369    fn into_transaction_action(self) -> TransactionAction<A> {
370        TransactionAction::new(move |client| Box::pin(async move { self.execute(client).await }))
371    }
372}
373
374impl<A, M, R, S> IntoTransactionAction<A> for InsertManyWithRelationsReturning<M, R, S>
375where
376    A: DinocoAdapter + Send + Sync + 'static,
377    M: crate::InsertModel + crate::InsertRelation<R> + Projection<M> + Clone + Send + Sync + 'static,
378    R: crate::InsertModel + Projection<R> + Clone + Send + Sync + 'static,
379    S: Projection<M> + Send + Sync + 'static,
380{
381    fn into_transaction_action(self) -> TransactionAction<A> {
382        TransactionAction::new(move |client| {
383            Box::pin(async move {
384                self.execute(client).await?;
385
386                Ok(())
387            })
388        })
389    }
390}
391
392impl<A, M, R> IntoTransactionAction<A> for InsertManyWithConnections<M, R>
393where
394    A: DinocoAdapter + Send + Sync + 'static,
395    M: crate::InsertModel + crate::InsertConnection<R> + Projection<M> + Send + Sync + 'static,
396    R: Send + Sync + 'static,
397{
398    fn into_transaction_action(self) -> TransactionAction<A> {
399        TransactionAction::new(move |client| Box::pin(async move { self.execute(client).await }))
400    }
401}
402
403impl<A, M, R, S> IntoTransactionAction<A> for InsertManyWithConnectionsReturning<M, R, S>
404where
405    A: DinocoAdapter + Send + Sync + 'static,
406    M: crate::InsertModel + crate::InsertConnection<R> + Projection<M> + Clone + Send + Sync + 'static,
407    R: Send + Sync + 'static,
408    S: Projection<M> + Send + Sync + 'static,
409{
410    fn into_transaction_action(self) -> TransactionAction<A> {
411        TransactionAction::new(move |client| {
412            Box::pin(async move {
413                self.execute(client).await?;
414
415                Ok(())
416            })
417        })
418    }
419}
420
421impl<A, M, R> IntoTransactionAction<A> for InsertManyWithConnection<M, R>
422where
423    A: DinocoAdapter + Send + Sync + 'static,
424    M: crate::InsertModel + crate::InsertConnection<R> + Projection<M> + Send + Sync + 'static,
425    R: Send + Sync + 'static,
426{
427    fn into_transaction_action(self) -> TransactionAction<A> {
428        TransactionAction::new(move |client| Box::pin(async move { self.execute(client).await }))
429    }
430}
431
432impl<A, M, R, S> IntoTransactionAction<A> for InsertManyWithConnectionReturning<M, R, S>
433where
434    A: DinocoAdapter + Send + Sync + 'static,
435    M: crate::InsertModel + crate::InsertConnection<R> + Projection<M> + Clone + Send + Sync + 'static,
436    R: Send + Sync + 'static,
437    S: Projection<M> + Send + Sync + 'static,
438{
439    fn into_transaction_action(self) -> TransactionAction<A> {
440        TransactionAction::new(move |client| {
441            Box::pin(async move {
442                self.execute(client).await?;
443
444                Ok(())
445            })
446        })
447    }
448}
449
450impl<A, M, V> IntoTransactionAction<A> for Update<M, V>
451where
452    A: DinocoAdapter + Send + Sync + 'static,
453    M: UpdateModel + Send + Sync + 'static,
454    V: UpdatePayload<M> + Send + Sync + 'static,
455{
456    fn into_transaction_action(self) -> TransactionAction<A> {
457        TransactionAction::new(move |client| Box::pin(async move { self.execute(client).await }))
458    }
459}
460
461impl<A, M, V, S> IntoTransactionAction<A> for UpdateReturning<M, V, S>
462where
463    A: DinocoAdapter + Send + Sync + 'static,
464    M: UpdateModel + Projection<M> + Send + Sync + 'static,
465    V: UpdatePayload<M> + Send + Sync + 'static,
466    S: Projection<M> + Send + Sync + 'static,
467{
468    fn into_transaction_action(self) -> TransactionAction<A> {
469        TransactionAction::new(move |client| {
470            Box::pin(async move {
471                self.execute(client).await?;
472
473                Ok(())
474            })
475        })
476    }
477}
478
479impl<A, M, V> IntoTransactionAction<A> for UpdateMany<M, V>
480where
481    A: DinocoAdapter + Send + Sync + 'static,
482    M: UpdateModel + Send + Sync + 'static,
483    V: UpdatePayload<M> + Send + Sync + 'static,
484{
485    fn into_transaction_action(self) -> TransactionAction<A> {
486        TransactionAction::new(move |client| Box::pin(async move { self.execute(client).await }))
487    }
488}
489
490impl<A, M, V, S> IntoTransactionAction<A> for UpdateManyReturning<M, V, S>
491where
492    A: DinocoAdapter + Send + Sync + 'static,
493    M: UpdateModel + Send + Sync + 'static,
494    V: UpdatePayload<M> + Send + Sync + 'static,
495    S: Projection<M> + Send + Sync + 'static,
496{
497    fn into_transaction_action(self) -> TransactionAction<A> {
498        TransactionAction::new(move |client| {
499            Box::pin(async move {
500                self.execute(client).await?;
501
502                Ok(())
503            })
504        })
505    }
506}