use std::sync::Arc;
use crate::{Environment, config::Config, health::Checks, store::Store};
#[cfg(axa_db = "sqlx")]
pub type Db = axa_sqlx::Pool;
#[cfg(axa_db = "seaorm")]
pub type Db = axa_seaorm::Pool;
#[cfg(axa_db = "diesel")]
pub type Db = axa_diesel::Pool;
#[cfg(axa_db = "toasty")]
pub type Db = axa_toasty::Pool;
#[cfg(axa_db = "none")]
pub type Db = ();
#[cfg(not(axa_db = "none"))]
pub async fn ping(db: &Db) -> crate::Result<()> {
#[cfg(axa_db = "sqlx")]
axa_sqlx::ping(db).await?;
#[cfg(axa_db = "seaorm")]
axa_seaorm::ping(db).await?;
#[cfg(axa_db = "diesel")]
axa_diesel::ping(db).await?;
#[cfg(axa_db = "toasty")]
axa_toasty::ping(db).await?;
Ok(())
}
#[cfg(all(test, axa_db = "seaorm"))]
fn test_db() -> Db {
sea_orm::DatabaseConnection::default()
}
#[cfg(all(test, axa_db = "sqlx"))]
fn test_db() -> Db {
static RUNTIME: std::sync::LazyLock<tokio::runtime::Runtime> =
std::sync::LazyLock::new(|| tokio::runtime::Runtime::new().expect("a runtime"));
let _entered = RUNTIME.enter();
axa_sqlx::sqlx::postgres::PgPoolOptions::new()
.acquire_timeout(std::time::Duration::from_millis(50))
.connect_lazy("postgres://axa:axa@127.0.0.1:1/axa")
.expect("a well-formed address")
}
#[cfg(all(test, axa_db = "diesel"))]
fn test_db() -> Db {
let config = axa_diesel::PoolConfig {
wait_timeout: std::time::Duration::from_millis(50),
..axa_diesel::PoolConfig::new("postgres://axa:axa@127.0.0.1:1/axa")
};
let tls = axa_diesel::web_tls().expect("TLS settings");
axa_diesel::pool_with_tls(&config, tls).expect("a pool that never connects")
}
#[cfg(all(test, axa_db = "toasty"))]
fn test_db() -> Db {
unimplemented!(
"Toasty connects when its handle is made, so a unit test with `toasty` as the only \
database feature has no context"
)
}
#[cfg(all(test, axa_db = "none"))]
fn test_db() -> Db {}
#[derive(Clone)]
pub struct AppContext {
pub environment: Environment,
pub db: Db,
pub config: Arc<Config>,
pub shared_store: Arc<Store>,
pub health_checks: Checks,
#[cfg(feature = "queue")]
pub queue_provider: Option<Arc<crate::queue::Queue>>,
}
impl std::fmt::Debug for AppContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut debug = f.debug_struct("AppContext");
debug
.field("environment", &self.environment)
.field("db", &std::any::type_name::<Db>())
.field("config", &self.config)
.field("shared_store", &self.shared_store)
.field("health_checks", &self.health_checks);
#[cfg(feature = "queue")]
debug.field("queue_provider", &self.queue_provider);
debug.finish()
}
}
impl AppContext {
#[must_use]
pub fn new(environment: Environment, db: Db, config: Config) -> Self {
Self {
environment,
db,
config: Arc::new(config),
shared_store: Arc::new(Store::default()),
health_checks: Checks::new(),
#[cfg(feature = "queue")]
queue_provider: None,
}
}
#[cfg(test)]
#[allow(clippy::unit_arg, dead_code)]
pub(crate) fn for_test(environment: Environment, config: Config) -> Self {
Self::new(environment, test_db(), config)
}
}