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= [--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) : {}; 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); });