- 0035: subscription.last_progress_at, acquisition_slot.position (primary version)
- GET /subscriptions: server-side groups + counts, card fields, sort/filter, offset cursor
- GET /subscriptions/{id}/coverage: season x episode (movie: edition) x slot matrix, 30s cache
- auto-fill for non-primary slots: inherit/on/off, per-subscription daily budget, upgrade priority
- params normalization with MP/legacy aliases; duplicate 409; pause/resume/resubscribe/batch/fill/slot-order
Co-Authored-By: Claude Opus 5.5 <[email protected]>
49 lines
2.1 KiB
TypeScript
49 lines
2.1 KiB
TypeScript
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<any>): Promise<void> {
|
|
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<any>): Promise<void> {
|
|
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;
|
|
`,
|
|
);
|
|
}
|