本项目展示了如何在 Rust 中构建一个健壮、类型安全的数据库访问层,特别适用于需要严格数据验证的医疗领域应用。通过抽象接口和具体实现分离的设计,系统可以轻松扩展支持更多类型的数据库,同时保证了代码的可维护性和可测试性。
核心设计概念
- 类型安全的数据结构
项目中定义了几个关键的类型安全封装:
- BoundedString: 限制长度的字符串类型
- FixedLengthString: 固定长度的字符串类型
- DicomDateString: 专门用于 DICOM 日期格式的字符串类型
// 示例:BoundedString 的定义
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct BoundedString<const N: usize> {
value: String,
}
- 统一的数据库访问接口
通过 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>;
// ... 其他方法
}
- 数据库类型适配
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 {
// 实现各种数据库操作方法
}
- 关键数据模型 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. 统一错误处理
使用 thiserror 和 snafu 库统一处理各种错误情况:
项目结构
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"
下一节将详细介绍数据库类型定义和实现。