Files
photo-live/services/api/test/reset-ov.ts
T
浅念 4db90b0e9e feat(sync): ov inbox ad 分支与 sender adId 推导(disabled/墓碑=删投影行)
- dto.ts SYNC_ENTITY_TYPES 追加 'ad'(对齐契约 SyncEntityType)。
- decideAndApply ③依赖检查豁免 ad:albumId 恒空串,不豁免则事件被永久
  暂存且无解锁路径(slot-state 同款空 albumId 危害)。
- project() 新增 ad 分支:全量快照直投 ads_ov;墓碑或 enabled=false 均
  deleteMany(disabled=公开不可见=无投影);albumIds 整体替换;createdAt
  取 cn 原值、updatedAt 为 ov 应用时刻(载荷无该字段)。
- sender.toWireEvent 新增 ad 分支:entityId 取载荷 adId(outbox 表无列),
  泛化 categoryId/assetId 兜底之前,缺料 fail-fast。
- e2e ads.e2e-spec:手工构造 outbox 行(绕过 CRUD,Task 7 才有)走真实
  sender→HTTP→inbox 链路,5 用例覆盖快照落位/disable 删行/复活 upsert/
  迟到旧版本不回滚/墓碑删行;reset-ov 增清 ads_ov。
- db-ov schema 附带注释修:ads_ov updatedAt 语义纠正(迁移头过度声明,
  迁移文件不动防 checksum 漂移)+ sync_inbox.entityType 枚举补 ad。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-28 23:18:37 +08:00

55 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// services/api/test/reset-ov.ts —— ov 库(photo_ov)e2e 隔离工具(P2 Task 2)。
// 与 reset.ts 镜像但独立成文件:两库连接串不同(DATABASE_URL_OV vs _CN),
// RESET_TABLES 互不重叠,cn/ov spec 各自 beforeAll 调用,互不清对方的数据。
// 与 reset.ts 的两点差异:
// 1. 无 MinIO 清理——ov 侧 P2 只读对象(签名 URL 指向同一 MinIO,上传仍归
// cn 侧 e2e 的前缀清理负责);
// 2. truncate-if-exists——经 information_schema 取「库中实际存在的待重置表」
// 再逐表 TRUNCATE(MySQL 无 TRUNCATE IF EXISTS):首次迁移前的空库上
// 调用是 no-op 而非报错,ov 库生命周期独立于 cn 库(compose profile ov)。
// ov 全库扁平字符串外键、无 FK 约束,FOREIGN_KEY_CHECKS 包裹仅沿用 reset.ts
// 的防御性约定(后续如引入约束同样安全);表序仍按逻辑依赖排列(子表在前)。
import { PrismaClient } from '@photo/db-ov';
export const RESET_TABLES_OV: readonly string[] = [
// 统计回传队列与互动流水(Task 7-9 的幂等锚点)。
'outbox_stat_events',
'visit_requests',
'visit_sessions',
'like_batches',
'album_stats',
// 同步账本(Task 4 inbox 消费)。
'sync_inbox',
'sync_state',
// 副本域(photos 先于 albums;展示位/广告位副本相册无关,随副本域一并清)。
'photos_ov',
'albums_ov',
'embed_slots_ov',
'ads_ov',
];
/** TRUNCATE photo_ov 中 RESET_TABLES_OV 里**实际存在**的表(空库安全)。 */
export async function resetOvDb(): Promise<void> {
const prisma = new PrismaClient();
try {
const placeholders = RESET_TABLES_OV.map(() => '?').join(', ');
const existing = await prisma.$queryRawUnsafe<
{ tableName: string }[]
>(
`SELECT TABLE_NAME AS tableName FROM information_schema.TABLES ` +
`WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME IN (${placeholders})`,
...RESET_TABLES_OV,
);
await prisma.$executeRawUnsafe('SET FOREIGN_KEY_CHECKS = 0');
try {
for (const { tableName } of existing) {
await prisma.$executeRawUnsafe(`TRUNCATE TABLE \`${tableName}\``);
}
} finally {
await prisma.$executeRawUnsafe('SET FOREIGN_KEY_CHECKS = 1');
}
} finally {
await prisma.$disconnect();
}
}