Files
delivery-desk/scripts/validate-postgres-migration.ts

48 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import fs from 'node:fs';
import path from 'node:path';
import Database from 'better-sqlite3';
import { newDb } from 'pg-mem';
const tables = [
'operation_groups', 'users', 'projects', 'collections', 'notes', 'images', 'annotations',
'work_comments', 'work_versions', 'review_events', 'sessions', 'customer_sessions',
'audit_logs', 'api_keys', 'storage_configs',
] as const;
const booleanColumns: Record<string, Set<string>> = {
users: new Set(['must_change_password']), projects: new Set(['customer_access_enabled']),
};
const memory = newDb({ autoCreateForeignKeyIndices: true });
const adapter = memory.adapters.createPg();
const client = new adapter.Client();
const sqlite = new Database(path.resolve('data/app.db'), { readonly: true });
try {
await client.connect();
const schema = fs.readFileSync(path.resolve('db/postgres/schema.sql'), 'utf8')
.replace(/^BEGIN;|COMMIT;$/gm, '')
.replace(/CREATE UNIQUE INDEX IF NOT EXISTS one_active_storage_config[^;]+;/, '')
.replace(/-- COLLECTION_STATUS_REPAIR_START[\s\S]+?-- COLLECTION_STATUS_REPAIR_END/, '');
await client.query(schema);
for (const table of tables) {
const exists = sqlite.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(table);
if (!exists) continue;
const rows = sqlite.prepare(`SELECT * FROM "${table}" ORDER BY id`).all() as Record<string, unknown>[];
for (const row of rows) {
const columns = Object.keys(row);
const values = columns.map((column) => booleanColumns[table]?.has(column) ? Boolean(row[column]) : row[column]);
await client.query(`INSERT INTO "${table}" (${columns.map((column) => `"${column}"`).join(',')}) VALUES (${columns.map((_, index) => `$${index + 1}`).join(',')})`, values);
}
const pgCount = Number((await client.query(`SELECT COUNT(*)::int AS count FROM "${table}"`)).rows[0].count);
if (pgCount !== rows.length) throw new Error(`${table} 行数不一致SQLite=${rows.length}, PostgreSQL=${pgCount}`);
}
const current = (await client.query(`SELECT n.version_number,n.review_status,i.storage_provider FROM notes n JOIN images i ON i.note_id=n.id AND i.version_number=n.version_number WHERE n.id=1 LIMIT 1`)).rows[0];
if (!current || Number(current.version_number) < 1) throw new Error('作品版本关系未正确迁移');
const activeStorage = Number((await client.query("SELECT COUNT(*)::int AS count FROM storage_configs WHERE status='active'")).rows[0].count);
if (activeStorage > 1) throw new Error('活动对象存储配置超过一个');
process.stdout.write(`PostgreSQL schema 与迁移映射验证通过:${tables.length} 张表,当前作品 V${current.version_number},存储=${current.storage_provider}\n`);
} finally {
sqlite.close();
await client.end();
}