mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-26 02:04:37 +08:00
129 lines
4.1 KiB
TypeScript
129 lines
4.1 KiB
TypeScript
/**
|
|
* Database migration — Electron adapter layer.
|
|
*
|
|
* Thin wrapper around @openchatlab/node-runtime shared migration definitions.
|
|
* Keeps Electron-only concerns: i18n MigrationInfo, better-sqlite3 type bridging.
|
|
*/
|
|
|
|
import type Database from 'better-sqlite3'
|
|
import {
|
|
CURRENT_SCHEMA_VERSION,
|
|
getSchemaVersion,
|
|
runMigrations,
|
|
needsMigration as coreNeedsMigration,
|
|
} from '@openchatlab/core'
|
|
import type { DatabaseAdapter, PathProvider } from '@openchatlab/core'
|
|
import { BetterSqliteAdapter } from '@openchatlab/node-runtime/src/better-sqlite3-adapter'
|
|
import {
|
|
CHAT_DB_COMPATIBILITY_RAISES,
|
|
getChatDbMigrations,
|
|
} from '@openchatlab/node-runtime/src/migrations/chat-db-migrations'
|
|
import { raiseDataDirMinRuntimeVersion, type RuntimeIdentity } from '@openchatlab/node-runtime/src/data-dir-compat'
|
|
import { t } from '../i18n'
|
|
import { tokenizeForFts } from '@openchatlab/node-runtime/src/nlp/fts-tokenizer'
|
|
|
|
export { CURRENT_SCHEMA_VERSION }
|
|
|
|
export interface MigrationInfo {
|
|
version: number
|
|
description: string
|
|
userMessage: string
|
|
}
|
|
|
|
export interface DesktopMigrationOptions {
|
|
pathProvider?: PathProvider
|
|
runtime?: RuntimeIdentity
|
|
}
|
|
|
|
const i18nKeys: Record<number, { descriptionKey: string; userMessageKey: string }> = Object.fromEntries(
|
|
Array.from({ length: CURRENT_SCHEMA_VERSION }, (_, index) => {
|
|
const version = index + 1
|
|
return [
|
|
version,
|
|
{
|
|
descriptionKey: `database.migrationV${version}Desc`,
|
|
userMessageKey: `database.migrationV${version}Message`,
|
|
},
|
|
]
|
|
})
|
|
)
|
|
|
|
function checkDatabaseIntegrity(db: DatabaseAdapter): { valid: boolean; error?: string } {
|
|
try {
|
|
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='meta'").all() as Array<{
|
|
name: string
|
|
}>
|
|
if (tables.length === 0) {
|
|
return { valid: false, error: t('database.integrityError') }
|
|
}
|
|
return { valid: true }
|
|
} catch (error) {
|
|
return {
|
|
valid: false,
|
|
error: t('database.checkFailed', { error: error instanceof Error ? error.message : String(error) }),
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute database migrations.
|
|
* Wraps better-sqlite3 Database in a DatabaseAdapter and delegates to core runMigrations
|
|
* with shared migration definitions from @openchatlab/node-runtime.
|
|
*/
|
|
export function migrateDatabase(
|
|
db: Database.Database,
|
|
forceRepair = false,
|
|
options: DesktopMigrationOptions = {}
|
|
): boolean {
|
|
const adapter = new BetterSqliteAdapter(db)
|
|
|
|
const integrity = checkDatabaseIntegrity(adapter)
|
|
if (!integrity.valid) {
|
|
throw new Error(integrity.error)
|
|
}
|
|
|
|
const beforeVersion = getSchemaVersion(adapter)
|
|
const migrations = getChatDbMigrations({ tokenizeForFts })
|
|
const migrated = runMigrations(adapter, migrations, forceRepair)
|
|
if (!migrated || !options.pathProvider || !options.runtime) return migrated
|
|
|
|
const afterVersion = getSchemaVersion(adapter)
|
|
for (const compatibilityRaise of CHAT_DB_COMPATIBILITY_RAISES) {
|
|
if (beforeVersion >= compatibilityRaise.migrationVersion || afterVersion < compatibilityRaise.migrationVersion) {
|
|
continue
|
|
}
|
|
|
|
raiseDataDirMinRuntimeVersion(options.pathProvider, {
|
|
minRuntimeVersion: compatibilityRaise.minRuntimeVersion,
|
|
dataCompatibilityVersion: compatibilityRaise.dataCompatibilityVersion,
|
|
reason: compatibilityRaise.reason,
|
|
runtime: options.runtime,
|
|
module: compatibilityRaise.module,
|
|
})
|
|
}
|
|
|
|
return migrated
|
|
}
|
|
|
|
export function needsMigration(db: Database.Database): boolean {
|
|
const adapter = new BetterSqliteAdapter(db)
|
|
return coreNeedsMigration(adapter, CURRENT_SCHEMA_VERSION)
|
|
}
|
|
|
|
/**
|
|
* Get pending migration info for UI display (with i18n).
|
|
*/
|
|
export function getPendingMigrationInfos(fromVersion = 0): MigrationInfo[] {
|
|
const migrations = getChatDbMigrations({ tokenizeForFts })
|
|
return migrations
|
|
.filter((m) => m.version > fromVersion)
|
|
.map((m) => {
|
|
const keys = i18nKeys[m.version]
|
|
return {
|
|
version: m.version,
|
|
description: (keys && t(keys.descriptionKey)) || m.description,
|
|
userMessage: (keys && t(keys.userMessageKey)) || m.description,
|
|
}
|
|
})
|
|
}
|