sql_middleware/pool/
connection.rs

1#[cfg(feature = "postgres")]
2use deadpool_postgres::Object as PostgresObject;
3
4#[cfg(feature = "sqlite")]
5use crate::sqlite::{SqliteConnection, SqlitePreparedStatement};
6#[cfg(feature = "sqlite")]
7use deadpool_sqlite::Object as SqliteObject;
8#[cfg(feature = "sqlite")]
9use deadpool_sqlite::rusqlite;
10
11#[cfg(feature = "turso")]
12use crate::turso::TursoPreparedStatement;
13#[cfg(feature = "libsql")]
14use deadpool_libsql::Object as LibsqlObject;
15#[cfg(feature = "turso")]
16use turso::Connection as TursoConnection;
17
18use super::types::MiddlewarePool;
19use crate::error::SqlMiddlewareDbError;
20
21pub enum MiddlewarePoolConnection {
22    #[cfg(feature = "postgres")]
23    Postgres(PostgresObject),
24    #[cfg(feature = "sqlite")]
25    Sqlite(SqliteConnection),
26    #[cfg(feature = "mssql")]
27    Mssql(deadpool::managed::Object<deadpool_tiberius::Manager>),
28    #[cfg(feature = "libsql")]
29    Libsql(LibsqlObject),
30    #[cfg(feature = "turso")]
31    Turso(TursoConnection),
32}
33
34// Manual Debug implementation because deadpool_tiberius::Manager doesn't implement Debug
35impl std::fmt::Debug for MiddlewarePoolConnection {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        match self {
38            #[cfg(feature = "postgres")]
39            Self::Postgres(conn) => f.debug_tuple("Postgres").field(conn).finish(),
40            #[cfg(feature = "sqlite")]
41            Self::Sqlite(conn) => f.debug_tuple("Sqlite").field(conn).finish(),
42            #[cfg(feature = "mssql")]
43            Self::Mssql(_) => f
44                .debug_tuple("Mssql")
45                .field(&"<TiberiusConnection>")
46                .finish(),
47            #[cfg(feature = "libsql")]
48            Self::Libsql(conn) => f.debug_tuple("Libsql").field(conn).finish(),
49            #[cfg(feature = "turso")]
50            Self::Turso(_) => f.debug_tuple("Turso").field(&"<Connection>").finish(),
51        }
52    }
53}
54
55impl MiddlewarePool {
56    /// Get a connection from the pool
57    ///
58    /// # Errors
59    /// Returns `SqlMiddlewareDbError::PoolErrorPostgres` or `SqlMiddlewareDbError::PoolErrorSqlite` if the pool fails to provide a connection.
60    pub async fn get_connection(
61        pool: &MiddlewarePool,
62    ) -> Result<MiddlewarePoolConnection, SqlMiddlewareDbError> {
63        match pool {
64            #[cfg(feature = "postgres")]
65            MiddlewarePool::Postgres(pool) => {
66                let conn: PostgresObject = pool
67                    .get()
68                    .await
69                    .map_err(SqlMiddlewareDbError::PoolErrorPostgres)?;
70                Ok(MiddlewarePoolConnection::Postgres(conn))
71            }
72            #[cfg(feature = "sqlite")]
73            MiddlewarePool::Sqlite(pool) => {
74                let conn: SqliteObject = pool
75                    .get()
76                    .await
77                    .map_err(SqlMiddlewareDbError::PoolErrorSqlite)?;
78                let worker_conn = SqliteConnection::new(conn)?;
79                Ok(MiddlewarePoolConnection::Sqlite(worker_conn))
80            }
81            #[cfg(feature = "mssql")]
82            MiddlewarePool::Mssql(pool) => {
83                let conn = pool
84                    .get()
85                    .await
86                    .map_err(SqlMiddlewareDbError::PoolErrorMssql)?;
87                Ok(MiddlewarePoolConnection::Mssql(conn))
88            }
89            #[cfg(feature = "libsql")]
90            MiddlewarePool::Libsql(pool) => {
91                let conn: LibsqlObject = pool
92                    .get()
93                    .await
94                    .map_err(SqlMiddlewareDbError::PoolErrorLibsql)?;
95                Ok(MiddlewarePoolConnection::Libsql(conn))
96            }
97            #[cfg(feature = "turso")]
98            MiddlewarePool::Turso(db) => {
99                let conn: TursoConnection = db.connect().map_err(SqlMiddlewareDbError::from)?;
100                Ok(MiddlewarePoolConnection::Turso(conn))
101            }
102            #[allow(unreachable_patterns)]
103            _ => Err(SqlMiddlewareDbError::Unimplemented(
104                "This database type is not enabled in the current build".to_string(),
105            )),
106        }
107    }
108}
109
110impl MiddlewarePoolConnection {
111    /// Run synchronous `SQLite` work on the underlying worker-owned connection.
112    ///
113    /// # Errors
114    /// Returns [`SqlMiddlewareDbError::Unimplemented`] when the connection is not `SQLite`.
115    #[cfg(feature = "sqlite")]
116    pub async fn with_sqlite_connection<F, R>(&mut self, func: F) -> Result<R, SqlMiddlewareDbError>
117    where
118        F: FnOnce(&mut rusqlite::Connection) -> Result<R, SqlMiddlewareDbError> + Send + 'static,
119        R: Send + 'static,
120    {
121        match self {
122            MiddlewarePoolConnection::Sqlite(sqlite_conn) => {
123                sqlite_conn.with_connection(func).await
124            }
125            _ => Err(SqlMiddlewareDbError::Unimplemented(
126                "with_sqlite_connection is only available for SQLite connections".to_string(),
127            )),
128        }
129    }
130
131    /// Prepare a `SQLite` statement and obtain a reusable handle backed by the worker thread.
132    ///
133    /// # Errors
134    /// Returns [`SqlMiddlewareDbError::Unimplemented`] when the underlying connection is not
135    /// `SQLite`, or propagates any preparation error reported by the worker thread.
136    #[cfg(feature = "sqlite")]
137    pub async fn prepare_sqlite_statement(
138        &mut self,
139        query: &str,
140    ) -> Result<SqlitePreparedStatement, SqlMiddlewareDbError> {
141        match self {
142            MiddlewarePoolConnection::Sqlite(sqlite_conn) => {
143                sqlite_conn.prepare_statement(query).await
144            }
145            _ => Err(SqlMiddlewareDbError::Unimplemented(
146                "prepare_sqlite_statement is only available for SQLite connections".to_string(),
147            )),
148        }
149    }
150
151    /// Prepare a Turso statement and obtain a reusable handle tied to the pooled connection.
152    ///
153    /// # Errors
154    /// Returns [`SqlMiddlewareDbError::Unimplemented`] when the connection is not Turso-enabled,
155    /// or bubbles up any error returned while preparing the statement through Turso's client.
156    #[cfg(feature = "turso")]
157    pub async fn prepare_turso_statement(
158        &mut self,
159        query: &str,
160    ) -> Result<TursoPreparedStatement, SqlMiddlewareDbError> {
161        match self {
162            MiddlewarePoolConnection::Turso(turso_conn) => {
163                TursoPreparedStatement::prepare(turso_conn.clone(), query).await
164            }
165            _ => Err(SqlMiddlewareDbError::Unimplemented(
166                "prepare_turso_statement is only available for Turso connections".to_string(),
167            )),
168        }
169    }
170}