1#[cfg(feature = "mysql")]
2use sqlx::MySql;
3#[cfg(feature = "mysql")]
4use sqlx::MySqlConnection;
5#[cfg(feature = "postgres")]
6use sqlx::Postgres;
7#[cfg(feature = "sqlite")]
8use sqlx::Sqlite;
9
10use crate::database::Pool;
11use crate::{Database, Driver, Error};
12
13pub struct Transaction {
16 pub(crate) inner: TxInner,
17}
18
19#[doc(hidden)]
21pub enum TxInner {
22 #[cfg(feature = "mysql")]
23 MySql(sqlx::Transaction<'static, MySql>),
24 #[cfg(feature = "postgres")]
25 Postgres(sqlx::Transaction<'static, Postgres>),
26 #[cfg(feature = "sqlite")]
27 Sqlite(sqlx::Transaction<'static, Sqlite>),
28}
29
30impl TxInner {
31 pub(crate) fn driver(&self) -> Driver {
32 match self {
33 #[cfg(feature = "mysql")]
34 Self::MySql(_) => Driver::MySql,
35 #[cfg(feature = "postgres")]
36 Self::Postgres(_) => Driver::Postgres,
37 #[cfg(feature = "sqlite")]
38 Self::Sqlite(_) => Driver::Sqlite,
39 }
40 }
41}
42
43impl Transaction {
44 pub(crate) async fn begin(pool: &Pool) -> Result<Self, Error> {
45 let inner = match pool {
46 #[cfg(feature = "mysql")]
47 Pool::MySql(pool) => TxInner::MySql(pool.begin().await?),
48 #[cfg(feature = "postgres")]
49 Pool::Postgres(pool) => TxInner::Postgres(pool.begin().await?),
50 #[cfg(feature = "sqlite")]
51 Pool::Sqlite(pool) => TxInner::Sqlite(pool.begin().await?),
52 };
53 Ok(Self { inner })
54 }
55
56 pub(crate) async fn commit(self) -> Result<(), Error> {
57 match self.inner {
58 #[cfg(feature = "mysql")]
59 TxInner::MySql(tx) => Ok(tx.commit().await?),
60 #[cfg(feature = "postgres")]
61 TxInner::Postgres(tx) => Ok(tx.commit().await?),
62 #[cfg(feature = "sqlite")]
63 TxInner::Sqlite(tx) => Ok(tx.commit().await?),
64 }
65 }
66
67 pub(crate) async fn rollback(self) -> Result<(), Error> {
68 match self.inner {
69 #[cfg(feature = "mysql")]
70 TxInner::MySql(tx) => Ok(tx.rollback().await?),
71 #[cfg(feature = "postgres")]
72 TxInner::Postgres(tx) => Ok(tx.rollback().await?),
73 #[cfg(feature = "sqlite")]
74 TxInner::Sqlite(tx) => Ok(tx.rollback().await?),
75 }
76 }
77
78 pub fn driver(&self) -> Driver {
80 self.inner.driver()
81 }
82
83 #[cfg(feature = "mysql")]
89 pub fn connection(&mut self) -> &mut MySqlConnection {
90 #[cfg(any(feature = "postgres", feature = "sqlite"))]
91 let driver = self.inner.driver();
92 match &mut self.inner {
93 TxInner::MySql(tx) => tx,
94 #[cfg(any(feature = "postgres", feature = "sqlite"))]
95 _ => panic!(
96 "`connection` is for MySQL; this transaction is on {}",
97 driver.name()
98 ),
99 }
100 }
101}
102
103pub trait Executor<'a> {
106 #[doc(hidden)]
107 fn target(self) -> Target<'a>;
108}
109
110#[doc(hidden)]
112pub enum Target<'a> {
113 Pool(&'a Pool),
114 Tx(&'a mut TxInner),
115}
116
117impl Target<'_> {
118 pub(crate) fn driver(&self) -> Driver {
120 match self {
121 Self::Pool(pool) => pool.driver(),
122 Self::Tx(tx) => tx.driver(),
123 }
124 }
125}
126
127impl<'a> Executor<'a> for &'a Database {
128 fn target(self) -> Target<'a> {
129 Target::Pool(&self.pool)
130 }
131}
132
133impl<'a> Executor<'a> for &'a mut Transaction {
134 fn target(self) -> Target<'a> {
135 Target::Tx(&mut self.inner)
136 }
137}