本项目展示了如何在 Rust 中构建一个健壮、类型安全的数据库访问层,特别适用于需要严格数据验证的医疗领域应用。通过抽象接口和具体实现分离的设计,系统可以轻松扩展支持更多类型的数据库,同时保证了代码的可维护性和可测试性。

核心设计概念

  1. 类型安全的数据结构

项目中定义了几个关键的类型安全封装:

  • BoundedString: 限制长度的字符串类型
  • FixedLengthString: 固定长度的字符串类型
  • DicomDateString: 专门用于 DICOM 日期格式的字符串类型
// 示例:BoundedString 的定义
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct BoundedString<const N: usize> {
    value: String,
}
  1. 统一的数据库访问接口

通过 DbProvider trait 抽象了数据库操作接口:

#[async_trait]
pub trait DbProvider: Send + Sync {
    async fn save_state_info(&self, state_meta: &DicomStateMeta) -> Result<(), DbError>;
    async fn save_state_list(&self, state_meta: &[DicomStateMeta]) -> Result<(), DbError>;
    async fn save_json_list(&self, state_meta: &[DicomJsonMeta]) -> Result<(), DbError>;
    // ... 其他方法
}
  1. 数据库类型适配

MySQL MySqlDbProvider 结构体实现了针对 MySQL 数据库的操作:

pub struct MySqlDbProvider {
    db_connection_string: String,
}

#[async_trait]
impl DbProvider for MySqlDbProvider {
    // 实现各种数据库操作方法
}

PostgreSQL PgDbProvider 结构体提供了对 PostgreSQL 数据库的支持:

pub struct PgDbProvider {
    db_connection_string: String,
}

#[async_trait]
impl DbProvider for PgDbProvider {
    // 实现各种数据库操作方法
}
  1. 关键数据模型 DICOM 状态元数据 DicomStateMeta 结构体包含了患者、检查、序列级别的元数据信息:
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DicomStateMeta {
    pub tenant_id: BoundedString<64>,
    pub patient_id: BoundedString<64>,
    pub study_uid: BoundedString<64>,
    pub series_uid: BoundedString<64>,
    // ...
}

DICOM 影像元数据 DicomImageMeta 结构体存储了实例级别的影像相关信息:

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DicomImageMeta {
    pub tenant_id: BoundedString<64>,
    pub patient_id: BoundedString<64>,
    pub study_uid: BoundedString<64>,
    pub series_uid: BoundedString<64>,
    pub sop_uid: BoundedString<64>,
    // ...
}

技术亮点

1. 编译时类型安全

通过 Rust 的泛型和类型系统,在编译时就能捕获许多潜在的数据错误:

2. 异步数据库操作

所有数据库操作都采用异步方式实现,提高系统并发性能:

3. 统一错误处理

使用 thiserrorsnafu 库统一处理各种错误情况:

项目结构

database/ ├── src/ │ ├── dicom_dbprovider.rs # 数据库提供者trait定义 │ ├── dicom_dbtype.rs # 自定义数据库类型 │ ├── dicom_meta.rs # DICOM元数据结构定义 │ ├── dicom_mysql.rs # MySQL实现 │ ├── dicom_mysql_types.rs # MySQL类型适配 │ ├── dicom_pg.rs # PostgreSQL实现 │ ├── dicom_pg_types.rs # PostgreSQL类型适配 │ └── lib.rs # 库入口文件 └── Cargo.toml # 项目配置文件

Cargo.toml 配置如下:

[package]
name = "database"
version = "0.1.0"
edition = "2024"

[dependencies]
md5 = { workspace = true }
const-crc32 = { workspace = true }
snafu = { workspace = true }
uuid = { workspace = true, features = ["v4", "v7", "fast-rng"] }
serde_json = "1.0.145"
serde = { workspace = true, features = ["derive"] }
config = { workspace = true }  # 配置文件解析
dotenv = { workspace = true }
clap = { workspace = true, features = ["derive"] }
dicom-core = { workspace = true }
dicom-ul = { workspace = true, features = ["async"] }
dicom-object = { workspace = true }
dicom-encoding = { workspace = true }
dicom-pixeldata = { workspace = true, 
features = ["native", "jpeg", "rle", "image", "jpegxl", "openjp2", "rayon", "deflate"] }
dicom-dictionary-std = { workspace = true }
dicom-transfer-syntax-registry = { workspace = true }
seahash = { workspace = true }
async-trait = { workspace = true }
tracing = { workspace = true }
tokio = { workspace = true, features = ["full"] }
urlencoding = { workspace = true }
url = { workspace = true }
slog = { workspace = true }
slog-term = { workspace = true }
slog-async = { workspace = true }
slog-stdlog = { workspace = true }
slog-scope = { workspace = true }
rdkafka = { workspace = true }
futures = { workspace = true }
futures-util = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
rayon = { workspace = true }
thiserror = { workspace = true }
encoding_rs = { workspace = true }
gdcm_conv = { workspace = true }
rstest = { workspace = true }
openssl = { workspace = true, features = ["v102", "vendored"] }  # 自带 OpenSSL,无需额外安装
x509-parser = { workspace = true }  # 请检查最新版本
der = { workspace = true }
pem = { workspace = true }
hex = { workspace = true } # x509-parser 可能依赖它
regex = { workspace = true }
lazy_static = { workspace = true }
tempfile = { workspace = true }
reqwest = { workspace = true, features = ["json"] }
aes-gcm = { workspace = true }
rand = { workspace = true }
base64 = { workspace = true }
cipher = "0.4.4"
salsa20 = "0.10.2"
generic-array = "0.14.7"
chrono-tz = "0.10.4"
tokio-postgres = { 
    version = "0.7.15",
    features = ["default", "with-time-0_3", "with-uuid-1", "with-chrono-0_4"] 
}
postgres-types = "0.2.11"
mysql = { 
    version = "26.0.1", 
    default-features = false, 
    features = ["minimal-rust", "rustls-tls","chrono","time"] 
}
ctor = "0.6.1"

下一节将详细介绍数据库类型定义和实现。

DICOM-Cloud Part ONE Database-TypeDefines