mod conv;
mod errors;
mod manager;
use std::path::Path;
pub use conv::{DatabaseTypeConversionError, SqlTypeConvert};
use diesel::{RunQueryDsl, SqliteConnection};
pub use errors::{DatabaseError, SchemaVerificationError};
pub use manager::{ConnectionManager, ConnectionManagerError, configure_connection_on_creation};
use tracing::Instrument;
pub type Result<T, E = DatabaseError> = std::result::Result<T, E>;
#[derive(Clone)]
pub struct Db {
pool: deadpool_diesel::Pool<ConnectionManager, deadpool::managed::Object<ConnectionManager>>,
}
impl Db {
pub fn new(database_filepath: &Path) -> Result<Self, DatabaseError> {
let manager = ConnectionManager::new(database_filepath.to_str().unwrap());
let pool = deadpool_diesel::Pool::builder(manager).max_size(16).build()?;
Ok(Self { pool })
}
pub async fn transact<R, E, Q, M>(&self, msg: M, query: Q) -> std::result::Result<R, E>
where
Q: Send
+ for<'a, 't> FnOnce(&'a mut SqliteConnection) -> std::result::Result<R, E>
+ 'static,
R: Send + 'static,
M: Send + ToString,
E: From<diesel::result::Error>,
E: From<DatabaseError>,
E: std::error::Error + Send + Sync + 'static,
{
let conn = self
.pool
.get()
.in_current_span()
.await
.map_err(|e| DatabaseError::ConnectionPoolObtainError(Box::new(e)))?;
let span = tracing::Span::current();
conn.interact(move |conn| {
let _guard = span.enter();
<_ as diesel::Connection>::transaction::<R, E, Q>(conn, query)
})
.await
.map_err(|err| E::from(DatabaseError::interact(&msg.to_string(), &err)))?
}
pub async fn query<R, E, Q, M>(&self, msg: M, query: Q) -> std::result::Result<R, E>
where
Q: Send + FnOnce(&mut SqliteConnection) -> std::result::Result<R, E> + 'static,
R: Send + 'static,
M: Send + ToString,
E: From<DatabaseError>,
E: std::error::Error + Send + Sync + 'static,
{
let conn = self
.pool
.get()
.await
.map_err(|e| DatabaseError::ConnectionPoolObtainError(Box::new(e)))?;
conn.interact(move |conn| {
let r = query(conn)?;
Ok(r)
})
.await
.map_err(|err| E::from(DatabaseError::interact(&msg.to_string(), &err)))?
}
}