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 {
24        client: PostgresObject,
25        translate_placeholders: bool,
26    },
27    #[cfg(feature = "sqlite")]
28    Sqlite {
29        conn: SqliteConnection,
30        translate_placeholders: bool,
31    },
32    #[cfg(feature = "mssql")]
33    Mssql {
34        conn: deadpool::managed::Object<deadpool_tiberius::Manager>,
35        translate_placeholders: bool,
36    },
37    #[cfg(feature = "libsql")]
38    Libsql {
39        conn: LibsqlObject,
40        translate_placeholders: bool,
41    },
42    #[cfg(feature = "turso")]
43    Turso {
44        conn: TursoConnection,
45        translate_placeholders: bool,
46    },
47}
48
49// Manual Debug implementation because deadpool_tiberius::Manager doesn't implement Debug
50impl std::fmt::Debug for MiddlewarePoolConnection {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        match self {
53            #[cfg(feature = "postgres")]
54            Self::Postgres { client, .. } => f.debug_tuple("Postgres").field(client).finish(),
55            #[cfg(feature = "sqlite")]
56            Self::Sqlite { conn, .. } => f.debug_tuple("Sqlite").field(conn).finish(),
57            #[cfg(feature = "mssql")]
58            Self::Mssql { .. } => f
59                .debug_tuple("Mssql")
60                .field(&"<TiberiusConnection>")
61                .finish(),
62            #[cfg(feature = "libsql")]
63            Self::Libsql { conn, .. } => f.debug_tuple("Libsql").field(conn).finish(),
64            #[cfg(feature = "turso")]
65            Self::Turso { .. } => f.debug_tuple("Turso").field(&"<Connection>").finish(),
66        }
67    }
68}
69
70impl MiddlewarePool {
71    /// Get a connection from the pool
72    ///
73    /// # Errors
74    /// Returns `SqlMiddlewareDbError::PoolErrorPostgres` or `SqlMiddlewareDbError::PoolErrorSqlite` if the pool fails to provide a connection.
75    pub async fn get_connection(
76        pool: &MiddlewarePool,
77        translate_placeholders: bool,
78    ) -> Result<MiddlewarePoolConnection, SqlMiddlewareDbError> {
79        match pool {
80            #[cfg(feature = "postgres")]
81            MiddlewarePool::Postgres(pool) => {
82                let conn: PostgresObject = pool
83                    .get()
84                    .await
85                    .map_err(SqlMiddlewareDbError::PoolErrorPostgres)?;
86                Ok(MiddlewarePoolConnection::Postgres {
87                    client: conn,
88                    translate_placeholders,
89                })
90            }
91            #[cfg(feature = "sqlite")]
92            MiddlewarePool::Sqlite(pool) => {
93                let conn: SqliteObject = pool
94                    .get()
95                    .await
96                    .map_err(SqlMiddlewareDbError::PoolErrorSqlite)?;
97                let worker_conn = SqliteConnection::new(conn)?;
98                Ok(MiddlewarePoolConnection::Sqlite {
99                    conn: worker_conn,
100                    translate_placeholders,
101                })
102            }
103            #[cfg(feature = "mssql")]
104            MiddlewarePool::Mssql(pool) => {
105                let conn = pool
106                    .get()
107                    .await
108                    .map_err(SqlMiddlewareDbError::PoolErrorMssql)?;
109                Ok(MiddlewarePoolConnection::Mssql {
110                    conn,
111                    translate_placeholders,
112                })
113            }
114            #[cfg(feature = "libsql")]
115            MiddlewarePool::Libsql(pool) => {
116                let conn: LibsqlObject = pool
117                    .get()
118                    .await
119                    .map_err(SqlMiddlewareDbError::PoolErrorLibsql)?;
120                Ok(MiddlewarePoolConnection::Libsql {
121                    conn,
122                    translate_placeholders,
123                })
124            }
125            #[cfg(feature = "turso")]
126            MiddlewarePool::Turso(db) => {
127                let conn: TursoConnection = db.connect().map_err(SqlMiddlewareDbError::from)?;
128                Ok(MiddlewarePoolConnection::Turso {
129                    conn,
130                    translate_placeholders,
131                })
132            }
133            #[allow(unreachable_patterns)]
134            _ => Err(SqlMiddlewareDbError::Unimplemented(
135                "This database type is not enabled in the current build".to_string(),
136            )),
137        }
138    }
139}
140
141impl MiddlewarePoolConnection {
142    /// Run synchronous `SQLite` work on the underlying worker-owned connection.
143    ///
144    /// # Errors
145    /// Returns [`SqlMiddlewareDbError::Unimplemented`] when the connection is not `SQLite`.
146    #[cfg(feature = "sqlite")]
147    pub async fn with_sqlite_connection<F, R>(&mut self, func: F) -> Result<R, SqlMiddlewareDbError>
148    where
149        F: FnOnce(&mut rusqlite::Connection) -> Result<R, SqlMiddlewareDbError> + Send + 'static,
150        R: Send + 'static,
151    {
152        match self {
153            MiddlewarePoolConnection::Sqlite { conn, .. } => conn.with_connection(func).await,
154            _ => Err(SqlMiddlewareDbError::Unimplemented(
155                "with_sqlite_connection is only available for SQLite connections".to_string(),
156            )),
157        }
158    }
159
160    /// Prepare a `SQLite` statement and obtain a reusable handle backed by the worker thread.
161    ///
162    /// # Errors
163    /// Returns [`SqlMiddlewareDbError::Unimplemented`] when the underlying connection is not
164    /// `SQLite`, or propagates any preparation error reported by the worker thread.
165    #[cfg(feature = "sqlite")]
166    pub async fn prepare_sqlite_statement(
167        &mut self,
168        query: &str,
169    ) -> Result<SqlitePreparedStatement, SqlMiddlewareDbError> {
170        match self {
171            MiddlewarePoolConnection::Sqlite { conn, .. } => conn.prepare_statement(query).await,
172            _ => Err(SqlMiddlewareDbError::Unimplemented(
173                "prepare_sqlite_statement is only available for SQLite connections".to_string(),
174            )),
175        }
176    }
177
178    /// Prepare a Turso statement and obtain a reusable handle tied to the pooled connection.
179    ///
180    /// # Errors
181    /// Returns [`SqlMiddlewareDbError::Unimplemented`] when the connection is not Turso-enabled,
182    /// or bubbles up any error returned while preparing the statement through Turso's client.
183    #[cfg(feature = "turso")]
184    pub async fn prepare_turso_statement(
185        &mut self,
186        query: &str,
187    ) -> Result<TursoPreparedStatement, SqlMiddlewareDbError> {
188        match self {
189            MiddlewarePoolConnection::Turso {
190                conn: turso_conn, ..
191            } => TursoPreparedStatement::prepare(turso_conn.clone(), query).await,
192            _ => Err(SqlMiddlewareDbError::Unimplemented(
193                "prepare_turso_statement is only available for Turso connections".to_string(),
194            )),
195        }
196    }
197
198    /// Pool-default translation toggle attached to this connection.
199    #[must_use]
200    pub fn translation_default(&self) -> bool {
201        match self {
202            #[cfg(feature = "postgres")]
203            MiddlewarePoolConnection::Postgres {
204                translate_placeholders,
205                ..
206            } => *translate_placeholders,
207            #[cfg(feature = "sqlite")]
208            MiddlewarePoolConnection::Sqlite {
209                translate_placeholders,
210                ..
211            } => *translate_placeholders,
212            #[cfg(feature = "mssql")]
213            MiddlewarePoolConnection::Mssql {
214                translate_placeholders,
215                ..
216            } => *translate_placeholders,
217            #[cfg(feature = "libsql")]
218            MiddlewarePoolConnection::Libsql {
219                translate_placeholders,
220                ..
221            } => *translate_placeholders,
222            #[cfg(feature = "turso")]
223            MiddlewarePoolConnection::Turso {
224                translate_placeholders,
225                ..
226            } => *translate_placeholders,
227        }
228    }
229}