sqlx_utils/traits/repository/transactions/
save_tx.rs

1//! Extension to [`SaveRepository`] to add transaction based saving.
2
3use crate::prelude::{Model, SaveRepository, TransactionRepository};
4use std::future::Future;
5
6/// Extension trait for Save operations with transactions.
7///
8/// This trait provides convenience methods for using transactions with repositories
9/// that implement [`SaveRepository`]. It's automatically implemented for any type that
10/// implements both [`SaveRepository<M>`] and [`TransactionRepository<M>`].
11pub trait SaveRepositoryTransaction<M>: SaveRepository<M> + TransactionRepository<M>
12where
13    M: Model + Send + Sync,
14{
15    /// Saves a model in a transactions, ensuring atomicity.
16    ///
17    /// This method:
18    /// 1. Creates a transactions using [`with_transaction`](TransactionRepository)
19    /// 2. Calls [`save_with_executor`](SaveRepository::save_with_executor) with the transactions
20    /// 3. Returns the model on successful save
21    ///
22    /// # Parameters
23    ///
24    /// * `model`: The model to save
25    ///
26    /// # Returns
27    ///
28    /// A future that resolves to:
29    /// * `Ok(M)`: The saved model on success
30    /// * `Err(crate::Error)`: The error if saving failed
31    ///
32    /// # Example
33    ///
34    /// ```no_compile
35    /// let saved_model = repo.save_in_transaction(model).await?;
36    /// ```
37    fn save_in_transaction<'a>(
38        &'a self,
39        model: M,
40    ) -> impl Future<Output = Result<M, crate::Error>> + Send + 'a
41    where
42        M: 'a,
43    {
44        self.with_transaction(move |mut tx| async move {
45            let res = self.save_with_executor(&mut *tx, model).await;
46
47            (res, tx)
48        })
49    }
50}
51
52// Blanket implementation for any repository that implements both required traits
53impl<T, M> SaveRepositoryTransaction<M> for T
54where
55    T: SaveRepository<M> + TransactionRepository<M>,
56    M: Model + Send + Sync,
57{
58}