use aro_web::App;
use axum::Router;
use axum::routing::get;
use sqlx::Database;
use std::sync::Arc;
use crate::health::health_db_handler;
pub trait AppDatabaseExt: Sized {
fn database<DB: Database>(
self,
url: &str,
) -> impl std::future::Future<Output = Result<Self, fletch_orm::FletchError>> + Send;
fn database_with<DB: Database>(
self,
url: &str,
builder: fletch_orm::PoolBuilder<DB>,
) -> impl std::future::Future<Output = Result<Self, fletch_orm::FletchError>> + Send;
fn health_check_db<DB: Database>(self) -> Self;
fn migrate<DB>(
self,
path: &str,
) -> impl std::future::Future<Output = Result<Self, sqlx::migrate::MigrateError>> + Send
where
DB: Database,
<DB as Database>::Connection: sqlx::migrate::Migrate;
}
impl AppDatabaseExt for App {
async fn database<DB: Database>(self, url: &str) -> Result<Self, fletch_orm::FletchError> {
let pool = fletch_orm::Pool::<DB>::connect(url).await?;
Ok(self.register::<fletch_orm::Pool<DB>>(Arc::new(pool)))
}
async fn database_with<DB: Database>(
self,
url: &str,
builder: fletch_orm::PoolBuilder<DB>,
) -> Result<Self, fletch_orm::FletchError> {
let pool = builder.connect(url).await?;
Ok(self.register::<fletch_orm::Pool<DB>>(Arc::new(pool)))
}
fn health_check_db<DB: Database>(self) -> Self {
let router = Router::new().route("/health/db", get(health_db_handler::<DB>));
self.routes_with_state(router)
}
async fn migrate<DB>(self, path: &str) -> Result<Self, sqlx::migrate::MigrateError>
where
DB: Database,
<DB as Database>::Connection: sqlx::migrate::Migrate,
{
let migrator = sqlx::migrate::Migrator::new(std::path::Path::new(path)).await?;
Ok(self.on_startup(move |state| {
Box::pin(async move {
let Some(pool) = state.get::<fletch_orm::Pool<DB>>() else {
return Err(
"fletch_orm::Pool not registered — call .database() before .migrate()"
.into(),
);
};
migrator.run(pool.inner()).await?;
Ok(())
})
}))
}
}