feat: align with upstream 1.5.9.9

This commit is contained in:
2026-09-12 18:21:11 +08:00
commit 34f0679117
805 changed files with 376275 additions and 0 deletions
+181
View File
@@ -0,0 +1,181 @@
#!/usr/bin/env node
/**
* 数据库完全重置脚本
* 删除所有表(含迁移记录表),然后从头执行迁移
* 使用方式: pnpm run db:reset
*/
import { execSync } from 'child_process'
import path from 'path'
import { config } from 'dotenv'
import postgres from 'postgres'
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
cyan: '\x1b[36m'
}
const log = (msg, color = 'reset') => console.log(`${colors[color]}${msg}${colors.reset}`)
const ok = (msg) => log(`✅ ${msg}`, 'green')
const warn = (msg) => log(`⚠️ ${msg}`, 'yellow')
const err = (msg) => log(`❌ ${msg}`, 'red')
const args = process.argv.slice(2)
const forceFlag = args.includes('--force')
// 禁止在 CI 中执行(防止误触发导致生产库被清空)
if (process.env.CI && !forceFlag) {
err('拒绝在 CI 环境中执行数据库重置;如确需强制,请使用 --force 标志并确认 CI 配置正确')
process.exit(1)
}
if (!forceFlag) {
err('危险操作:此脚本将清空整库数据')
err('请添加 --force 标志确认执行:pnpm run db:reset -- --force')
process.exit(1)
}
config({ path: path.resolve(process.cwd(), '.env') })
const NON_INTERACTIVE_ENV = {
...process.env,
CI: 'true',
DRIZZLE_KIT_FORCE: 'true',
NODE_ENV: process.env.NODE_ENV || 'production'
}
function safeExec(command, options = {}) {
try {
execSync(command, { stdio: 'inherit', ...options })
return true
} catch {
return false
}
}
function createSqlClient() {
return postgres(process.env.DATABASE_URL, { max: 1 })
}
async function dropAllTables(sql) {
log('获取 public schema 下所有表...', 'cyan')
const tables = await sql`
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_type = 'BASE TABLE'
ORDER BY table_name
`
if (tables.length === 0) {
warn('没有找到任何表')
return
}
log(`发现 ${tables.length} 张表,准备逐个删除(含 __drizzle_migrations__)...`, 'cyan')
for (const row of tables) {
const tableName = row.table_name
await sql.unsafe(`DROP TABLE IF EXISTS "${tableName}" CASCADE`)
log(` - ${tableName}`, 'reset')
}
ok(`已删除 ${tables.length} 张表`)
}
async function dropAllEnums(sql) {
log('清理枚举类型...', 'cyan')
const enums = await sql`
SELECT t.typname
FROM pg_type t
JOIN pg_namespace n ON n.oid = t.typnamespace
WHERE n.nspname = 'public'
AND t.typtype = 'e'
ORDER BY t.typname
`
if (enums.length === 0) {
return
}
for (const row of enums) {
await sql.unsafe(`DROP TYPE IF EXISTS "${row.typname}" CASCADE`)
log(` - ${row.typname}`, 'reset')
}
ok(`已清理 ${enums.length} 个枚举类型`)
}
async function dropAllSequences(sql) {
log('清理序列...', 'cyan')
const sequences = await sql`
SELECT sequence_name
FROM information_schema.sequences
WHERE sequence_schema = 'public'
ORDER BY sequence_name
`
if (sequences.length === 0) {
return
}
for (const row of sequences) {
await sql.unsafe(`DROP SEQUENCE IF EXISTS "${row.sequence_name}"`)
log(` - ${row.sequence_name}`, 'reset')
}
ok(`已清理 ${sequences.length} 个序列`)
}
async function main() {
if (!process.env.DATABASE_URL) {
err('未设置 DATABASE_URL 环境变量')
process.exit(1)
}
log('⚠️ 此操作将删除数据库所有表(含迁移记录),并从头重建', 'red')
const dbUrl = (process.env.DATABASE_URL || '')
.replace(/(postgresql:\/\/[^:@]+):[^@]+@/, '$1:***@')
.replace(/(postgres:\/\/[^:@]+):[^@]+@/, '$1:***@')
log(`目标数据库: ${dbUrl}`, 'cyan')
log('🔄 开始数据库完全重置...', 'bright')
const sql = createSqlClient()
try {
// 1. 删除所有表
await dropAllTables(sql)
// 2. 删除所有枚举
await dropAllEnums(sql)
// 3. 删除所有序列
await dropAllSequences(sql)
// 4. 从头执行迁移
log('📋 从头执行数据库迁移...', 'cyan')
if (!safeExec('pnpm run db:migrate', { env: NON_INTERACTIVE_ENV })) {
err('数据库迁移失败')
process.exit(1)
}
ok('数据库完全重置并迁移成功!')
ok('数据库现已处于全新初始状态')
} catch (error) {
err(`重置失败: ${error.message || error}`)
process.exit(1)
} finally {
await sql.end()
}
}
main().catch((e) => {
err(`未预期的错误: ${e.message || e}`)
process.exit(1)
})