Skip to main content

yggdrasil/db/
mod.rs

1//! 数据库连接模块。
2//!
3//! 连接池、重试和迁移仅在 `server` feature 下编译;WASM 前端无需数据库占位实现。
4
5/// 错误格式化工具:把 `std::error::Error` 的 source 链完整展开为字符串。
6///
7/// 存在的原因:`tokio_postgres::Error` 的 `Display` 对 DB 侧错误只会打印
8/// 无信息量的占位串 `db error`,真正的消息文本(如
9/// `column "x" of relation "y" already exists`、SQLSTATE、约束名)藏在
10/// `source()` 链里的 `postgres::error::DbError`。不主动遍历链,日志和错误
11/// 字符串就会全部折叠成 `db error`,无法定位失败原因。
12///
13/// 用法:`format!("...: {}", format_with_sources(&e))` 或直接
14/// `format_with_sources(&e)` 得到完整的 `e: cause: deeper cause`。
15#[cfg(feature = "server")]
16pub fn format_with_sources(e: &dyn std::error::Error) -> String {
17    use std::fmt::Write;
18    let mut s = e.to_string();
19    let mut cur: &dyn std::error::Error = e;
20    while let Some(next) = cur.source() {
21        // 跳过与外层 Display 完全相同的占位层(如 tokio_postgres 的 `db error`),
22        // 避免输出 `db error: db error` 这种重复。只在能带来新信息时追加。
23        let next_disp = next.to_string();
24        if !next_disp.is_empty() && next_disp != s {
25            let _ = write!(s, ": {next_disp}");
26        }
27        cur = next;
28    }
29    s
30}
31
32/// 真实的 PostgreSQL 连接池实现,仅在启用 server feature 时编译。
33#[cfg(feature = "server")]
34pub mod pool;
35
36/// 连接获取的指数退避重试策略,仅在启用 server feature 时编译。
37#[cfg(feature = "server")]
38pub mod retry;
39
40/// 数据库迁移运行器,仅在启用 server feature 时编译。
41#[cfg(feature = "server")]
42pub mod migrate;