use std::any::type_name;
use std::time::Duration;
use eyre::{OptionExt, Result};
use sea_orm::{ConnectOptions, DatabaseConnection};
use tracing::log::LevelFilter;
use crate::contracts::{Application, Service};
use crate::foundation::application::config;
use crate::services::{Redis, service};
async fn connection() -> Result<DatabaseConnection> {
let config = config()?.get::<crate::config::Database>("database")?;
let mut opt = ConnectOptions::new(config.uri);
opt.max_connections(config.max_connections)
.min_connections(config.min_connections)
.connect_timeout(Duration::from_secs(config.connect_timeout))
.acquire_timeout(Duration::from_secs(config.acquire_timeout.unwrap_or(8)))
.idle_timeout(Duration::from_secs(config.idle_timeout))
.max_lifetime(Duration::from_secs(config.max_lifetime))
.sqlx_logging(config.enable_logging)
.sqlx_logging_level(LevelFilter::Debug);
Ok(sea_orm::Database::connect(opt).await?)
}
pub struct Database(DatabaseConnection);
impl Service for Database {
fn register<A: Application + ?Sized>() -> Self
where
Self: Sized,
{
let connection = A::runtime()
.block_on(connection())
.unwrap_or_else(|err| panic!("{}", err));
tracing::info!("[service] {} booting", type_name::<Self>());
Database(connection)
}
fn boot<A: Application + ?Sized>() -> Result<()>
where
Self: Sized,
{
let db = service()
.get::<Database>()
.ok_or_eyre("failed to get db service")?;
A::runtime().block_on(db.ping())?;
tracing::info!("[service] {} booted", type_name::<Self>());
Ok(())
}
}
impl Database {
pub fn connection(&self) -> &DatabaseConnection {
&self.0
}
pub async fn ping(&self) -> Result<()> {
assert!(self.connection().ping().await.is_ok());
Ok(())
}
}