修正 spec review 发现的问题: - C-1: TestDb 实际是本地 PostgreSQL 隔离,非 Testcontainers - C-2: E2E 已有 4 spec/10 测试,非零测试 - 补充 6 个遗漏的 service(alert/daily_monitoring/critical_value_threshold 等) - 增加 Phase 0 基础设施搭建 - 修正 CI 配置(增加 PostgreSQL service、验证链) - 补充 5 个遗漏风险项和回退策略 - 统一"全量 80%"目标的准确含义
68 lines
2.6 KiB
Rust
68 lines
2.6 KiB
Rust
use sea_orm_migration::prelude::*;
|
||
|
||
#[derive(DeriveMigrationName)]
|
||
pub struct Migration;
|
||
|
||
#[async_trait::async_trait]
|
||
impl MigrationTrait for Migration {
|
||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||
// 分区表必须用 raw SQL,SeaORM schema builder 不支持 PARTITION BY
|
||
let sql = r#"
|
||
CREATE TABLE IF NOT EXISTS device_readings (
|
||
id UUID NOT NULL DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL,
|
||
patient_id UUID NOT NULL,
|
||
device_id VARCHAR(64),
|
||
device_type VARCHAR(32) NOT NULL,
|
||
device_model VARCHAR(64),
|
||
raw_value JSONB NOT NULL,
|
||
measured_at TIMESTAMPTZ NOT NULL,
|
||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
deleted_at TIMESTAMPTZ
|
||
) PARTITION BY RANGE (measured_at);
|
||
"#;
|
||
manager.get_connection().execute_unprepared(sql).await?;
|
||
|
||
// 分区表主键必须包含分区键
|
||
manager.get_connection().execute_unprepared(
|
||
"ALTER TABLE device_readings ADD PRIMARY KEY (id, measured_at);"
|
||
).await?;
|
||
|
||
// 核心查询索引
|
||
manager.get_connection().execute_unprepared(
|
||
"CREATE INDEX idx_dr_tenant_patient ON device_readings (tenant_id, patient_id, measured_at DESC);"
|
||
).await?;
|
||
|
||
manager.get_connection().execute_unprepared(
|
||
"CREATE INDEX idx_dr_device_type ON device_readings (tenant_id, device_type, measured_at DESC);"
|
||
).await?;
|
||
|
||
// 创建初始分区(当前月 + 未来 3 个月)
|
||
for (suffix, start, end) in [
|
||
("2026_05", "2026-05-01", "2026-06-01"),
|
||
("2026_06", "2026-06-01", "2026-07-01"),
|
||
("2026_07", "2026-07-01", "2026-08-01"),
|
||
("2026_08", "2026-08-01", "2026-09-01"),
|
||
] {
|
||
let partition_sql = format!(
|
||
"CREATE TABLE IF NOT EXISTS device_readings_{suffix} PARTITION OF device_readings FOR VALUES FROM ('{start}') TO ('{end}');"
|
||
);
|
||
manager.get_connection().execute_unprepared(&partition_sql).await?;
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
|
||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||
for suffix in ["2026_05", "2026_06", "2026_07", "2026_08"] {
|
||
manager.get_connection().execute_unprepared(
|
||
&format!("DROP TABLE IF EXISTS device_readings_{suffix};")
|
||
).await.ok();
|
||
}
|
||
manager.get_connection().execute_unprepared(
|
||
"DROP TABLE IF EXISTS device_readings;"
|
||
).await?;
|
||
Ok(())
|
||
}
|
||
}
|