use core::{error::Error, fmt};
use std::path::PathBuf;
use bb8::{Pool, RunError};
use bb8_postgres::PostgresConnectionManager;
use tokio_postgres::{Error as PostgresError, NoTls};
use ts_sql::{MigrationError, perform_migrations_async};
pub type ConnectionPool = Pool<PostgresConnectionManager<NoTls>>;
#[derive(Debug)]
#[non_exhaustive]
#[allow(missing_docs)]
pub enum SetupPostgresError {
#[non_exhaustive]
BuildPoolError { source: PostgresError },
#[non_exhaustive]
InvalidConnectionString { source: PostgresError },
#[non_exhaustive]
GetConnection { source: RunError<PostgresError> },
#[non_exhaustive]
PerformMigrations { source: MigrationError },
}
impl fmt::Display for SetupPostgresError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
Self::BuildPoolError { .. } => {
write!(f, "failed to build connection pool")
}
Self::InvalidConnectionString { .. } => {
write!(f, "invalid connection string")
}
Self::GetConnection { .. } => write!(f, "could not connect to database"),
Self::PerformMigrations { .. } => write!(f, "failed to perform migrations"),
}
}
}
impl Error for SetupPostgresError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self {
Self::InvalidConnectionString { source } | Self::BuildPoolError { source } => {
Some(source)
}
Self::GetConnection { source, .. } => Some(source),
Self::PerformMigrations { source, .. } => Some(source),
}
}
}
pub async fn setup_connection_pool<S: ToString>(
connection_string: S,
migrations_directory: Option<PathBuf>,
) -> Result<ConnectionPool, SetupPostgresError> {
let manager = PostgresConnectionManager::new_from_stringlike(connection_string, NoTls)
.map_err(|source| SetupPostgresError::InvalidConnectionString { source })?;
let pool = Pool::builder()
.build(manager)
.await
.map_err(|source| SetupPostgresError::BuildPoolError { source })?;
{
let client = pool
.get()
.await
.map_err(|source| SetupPostgresError::GetConnection { source })?;
perform_migrations_async(&client, migrations_directory)
.await
.map_err(|source| SetupPostgresError::PerformMigrations { source })?;
}
Ok(pool)
}