ai-chatbot/scripts/system-settings/restore-snapshot.ts
2026-05-29 16:52:40 +08:00

104 lines
2.5 KiB
TypeScript

import { config as loadEnv } from "dotenv";
import { eq } from "drizzle-orm";
loadEnv({ path: ".env.local" });
function readArg(name: string) {
const prefix = `${name}=`;
const match = process.argv.find((arg) => arg.startsWith(prefix));
return match ? match.slice(prefix.length) : null;
}
async function main() {
const snapshotId = readArg("--snapshot-id");
const reason = readArg("--reason") || "manual-snapshot-restore";
if (!snapshotId) {
throw new Error(
"Usage: pnpm tsx scripts/system-settings/restore-snapshot.ts --snapshot-id=<id> [--reason=<reason>]"
);
}
const dbModule = await import("../../lib/db");
const schemaModule = await import("../../lib/db/schema");
const { db } = dbModule;
const { systemSettingHistory, systemSettingSnapshot, systemSettings } = schemaModule;
const [snapshot] = await db
.select({
id: systemSettingSnapshot.id,
scope: systemSettingSnapshot.scope,
data: systemSettingSnapshot.data,
})
.from(systemSettingSnapshot)
.where(eq(systemSettingSnapshot.id, snapshotId))
.limit(1);
if (!snapshot) {
throw new Error(`Snapshot not found: ${snapshotId}`);
}
const data =
snapshot.data && typeof snapshot.data === "object" && !Array.isArray(snapshot.data)
? (snapshot.data as Record<string, unknown>)
: {};
const keys = Object.keys(data);
await db.transaction(async (tx) => {
for (const key of keys) {
const [existing] = await tx
.select({ value: systemSettings.value })
.from(systemSettings)
.where(eq(systemSettings.key, key))
.limit(1);
const nextValue = data[key] ?? null;
await tx.insert(systemSettingHistory).values({
key,
previousValue: existing?.value ?? null,
nextValue,
reason,
changedAt: new Date(),
changedBy: null,
});
await tx
.insert(systemSettings)
.values({
key,
value: nextValue,
updatedAt: new Date(),
updatedBy: null,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: nextValue,
updatedAt: new Date(),
updatedBy: null,
},
});
}
});
console.log(
JSON.stringify(
{
snapshotId,
scope: snapshot.scope,
restoredKeyCount: keys.length,
reason,
},
null,
2
)
);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});