import type { Kysely } from "kysely"; import { execDdl } from "../src/migration-helpers.ts"; // W9-E 订阅重做(docs/design/subscriptions.md §1、§2.2、§5): // - subscription.last_progress_at:总览"上次更新"。任一关联版本目标的单元转为已入库、或总集数变化时写入; // 计划预留时间由查询侧取 max(acquisition_plan.created_at) 合并,不在这里冗余;空 = 取 created_at。 // 存量订阅按分集账本与计划时间回填一次。 // - acquisition_slot.position:同一订阅内版本目标的顺序,最小者为主版本(自动补全只约束非主版本); // 存量按 created_at 编号,与原"第一个版本目标"口径一致。 // biome-ignore lint/suspicious/noExplicitAny: 迁移不依赖应用表类型 export async function up(db: Kysely): Promise { await execDdl( db, ` alter table subscription add column last_progress_at timestamptz; create index subscription_last_progress_idx on subscription (coalesce(last_progress_at, created_at) desc); alter table acquisition_slot add column position integer not null default 0 check (position >= 0); update acquisition_slot s set position = x.n from (select id, (row_number() over (partition by media_entity_id, subscription_id order by created_at, id) - 1)::int as n from acquisition_slot) x where x.id = s.id; update subscription sub set last_progress_at = x.at from (select s.subscription_id as id, greatest(max(su.updated_at), max(p.created_at)) as at from acquisition_slot s left join slot_unit su on su.slot_id = s.id and su.media_asset_id is not null left join acquisition_plan p on p.slot_id = s.id and p.status <> 'draft' where s.subscription_id is not null group by s.subscription_id) x where x.id = sub.id and x.at is not null; `, ); } // biome-ignore lint/suspicious/noExplicitAny: 同上 export async function down(db: Kysely): Promise { await execDdl( db, ` alter table acquisition_slot drop column if exists position; drop index if exists subscription_last_progress_idx; alter table subscription drop column if exists last_progress_at; `, ); }