mod db_pool;
mod session;
#[cfg(feature = "duckdb")]
pub mod duckdb_conn;
use crate::foundation::config::DbConfig;
pub use db_pool::{DatabaseConnection, DbConnection, DbPool, PoolStatus};
pub use session::Session;
#[cfg(feature = "duckdb")]
pub use duckdb_conn::{DuckDbConnection, DuckDbExecResult, DuckDbRow};
#[cfg(feature = "migration")]
pub(crate) use crate::database::migration::MigrationExecutor;
#[cfg(feature = "metrics")]
use crate::observability::metrics::MetricsCollectorTrait;
pub use sea_orm::{ConnectionTrait, TransactionTrait};
use crate::foundation::error::DbResult;
use async_trait::async_trait;
use sea_orm::ExecResult;
use std::sync::Arc;
#[cfg(feature = "cache")]
use oxcache::Cache;
#[async_trait]
pub trait ConnectionPool: Send + Sync {
async fn get_session(&self, role: &str) -> DbResult<Session>;
fn status(&self) -> PoolStatus;
fn config(&self) -> &DbConfig;
}
#[async_trait]
pub trait DatabaseSession: Send + Sync {
async fn execute(&self, sql: &str) -> DbResult<ExecResult>;
async fn execute_raw(&self, sql: &str) -> DbResult<ExecResult>;
async fn execute_raw_ddl(&self, sql: &str) -> DbResult<ExecResult>;
async fn begin_transaction(&self) -> DbResult<()>;
async fn commit(&self) -> DbResult<()>;
async fn rollback(&self) -> DbResult<()>;
fn role(&self) -> &str;
async fn is_in_transaction(&self) -> bool;
}
#[cfg(feature = "permission")]
use crate::access::permission::PermissionConfig;
#[cfg(feature = "metrics")]
use crate::observability::metrics::MetricsCollector;
#[derive(Clone, Default)]
pub struct DbPoolBuilder {
url: Option<String>,
config: Option<DbConfig>,
#[cfg(feature = "metrics")]
metrics_collector: Option<Arc<dyn MetricsCollectorTrait>>,
#[cfg(feature = "permission")]
permission_config: Option<PermissionConfig>,
admin_role: Option<String>,
#[cfg(feature = "cache")]
cache: Option<Arc<Cache<String, serde_json::Value>>>,
}
impl DbPoolBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn url(mut self, url: &str) -> Self {
self.url = Some(url.to_string());
self
}
pub fn config(mut self, config: DbConfig) -> Self {
self.config = Some(config);
self
}
#[deprecated(
since = "0.3.0",
note = "DbPoolBuilder::build() 静默丢弃此值;请通过 DbConfig 或 DbPool::with_config() 后注入"
)]
#[cfg(feature = "metrics")]
pub fn metrics_collector(mut self, metrics_collector: Arc<MetricsCollector>) -> Self {
self.metrics_collector = Some(metrics_collector);
self
}
#[deprecated(
since = "0.3.0",
note = "DbPoolBuilder::build() 静默丢弃此值;请使用 DbConfig.permission_config_path"
)]
#[cfg(feature = "permission")]
pub fn permission_config(mut self, permission_config: PermissionConfig) -> Self {
self.permission_config = Some(permission_config);
self
}
pub fn admin_role(mut self, admin_role: &str) -> Self {
if let Some(ref mut config) = self.config {
config.admin_role = admin_role.to_string();
} else {
self.admin_role = Some(admin_role.to_string());
}
self
}
#[deprecated(
since = "0.3.0",
note = "DbPoolBuilder::build() 静默丢弃此值;缓存由 DbPool::with_config() 根据 DbConfig.cache_config 自动创建"
)]
#[cfg(feature = "cache")]
pub fn with_oxcache(mut self, cache: Arc<Cache<String, serde_json::Value>>) -> Self {
self.cache = Some(cache);
self
}
pub fn max_connections(mut self, max_connections: u32) -> Self {
if let Some(ref mut config) = self.config {
config.max_connections = max_connections;
} else if let Some(ref url) = self.url {
let config = DbConfig {
url: url.clone(),
max_connections,
..Default::default()
};
self.config = Some(config);
}
self
}
pub fn min_connections(mut self, min_connections: u32) -> Self {
if let Some(ref mut config) = self.config {
config.min_connections = min_connections;
} else if let Some(ref url) = self.url {
let config = DbConfig {
url: url.clone(),
min_connections,
..Default::default()
};
self.config = Some(config);
}
self
}
pub async fn build(self) -> DbResult<DbPool> {
let config = if let Some(config) = self.config {
config
} else if let Some(url) = self.url {
DbConfig {
url,
max_connections: 20,
min_connections: 5,
idle_timeout: 300,
acquire_timeout: 5000,
admin_role: self.admin_role.unwrap_or_else(|| "admin".to_string()),
..Default::default()
}
} else {
return Err(crate::foundation::error::DbError::new(sea_orm::DbErr::Custom(
"Either url or config must be provided".to_string(),
)));
};
let pool = DbPool::with_config(config).await?;
Ok(pool)
}
}
impl std::fmt::Debug for DbPoolBuilder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DbPoolBuilder")
.field("url", &self.url)
.field("config", &self.config.is_some())
.field("admin_role", &self.admin_role)
.finish()
}
}