ddnet_account_sql/
any.rs

1use futures::future::BoxFuture;
2use sqlx::Acquire;
3
4#[derive(Debug)]
5/// Enum variant over a database statement
6pub enum AnyStatement<'a> {
7    #[cfg(feature = "mysql")]
8    /// Mysql statement
9    MySql(sqlx::mysql::MySqlStatement<'a>),
10    /// Sqlite statement
11    #[cfg(feature = "sqlite")]
12    Sqlite(sqlx::sqlite::SqliteStatement<'a>),
13}
14
15/// Enum variant over a database row result
16pub enum AnyRow {
17    #[cfg(feature = "mysql")]
18    /// Mysql query row result
19    MySql(sqlx::mysql::MySqlRow),
20    /// Sqlite query row result
21    #[cfg(feature = "sqlite")]
22    Sqlite(sqlx::sqlite::SqliteRow),
23}
24
25#[derive(Debug)]
26/// Enum variant over a database query result
27pub enum AnyQueryResult {
28    #[cfg(feature = "mysql")]
29    /// Mysql query result
30    MySql(sqlx::mysql::MySqlQueryResult),
31    /// Sqlite query result
32    #[cfg(feature = "sqlite")]
33    Sqlite(sqlx::sqlite::SqliteQueryResult),
34}
35
36impl AnyQueryResult {
37    /// How many rows were affected by the last query.
38    pub fn rows_affected(&self) -> u64 {
39        match self {
40            #[cfg(feature = "mysql")]
41            Self::MySql(res) => res.rows_affected(),
42            #[cfg(feature = "sqlite")]
43            Self::Sqlite(res) => res.rows_affected(),
44        }
45    }
46}
47
48/// Enum variant over a database query
49pub enum AnyQuery<'a> {
50    #[cfg(feature = "mysql")]
51    /// Mysql query
52    MySql(sqlx::query::Query<'a, sqlx::MySql, sqlx::mysql::MySqlArguments>),
53    /// Sqlite query
54    #[cfg(feature = "sqlite")]
55    Sqlite(sqlx::query::Query<'a, sqlx::Sqlite, sqlx::sqlite::SqliteArguments<'a>>),
56}
57
58impl AnyQuery<'_> {
59    /// Executes the given query.
60    ///
61    /// See [sqlx::query::Query::execute].
62    #[allow(irrefutable_let_patterns)]
63    pub async fn execute(self, con: &mut AnyConnection<'_>) -> Result<AnyQueryResult, sqlx::Error> {
64        Ok(match self {
65            #[cfg(feature = "mysql")]
66            Self::MySql(query) => {
67                let AnyConnection::MySql(con) = con else {
68                    return Err(sqlx::Error::AnyDriverError(
69                        "Connection was not of mysql type, while query was.".into(),
70                    ));
71                };
72                AnyQueryResult::MySql(query.execute(&mut **con).await?)
73            }
74            #[cfg(feature = "sqlite")]
75            Self::Sqlite(query) => {
76                let AnyConnection::Sqlite(con) = con else {
77                    return Err(sqlx::Error::AnyDriverError(
78                        "Connection was not of sqlite type, while query was.".into(),
79                    ));
80                };
81                AnyQueryResult::Sqlite(query.execute(&mut **con).await?)
82            }
83        })
84    }
85
86    /// Execute the query, returning the first row or [`sqlx::Error::RowNotFound`] otherwise.
87    ///
88    /// See [sqlx::query::Query::fetch_one].
89    #[allow(irrefutable_let_patterns)]
90    pub async fn fetch_one(self, con: &mut AnyConnection<'_>) -> Result<AnyRow, sqlx::Error> {
91        Ok(match self {
92            #[cfg(feature = "mysql")]
93            Self::MySql(query) => {
94                let AnyConnection::MySql(con) = con else {
95                    return Err(sqlx::Error::AnyDriverError(
96                        "Connection was not of mysql type, while query was.".into(),
97                    ));
98                };
99                AnyRow::MySql(query.fetch_one(&mut **con).await?)
100            }
101            #[cfg(feature = "sqlite")]
102            Self::Sqlite(query) => {
103                let AnyConnection::Sqlite(con) = con else {
104                    return Err(sqlx::Error::AnyDriverError(
105                        "Connection was not of sqlite type, while query was.".into(),
106                    ));
107                };
108                AnyRow::Sqlite(query.fetch_one(&mut **con).await?)
109            }
110        })
111    }
112
113    /// Execute the query and return all the resulting rows collected into a [`Vec`].
114    ///
115    /// See [sqlx::query::Query::fetch_all].
116    #[allow(irrefutable_let_patterns)]
117    pub async fn fetch_all(self, con: &mut AnyConnection<'_>) -> Result<Vec<AnyRow>, sqlx::Error> {
118        Ok(match self {
119            #[cfg(feature = "mysql")]
120            Self::MySql(query) => {
121                let AnyConnection::MySql(con) = con else {
122                    return Err(sqlx::Error::AnyDriverError(
123                        "Connection was not of mysql type, while query was.".into(),
124                    ));
125                };
126                query
127                    .fetch_all(&mut **con)
128                    .await?
129                    .into_iter()
130                    .map(AnyRow::MySql)
131                    .collect()
132            }
133            #[cfg(feature = "sqlite")]
134            Self::Sqlite(query) => {
135                let AnyConnection::Sqlite(con) = con else {
136                    return Err(sqlx::Error::AnyDriverError(
137                        "Connection was not of sqlite type, while query was.".into(),
138                    ));
139                };
140                query
141                    .fetch_all(&mut **con)
142                    .await?
143                    .into_iter()
144                    .map(AnyRow::Sqlite)
145                    .collect()
146            }
147        })
148    }
149
150    /// Execute the query, returning the first row or `None` otherwise.
151    ///
152    /// See [sqlx::query::Query::fetch_optional].
153    #[allow(irrefutable_let_patterns)]
154    pub async fn fetch_optional(
155        self,
156        con: &mut AnyConnection<'_>,
157    ) -> Result<Option<AnyRow>, sqlx::Error> {
158        Ok(match self {
159            #[cfg(feature = "mysql")]
160            Self::MySql(query) => {
161                let AnyConnection::MySql(con) = con else {
162                    return Err(sqlx::Error::AnyDriverError(
163                        "Connection was not of mysql type, while query was.".into(),
164                    ));
165                };
166                query.fetch_optional(&mut **con).await?.map(AnyRow::MySql)
167            }
168            #[cfg(feature = "sqlite")]
169            Self::Sqlite(query) => {
170                let AnyConnection::Sqlite(con) = con else {
171                    return Err(sqlx::Error::AnyDriverError(
172                        "Connection was not of sqlite type, while query was.".into(),
173                    ));
174                };
175                query.fetch_optional(&mut **con).await?.map(AnyRow::Sqlite)
176            }
177        })
178    }
179}
180
181#[derive(Debug)]
182/// Enum variant over a database transaction
183pub enum AnyTransaction<'a, 'b> {
184    #[cfg(feature = "mysql")]
185    /// Mysql connection transaction
186    MySql(&'a mut sqlx::Transaction<'b, sqlx::MySql>),
187    /// Sqlite connection transaction
188    #[cfg(feature = "sqlite")]
189    Sqlite(&'a mut sqlx::Transaction<'b, sqlx::Sqlite>),
190}
191
192impl AnyTransaction<'_, '_> {
193    /// Get the connection from this transaction
194    pub fn con(&mut self) -> AnyConnection<'_> {
195        match self {
196            #[cfg(feature = "mysql")]
197            AnyTransaction::MySql(trans) => AnyConnection::MySql(trans),
198            #[cfg(feature = "sqlite")]
199            AnyTransaction::Sqlite(trans) => AnyConnection::Sqlite(trans),
200        }
201    }
202}
203
204#[derive(Debug)]
205/// Enum variant over a database connection
206pub enum AnyConnection<'a> {
207    #[cfg(feature = "mysql")]
208    /// Mysql connection
209    MySql(&'a mut sqlx::mysql::MySqlConnection),
210    /// Sqlite connection
211    #[cfg(feature = "sqlite")]
212    Sqlite(&'a mut sqlx::sqlite::SqliteConnection),
213}
214
215impl AnyConnection<'_> {
216    /// Execute the function inside a transaction.
217    /// See [`sqlx::Connection::transaction`].
218    pub async fn transaction<'a, F, R, E>(&'a mut self, callback: F) -> Result<R, E>
219    where
220        for<'c> F: FnOnce(AnyTransaction<'c, '_>) -> BoxFuture<'c, Result<R, E>> + 'a + Send + Sync,
221        Self: Sized,
222        R: Send,
223        E: From<sqlx::Error> + Send,
224    {
225        use sqlx::Connection;
226        match self {
227            #[cfg(feature = "mysql")]
228            AnyConnection::MySql(con) => {
229                con.transaction(|transaction| callback(AnyTransaction::MySql(transaction)))
230                    .await
231            }
232            #[cfg(feature = "sqlite")]
233            AnyConnection::Sqlite(con) => {
234                con.transaction(|transaction| callback(AnyTransaction::Sqlite(transaction)))
235                    .await
236            }
237        }
238    }
239}
240
241#[derive(Debug)]
242/// Enum variant over a database pooled connection
243pub enum AnyPoolConnection {
244    #[cfg(feature = "mysql")]
245    /// Mysql pool connection
246    MySql(sqlx::pool::PoolConnection<sqlx::MySql>),
247    /// Sqlite pool connection
248    #[cfg(feature = "sqlite")]
249    Sqlite(sqlx::pool::PoolConnection<sqlx::Sqlite>),
250}
251
252impl AnyPoolConnection {
253    /// Retrieves the inner connection of this pool connection.
254    ///
255    /// See [sqlx::Acquire::acquire].
256    pub async fn acquire(&mut self) -> Result<AnyConnection, sqlx::Error> {
257        Ok(match self {
258            #[cfg(feature = "mysql")]
259            Self::MySql(con) => AnyConnection::MySql(con.acquire().await?),
260            #[cfg(feature = "sqlite")]
261            Self::Sqlite(con) => AnyConnection::Sqlite(con.acquire().await?),
262        })
263    }
264}
265
266#[derive(Debug, Clone)]
267/// Enum variant over a database connection pool
268pub enum AnyPool {
269    #[cfg(feature = "mysql")]
270    /// Mysql pool
271    MySql(sqlx::mysql::MySqlPool),
272    /// Sqlite pool
273    #[cfg(feature = "sqlite")]
274    Sqlite(sqlx::sqlite::SqlitePool),
275}
276
277impl AnyPool {
278    /// Retrieves a connection from the pool.
279    ///
280    /// See [sqlx::pool::Pool::acquire].
281    pub async fn acquire(&self) -> Result<AnyPoolConnection, sqlx::Error> {
282        Ok(match self {
283            #[cfg(feature = "mysql")]
284            Self::MySql(pool) => AnyPoolConnection::MySql(pool.acquire().await?),
285            #[cfg(feature = "sqlite")]
286            Self::Sqlite(pool) => AnyPoolConnection::Sqlite(pool.acquire().await?),
287        })
288    }
289}