Commit 106edbac by luoqi

feat(friday): export.sh 支持 --clinics/--since/--months cohort 过滤 — 语义对齐 jvs-dw

文件源宿主的诊所/时间过滤放导出侧(架构约定:host 端 dump 时过滤,PAC 不动):
- cohort 源 = med_emr_info 正式病历(对齐 jvs-dw clinic_scope 挂 EMR 事实表);
  只收窄患者名单,入选患者全部主体/跨诊所/全历史照常导出,谓词按患者求交非行级 AND
- settlement_modes 无患者列经结算头单 IN 子查询挂靠(纪律放行形态)
- SQL 走 stdin(cohort IN 列表会撞 ARG_MAX);空 cohort 拒跑防退化全量;
  cohort 内 0 行表合成表头(mysql --batch 空结果连表头都不出)
- cold-import 文件源传 --clinics/--since 时显式警告(此前静默忽略)
- refresh-clinic-names 改合并语义:子集导出不再刷掉子集外诊所名

实测(刘医生演示诊所 36 患者):EMR 53 份含 4 家其他诊所历史,零越界;
dry-run 15 资源 746 txns 0 failed;空 cohort exit=1;0 行表合成表头可导入。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
parent 1af18042
Pipeline #3401 failed in 0 seconds
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
* 用法: * 用法:
* pnpm refresh-clinic-names -- --dir=./data/jvs-dw [--host=<name 覆盖>] * pnpm refresh-clinic-names -- --dir=./data/jvs-dw [--host=<name 覆盖>]
* *
* 幂等:整表 upsert host.clinicNames(全量覆盖为最新派生结果)。可接 cron 定期刷。 * 幂等:派生结果**合并**进 host.clinicNames(同 key 新值胜,旧 key 保留)。可接 cron 定期刷。
* 合并而非覆盖:文件模式的导出可能是 cohort 子集(export.sh --clinics/--since),
* 覆盖会把子集外诊所的名字刷掉。
*/ */
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core';
import { Logger } from '@nestjs/common'; import { Logger } from '@nestjs/common';
...@@ -121,8 +123,14 @@ async function main(): Promise<void> { ...@@ -121,8 +123,14 @@ async function main(): Promise<void> {
const prisma = app.get(PrismaService); const prisma = app.get(PrismaService);
const host = await prisma.host.findFirst({ where: { name: hostName } }); const host = await prisma.host.findFirst({ where: { name: hostName } });
if (!host) throw new Error(`host "${hostName}" 不存在`); if (!host) throw new Error(`host "${hostName}" 不存在`);
await prisma.host.update({ where: { id: host.id }, data: { clinicNames: clinicMap } }); // 合并而非整表覆盖:导出文件可能是 cohort 子集(export.sh --clinics/--since),
logger.log(`✓ host="${hostName}" clinicNames ${nc} 家(样例: ${Object.values(clinicMap).slice(0, 3).join(' / ')})`); // 覆盖会把子集外诊所的名字刷掉。同 key 新值胜(改名照常生效),旧 key 保留。
const merged = { ...((host.clinicNames as Record<string, string>) ?? {}), ...clinicMap };
await prisma.host.update({ where: { id: host.id }, data: { clinicNames: merged } });
logger.log(
`✓ host="${hostName}" clinicNames 本次派生 ${nc} 家,合并后 ${Object.keys(merged).length} 家` +
`(样例: ${Object.values(clinicMap).slice(0, 3).join(' / ')})`,
);
} finally { } finally {
await app.close(); await app.close();
} }
......
...@@ -903,6 +903,15 @@ export class ColdImportService { ...@@ -903,6 +903,15 @@ export class ColdImportService {
} }
} else { } else {
// ── single-shot 模式(向后兼容 / 文件源)── // ── single-shot 模式(向后兼容 / 文件源)──
// --clinics/--since 挂在 sql_source.cohort(PAC 生成 WHERE);文件源等价物在导出侧
// (如 data/friday/export.sh --clinics/--since,同语义:只收窄患者名单,选中者全史全摄)。
// 这里显式警告而非静默忽略 —— 否则误以为过滤生效,实际全量导入。
if (options.clinics?.length || options.since) {
this.logger.warn(
`--clinics/--since 仅 sql_source.cohort(ClickHouse 直连)支持,当前 manifest 是文件源 → 忽略。` +
`文件源请在导出侧过滤(export.sh --clinics/--since),CSV 落地即已收窄。`,
);
}
await this.processCohort({ await this.processCohort({
absDir, absDir,
manifest, manifest,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment