import { type Kysely, sql } from "kysely"; // 首个迁移:底座四张表。gen_random_uuid() 为 PG13+ 内置 // biome-ignore lint/suspicious/noExplicitAny: 迁移不依赖应用表类型 export async function up(db: Kysely): Promise { await db.schema .createTable("settings") .addColumn("key", "text", (c) => c.primaryKey()) .addColumn("value", "jsonb", (c) => c.notNull()) .addColumn("updated_at", "timestamptz", (c) => c.notNull().defaultTo(sql`now()`)) .execute(); await db.schema .createTable("api_key") .addColumn("id", "uuid", (c) => c.primaryKey().defaultTo(sql`gen_random_uuid()`)) .addColumn("name", "text", (c) => c.notNull()) .addColumn("key_hash", "text", (c) => c.notNull().unique()) .addColumn("scopes", sql`text[]`, (c) => c.notNull().defaultTo(sql`'{}'::text[]`)) .addColumn("created_at", "timestamptz", (c) => c.notNull().defaultTo(sql`now()`)) .addColumn("revoked_at", "timestamptz") .addColumn("last_used_at", "timestamptz") .execute(); await db.schema .createTable("audit_event") .addColumn("id", "uuid", (c) => c.primaryKey().defaultTo(sql`gen_random_uuid()`)) .addColumn("at", "timestamptz", (c) => c.notNull().defaultTo(sql`now()`)) .addColumn("actor_type", "text", (c) => c.notNull()) .addColumn("actor_id", "text") .addColumn("action", "text", (c) => c.notNull()) .addColumn("target_type", "text") .addColumn("target_id", "text") .addColumn("payload", "jsonb", (c) => c.notNull().defaultTo(sql`'{}'::jsonb`)) .addColumn("trace_id", "text") .execute(); await db.schema.createIndex("audit_event_at_idx").on("audit_event").column("at").execute(); await db.schema .createIndex("audit_event_target_idx") .on("audit_event") .columns(["target_type", "target_id"]) .execute(); await db.schema .createTable("outbox_event") .addColumn("id", "uuid", (c) => c.primaryKey().defaultTo(sql`gen_random_uuid()`)) .addColumn("at", "timestamptz", (c) => c.notNull().defaultTo(sql`now()`)) .addColumn("type", "text", (c) => c.notNull()) .addColumn("payload", "jsonb", (c) => c.notNull().defaultTo(sql`'{}'::jsonb`)) .addColumn("published_at", "timestamptz") .execute(); // 只索引未投递的事件,投递器按时间顺序扫描 await db.schema .createIndex("outbox_event_pending_idx") .on("outbox_event") .column("at") .where(sql.ref("published_at"), "is", null) .execute(); } // biome-ignore lint/suspicious/noExplicitAny: 同上 export async function down(db: Kysely): Promise { await db.schema.dropTable("outbox_event").ifExists().execute(); await db.schema.dropTable("audit_event").ifExists().execute(); await db.schema.dropTable("api_key").ifExists().execute(); await db.schema.dropTable("settings").ifExists().execute(); }