mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-25 17:54:34 +08:00
84 lines
2.3 KiB
TypeScript
84 lines
2.3 KiB
TypeScript
/**
|
|
* 数据库迁移框架(平台无关)
|
|
*
|
|
* 提供 Schema 版本检测和通用迁移执行逻辑。
|
|
* 具体的迁移脚本由运行时注册,迁移本身只依赖 DatabaseAdapter。
|
|
*/
|
|
|
|
import type { DatabaseAdapter } from '../interfaces'
|
|
|
|
/** 迁移脚本接口 */
|
|
export interface Migration {
|
|
version: number
|
|
description: string
|
|
up: (db: DatabaseAdapter) => void
|
|
}
|
|
|
|
/**
|
|
* 读取数据库的 schema 版本
|
|
*/
|
|
export function getSchemaVersion(db: DatabaseAdapter): number {
|
|
try {
|
|
const tableInfo = db.pragma('table_info(meta)') as Array<{ name: string }>
|
|
const hasVersionColumn = tableInfo.some((col) => col.name === 'schema_version')
|
|
if (!hasVersionColumn) return 0
|
|
|
|
const result = db.prepare('SELECT schema_version FROM meta LIMIT 1').get() as
|
|
| { schema_version: number | null }
|
|
| undefined
|
|
return result?.schema_version ?? 0
|
|
} catch {
|
|
return 0
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 设置数据库的 schema 版本
|
|
*/
|
|
export function setSchemaVersion(db: DatabaseAdapter, version: number): void {
|
|
const tableInfo = db.pragma('table_info(meta)') as Array<{ name: string }>
|
|
const hasVersionColumn = tableInfo.some((col) => col.name === 'schema_version')
|
|
|
|
if (!hasVersionColumn) {
|
|
db.exec('ALTER TABLE meta ADD COLUMN schema_version INTEGER DEFAULT 0')
|
|
}
|
|
|
|
db.prepare('UPDATE meta SET schema_version = ?').run(version)
|
|
}
|
|
|
|
/**
|
|
* 检查数据库是否需要迁移
|
|
*/
|
|
export function needsMigration(db: DatabaseAdapter, targetVersion: number): boolean {
|
|
return getSchemaVersion(db) < targetVersion
|
|
}
|
|
|
|
/**
|
|
* 执行数据库迁移
|
|
*
|
|
* @param db 数据库适配器
|
|
* @param migrationsList 迁移脚本列表(由调用方提供,可包含平台特定逻辑)
|
|
* @param forceRepair 是否强制修复
|
|
* @returns 是否执行了迁移
|
|
*/
|
|
export function runMigrations(db: DatabaseAdapter, migrationsList: Migration[], forceRepair = false): boolean {
|
|
const currentVersion = getSchemaVersion(db)
|
|
|
|
if (!forceRepair && currentVersion >= (migrationsList.at(-1)?.version ?? 0)) {
|
|
return false
|
|
}
|
|
|
|
const pending = forceRepair ? migrationsList : migrationsList.filter((m) => m.version > currentVersion)
|
|
|
|
if (pending.length === 0) return false
|
|
|
|
db.transaction(() => {
|
|
for (const migration of pending) {
|
|
migration.up(db)
|
|
setSchemaVersion(db, migration.version)
|
|
}
|
|
})
|
|
|
|
return true
|
|
}
|