Skip to main content

dbnexus/database/pool/
mod.rs

1// Copyright (c) 2026 Kirky.X
2//
3// Licensed under the MIT License
4// See LICENSE file in the project root for full license information.
5
6//! 连接池管理模块
7//!
8//! 提供数据库连接池的创建、管理和自动修正功能
9
10mod db_pool;
11mod session;
12
13#[cfg(feature = "duckdb")]
14pub mod duckdb_conn;
15
16use crate::foundation::config::DbConfig;
17
18pub use db_pool::{DatabaseConnection, DbConnection, DbPool, PoolStatus};
19pub use session::Session;
20
21#[cfg(feature = "duckdb")]
22pub use duckdb_conn::{DuckDbConnection, DuckDbExecResult, DuckDbRow};
23
24// 导出迁移执行器供内部使用
25#[cfg(feature = "migration")]
26pub(crate) use crate::database::migration::MigrationExecutor;
27
28// 导入 MetricsCollectorTrait
29#[cfg(feature = "metrics")]
30use crate::observability::metrics::MetricsCollectorTrait;
31
32// 导入 Sea-ORM 的事务 trait 和连接 trait
33pub use sea_orm::{ConnectionTrait, TransactionTrait};
34
35use crate::foundation::error::DbResult;
36use async_trait::async_trait;
37use sea_orm::ExecResult;
38
39#[cfg(any(feature = "metrics", feature = "cache"))]
40use std::sync::Arc;
41
42#[cfg(feature = "cache")]
43use oxcache::Cache;
44
45/// 连接池抽象 trait
46///
47/// 定义连接池的通用接口,便于测试和替换实现
48#[async_trait]
49pub trait ConnectionPool: Send + Sync {
50    /// 获取会话
51    ///
52    /// # Arguments
53    ///
54    /// * `role` - 用户角色
55    ///
56    /// # Returns
57    ///
58    /// 返回数据库会话
59    async fn get_session(&self, role: &str) -> DbResult<Session>;
60
61    /// 获取连接池状态
62    ///
63    /// # Returns
64    ///
65    /// 返回连接池状态信息
66    fn status(&self) -> PoolStatus;
67
68    /// 获取配置
69    ///
70    /// # Returns
71    ///
72    /// 返回连接池配置
73    fn config(&self) -> &DbConfig;
74}
75
76/// 数据库会话抽象 trait
77///
78/// 定义数据库会话的通用接口,便于测试和替换实现
79#[async_trait]
80pub trait DatabaseSession: Send + Sync {
81    /// 执行 SQL(带权限检查)
82    ///
83    /// # Arguments
84    ///
85    /// * `sql` - SQL 语句
86    ///
87    /// # Returns
88    ///
89    /// 返回执行结果
90    async fn execute(&self, sql: &str) -> DbResult<ExecResult>;
91
92    /// 执行原始 SQL(不带权限检查)
93    ///
94    /// # Arguments
95    ///
96    /// * `sql` - SQL 语句
97    ///
98    /// # Returns
99    ///
100    /// 返回执行结果
101    async fn execute_raw(&self, sql: &str) -> DbResult<ExecResult>;
102
103    /// 执行原始 DDL(仅限管理员)
104    ///
105    /// # Arguments
106    ///
107    /// * `sql` - DDL SQL 语句
108    ///
109    /// # Returns
110    ///
111    /// 返回执行结果
112    async fn execute_raw_ddl(&self, sql: &str) -> DbResult<ExecResult>;
113
114    /// 开始事务
115    ///
116    /// # Returns
117    ///
118    /// 返回成功或错误
119    async fn begin_transaction(&self) -> DbResult<()>;
120
121    /// 提交事务
122    ///
123    /// # Returns
124    ///
125    /// 返回成功或错误
126    async fn commit(&self) -> DbResult<()>;
127
128    /// 回滚事务
129    ///
130    /// # Returns
131    ///
132    /// 返回成功或错误
133    async fn rollback(&self) -> DbResult<()>;
134
135    /// 获取角色
136    ///
137    /// # Returns
138    ///
139    /// 返回用户角色
140    fn role(&self) -> &str;
141
142    /// 是否在事务中
143    ///
144    /// # Returns
145    ///
146    /// 返回是否在事务中
147    async fn is_in_transaction(&self) -> bool;
148}
149
150// ============================================================================
151// DbPoolBuilder - 依赖注入构造器
152// ============================================================================
153
154#[cfg(feature = "permission")]
155use crate::access::permission::PermissionConfig;
156#[cfg(feature = "metrics")]
157use crate::observability::metrics::MetricsCollector;
158
159/// DbPool 构造器
160///
161/// 支持部分依赖注入的流式 API 构建模式。
162/// 未注入的依赖将使用默认值。
163///
164/// # Example
165///
166/// ```ignore
167/// use dbnexus::DbPool;
168///
169/// #[tokio::main]
170/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
171///     let pool = DbPool::builder()
172///         .url("sqlite://example.db")
173///         .max_connections(10)
174///         .build()
175///         .await?;
176///     Ok(())
177/// }
178/// ```
179#[derive(Clone, Default)]
180pub struct DbPoolBuilder {
181    /// 数据库连接 URL(可选,如果未提供则需要 config)
182    url: Option<String>,
183    /// 数据库配置(可选,如果提供了 url 则自动创建)
184    config: Option<DbConfig>,
185    /// 指标收集器(可选)
186    #[cfg(feature = "metrics")]
187    metrics_collector: Option<Arc<dyn MetricsCollectorTrait>>,
188    /// 权限配置(可选)
189    #[cfg(feature = "permission")]
190    permission_config: Option<PermissionConfig>,
191    /// 管理员角色名称(可选,默认使用配置中的值)
192    admin_role: Option<String>,
193    /// 缓存实例(用于查询结果缓存)
194    #[cfg(feature = "cache")]
195    cache: Option<Arc<Cache<String, serde_json::Value>>>,
196}
197
198impl DbPoolBuilder {
199    /// 创建新的构造器
200    pub fn new() -> Self {
201        Self::default()
202    }
203
204    /// 设置数据库连接 URL
205    ///
206    /// # Arguments
207    ///
208    /// * `url` - 数据库连接 URL 字符串
209    ///
210    /// # Returns
211    ///
212    /// 返回构造器自身以支持链式调用
213    pub fn url(mut self, url: &str) -> Self {
214        self.url = Some(url.to_string());
215        self
216    }
217
218    /// 设置数据库配置
219    ///
220    /// # Arguments
221    ///
222    /// * `config` - 数据库配置
223    ///
224    /// # Returns
225    ///
226    /// 返回构造器自身以支持链式调用
227    pub fn config(mut self, config: DbConfig) -> Self {
228        self.config = Some(config);
229        self
230    }
231
232    /// 设置指标收集器
233    ///
234    /// # Deprecated
235    ///
236    /// **此 setter 为 no-op**:`build()` 当前不会使用此值(HIGH-001)。
237    /// 请通过 `DbConfig` 或在 `DbPool::with_config()` 创建后注入。
238    #[deprecated(
239        since = "0.3.0",
240        note = "DbPoolBuilder::build() 静默丢弃此值;请通过 DbConfig 或 DbPool::with_config() 后注入"
241    )]
242    #[cfg(feature = "metrics")]
243    pub fn metrics_collector(mut self, metrics_collector: Arc<MetricsCollector>) -> Self {
244        self.metrics_collector = Some(metrics_collector);
245        self
246    }
247
248    /// 设置权限配置
249    ///
250    /// # Deprecated
251    ///
252    /// **此 setter 为 no-op**:`build()` 当前不会使用此值(HIGH-001)。
253    /// 请通过 `DbConfig.permission_config_path` 指定权限配置文件路径。
254    #[deprecated(
255        since = "0.3.0",
256        note = "DbPoolBuilder::build() 静默丢弃此值;请使用 DbConfig.permission_config_path"
257    )]
258    #[cfg(feature = "permission")]
259    pub fn permission_config(mut self, permission_config: PermissionConfig) -> Self {
260        self.permission_config = Some(permission_config);
261        self
262    }
263
264    /// 设置管理员角色名称
265    ///
266    /// # Arguments
267    ///
268    /// * `admin_role` - 管理员角色名称
269    ///
270    /// # Returns
271    ///
272    /// 返回构造器自身以支持链式调用
273    pub fn admin_role(mut self, admin_role: &str) -> Self {
274        if let Some(ref mut config) = self.config {
275            config.admin_role = admin_role.to_string();
276        } else {
277            self.admin_role = Some(admin_role.to_string());
278        }
279        self
280    }
281
282    /// 注入oxcache缓存实例(DI支持)
283    ///
284    /// # Deprecated
285    ///
286    /// **此 setter 为 no-op**:`build()` 当前不会使用此值(HIGH-001)。
287    /// 缓存实例由 `DbPool::with_config()` 根据 `DbConfig.cache_config` 自动创建。
288    #[deprecated(
289        since = "0.3.0",
290        note = "DbPoolBuilder::build() 静默丢弃此值;缓存由 DbPool::with_config() 根据 DbConfig.cache_config 自动创建"
291    )]
292    #[cfg(feature = "cache")]
293    pub fn with_oxcache(mut self, cache: Arc<Cache<String, serde_json::Value>>) -> Self {
294        self.cache = Some(cache);
295        self
296    }
297
298    /// 设置最大连接数
299    ///
300    /// # Arguments
301    ///
302    /// * `max_connections` - 最大连接数
303    ///
304    /// # Returns
305    ///
306    /// 返回构造器自身以支持链式调用
307    pub fn max_connections(mut self, max_connections: u32) -> Self {
308        if let Some(ref mut config) = self.config {
309            config.max_connections = max_connections;
310        } else if let Some(ref url) = self.url {
311            // 如果只有 url,创建一个默认配置然后修改
312            let config = DbConfig {
313                url: url.clone(),
314                max_connections,
315                ..Default::default()
316            };
317            self.config = Some(config);
318        }
319        self
320    }
321
322    /// 设置最小连接数
323    ///
324    /// # Arguments
325    ///
326    /// * `min_connections` - 最小连接数
327    ///
328    /// # Returns
329    ///
330    /// 返回构造器自身以支持链式调用
331    pub fn min_connections(mut self, min_connections: u32) -> Self {
332        if let Some(ref mut config) = self.config {
333            config.min_connections = min_connections;
334        } else if let Some(ref url) = self.url {
335            let config = DbConfig {
336                url: url.clone(),
337                min_connections,
338                ..Default::default()
339            };
340            self.config = Some(config);
341        }
342        self
343    }
344
345    /// 构建 DbPool
346    ///
347    /// # Errors
348    ///
349    /// 如果配置无效或无法连接数据库,返回错误
350    ///
351    /// # Returns
352    ///
353    /// 返回新创建的 DbPool 实例
354    pub async fn build(self) -> DbResult<DbPool> {
355        // 确定最终配置
356        let config = if let Some(config) = self.config {
357            config
358        } else if let Some(url) = self.url {
359            // 从 url 创建默认配置
360            DbConfig {
361                url,
362                max_connections: 20,
363                min_connections: 5,
364                idle_timeout: 300,
365                acquire_timeout: 5000,
366                admin_role: self.admin_role.unwrap_or_else(|| "admin".to_string()),
367                ..Default::default()
368            }
369        } else {
370            return Err(crate::foundation::error::DbError::new(sea_orm::DbErr::Custom(
371                "Either url or config must be provided".to_string(),
372            )));
373        };
374
375        // 创建 pool
376        let pool = DbPool::with_config(config).await?;
377
378        // 注意:以下值已通过 config 设置,不需要额外调用 setter 方法
379        // - admin_role: 在 config 创建时已设置(line 327)
380        // - metrics_collector: 通过 config 或其他方式设置
381        // - permission_config: 在 config 创建时已设置
382
383        Ok(pool)
384    }
385}
386
387impl std::fmt::Debug for DbPoolBuilder {
388    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
389        f.debug_struct("DbPoolBuilder")
390            .field("url", &self.url)
391            .field("config", &self.config.is_some())
392            .field("admin_role", &self.admin_role)
393            .finish()
394    }
395}