refactor: improve SQLite migration handling and update .gitignore

This commit is contained in:
cita
2026-03-07 00:29:56 +08:00
parent 1e12ec5211
commit 98a2936416
4 changed files with 63 additions and 14 deletions
+34 -9
View File
@@ -2,14 +2,39 @@ import Database from 'better-sqlite3';
import { drizzle } from 'drizzle-orm/better-sqlite3';
import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
import { config } from '../config.js';
import { mkdirSync } from 'fs';
import { dirname } from 'path';
import { mkdirSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const dbPath = `${config.dataDir}/hub.db`;
mkdirSync(dirname(dbPath), { recursive: true });
function resolveSqliteDbPath(): string {
const raw = (config.dbUrl || '').trim();
if (!raw) return resolve(`${config.dataDir}/hub.db`);
if (raw === ':memory:') return raw;
if (raw.startsWith('file://')) {
const parsed = new URL(raw);
return decodeURIComponent(parsed.pathname);
}
if (raw.startsWith('sqlite://')) {
return resolve(raw.slice('sqlite://'.length).trim());
}
return resolve(raw);
}
const sqlite = new Database(dbPath);
const db = drizzle(sqlite);
migrate(db, { migrationsFolder: './drizzle' });
sqlite.close();
console.log('Migration complete.');
function resolveMigrationsFolder(): string {
return resolve(dirname(fileURLToPath(import.meta.url)), '../../../drizzle');
}
export function runSqliteMigrations(): void {
const dbPath = resolveSqliteDbPath();
if (dbPath !== ':memory:') {
mkdirSync(dirname(dbPath), { recursive: true });
}
const sqlite = new Database(dbPath);
const db = drizzle(sqlite);
migrate(db, { migrationsFolder: resolveMigrationsFolder() });
sqlite.close();
console.log('Migration complete.');
}
runSqliteMigrations();
+22 -3
View File
@@ -24,9 +24,22 @@ import { buildStartupSummaryLines } from './services/startupInfo.js';
import { repairStoredCreatedAtValues } from './services/storedTimestampRepairService.js';
import { isPublicApiRoute, registerDesktopRoutes } from './desktop.js';
import { existsSync } from 'fs';
import { normalize, resolve, sep } from 'path';
import { fileURLToPath } from 'url';
import { dirname, normalize, resolve, sep } from 'path';
import { db, ensureProxyLogBillingDetailsColumn, runtimeDbDialect, schema, switchRuntimeDatabase, type RuntimeDbDialect } from './db/index.js';
let sqliteMigrationsBootstrapped = false;
async function ensureSqliteRuntimeMigrations() {
if (runtimeDbDialect !== 'sqlite') return;
const migrateModule = await import('./db/migrate.js');
if (sqliteMigrationsBootstrapped) {
migrateModule.runSqliteMigrations();
return;
}
sqliteMigrationsBootstrapped = true;
}
function toSettingsMap(rows: Array<{ key: string; value: string }>) {
return new Map(rows.map((row) => [row.key, row.value]));
}
@@ -171,6 +184,9 @@ function applyRuntimeSettings(settingsMap: Map<string, string>) {
}
}
// Ensure sqlite tables exist before reading runtime settings.
await ensureSqliteRuntimeMigrations();
// Load runtime config overrides from settings
try {
const initialRows = await db.select().from(schema.settings).all();
@@ -180,6 +196,7 @@ try {
if (savedDbConfig && (savedDbConfig.dialect !== runtimeDbDialect || savedDbConfig.dbUrl !== activeDbUrl || savedDbConfig.ssl !== config.dbSsl)) {
try {
await switchRuntimeDatabase(savedDbConfig.dialect, savedDbConfig.dbUrl, savedDbConfig.ssl);
await ensureSqliteRuntimeMigrations();
console.log(`Loaded runtime DB config from settings: ${savedDbConfig.dialect}`);
} catch (error) {
console.warn(`Failed to switch runtime DB from settings: ${(error as Error)?.message || 'unknown error'}`);
@@ -193,7 +210,9 @@ try {
await repairStoredCreatedAtValues();
console.log('Loaded runtime settings overrides');
} catch { /* first run, table may not exist */ }
} catch (error) {
console.warn(`Failed to load runtime settings overrides: ${(error as Error)?.message || 'unknown error'}`);
}
const app = Fastify({ logger: true });
@@ -227,7 +246,7 @@ await app.register(downstreamApiKeysRoutes);
await app.register(proxyRoutes);
// Serve static web frontend in production
const webDir = resolve('dist/web');
const webDir = resolve(dirname(fileURLToPath(import.meta.url)), '../web');
if (existsSync(webDir)) {
await app.register(fastifyStatic, {
root: webDir,