Files
delivery-desk/scripts/validate-postgres-migration.ts
yuzhe b0c498fbb6 feat(auth): 添加认证模块和图片批注功能(项目初始化)
- 实现用户登录、登出、密码修改等认证功能
- 添加会话管理和权限控制中间件
- 创建图片批注组件和相关API路由
- 实现批注的增删改查功能
- 添加Docker和Git忽略配置文件
- 创建系统架构文档和开发约定说明
- 集成认证模块到前端应用路由中
2026-07-21 15:28:55 +08:00

47 lines
2.6 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[^;]+;/, '');
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();
}