|
|
|
@ -3,11 +3,16 @@ import { mkdirSync, appendFileSync } from 'fs';
|
|
|
|
import { join } from 'path';
|
|
|
|
import { join } from 'path';
|
|
|
|
import { migrations, type Migration } from './migrations';
|
|
|
|
import { migrations, type Migration } from './migrations';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const MIGRATIONS_LOG_LEVEL = (process.env.MIGRATIONS_LOG_LEVEL || '').toLowerCase();
|
|
|
|
|
|
|
|
const MIGRATIONS_QUIET = process.env.NODE_ENV === 'test' || MIGRATIONS_LOG_LEVEL === 'silent';
|
|
|
|
|
|
|
|
|
|
|
|
function nowIso(): string {
|
|
|
|
function nowIso(): string {
|
|
|
|
return new Date().toISOString().replace('T', ' ').replace('Z', '');
|
|
|
|
return new Date().toISOString().replace('T', ' ').replace('Z', '');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function logEvent(level: 'info' | 'error', event: string, data: any = {}) {
|
|
|
|
function logEvent(level: 'info' | 'error', event: string, data: any = {}) {
|
|
|
|
|
|
|
|
// En modo test o nivel 'silent', no registrar eventos para evitar ruido
|
|
|
|
|
|
|
|
if (MIGRATIONS_QUIET) return;
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
mkdirSync('data', { recursive: true });
|
|
|
|
mkdirSync('data', { recursive: true });
|
|
|
|
} catch {}
|
|
|
|
} catch {}
|
|
|
|
@ -64,10 +69,10 @@ function backupDatabaseIfNeeded(db: Database): string | null {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
// VACUUM INTO hace copia consistente del estado actual
|
|
|
|
// VACUUM INTO hace copia consistente del estado actual
|
|
|
|
db.exec(`VACUUM INTO '${backupPath.replace(/'/g, "''")}'`);
|
|
|
|
db.exec(`VACUUM INTO '${backupPath.replace(/'/g, "''")}'`);
|
|
|
|
console.log(`ℹ️ Backup de base de datos creado en: ${backupPath}`);
|
|
|
|
if (!MIGRATIONS_QUIET) console.log(`ℹ️ Backup de base de datos creado en: ${backupPath}`);
|
|
|
|
return backupPath;
|
|
|
|
return backupPath;
|
|
|
|
} catch (e) {
|
|
|
|
} catch (e) {
|
|
|
|
console.warn('⚠️ No se pudo crear el backup con VACUUM INTO (continuando de todos modos):', e);
|
|
|
|
if (!MIGRATIONS_QUIET) console.warn('⚠️ No se pudo crear el backup con VACUUM INTO (continuando de todos modos):', e);
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -100,7 +105,7 @@ export const Migrator = {
|
|
|
|
const jmRow = db.query(`PRAGMA journal_mode`).get() as any;
|
|
|
|
const jmRow = db.query(`PRAGMA journal_mode`).get() as any;
|
|
|
|
const journalMode = jmRow ? (jmRow.journal_mode || jmRow.value || jmRow.mode || 'unknown') : 'unknown';
|
|
|
|
const journalMode = jmRow ? (jmRow.journal_mode || jmRow.value || jmRow.mode || 'unknown') : 'unknown';
|
|
|
|
const currentVersion = applied.size ? Math.max(...Array.from(applied.keys())) : 0;
|
|
|
|
const currentVersion = applied.size ? Math.max(...Array.from(applied.keys())) : 0;
|
|
|
|
console.log(`ℹ️ Migrador — journal_mode=${journalMode}, versión_actual=${currentVersion}, pendientes=${pending.length}`);
|
|
|
|
if (!MIGRATIONS_QUIET) console.log(`ℹ️ Migrador — journal_mode=${journalMode}, versión_actual=${currentVersion}, pendientes=${pending.length}`);
|
|
|
|
try { logEvent('info', 'startup_summary', { journal_mode: journalMode, current_version: currentVersion, pending: pending.length }); } catch {}
|
|
|
|
try { logEvent('info', 'startup_summary', { journal_mode: journalMode, current_version: currentVersion, pending: pending.length }); } catch {}
|
|
|
|
|
|
|
|
|
|
|
|
if (applied.size === 0 && allowBaseline && detectExistingSchema(db)) {
|
|
|
|
if (applied.size === 0 && allowBaseline && detectExistingSchema(db)) {
|
|
|
|
@ -109,14 +114,14 @@ export const Migrator = {
|
|
|
|
db.transaction(() => {
|
|
|
|
db.transaction(() => {
|
|
|
|
insertMigrationRow(db, v1);
|
|
|
|
insertMigrationRow(db, v1);
|
|
|
|
})();
|
|
|
|
})();
|
|
|
|
console.log('ℹ️ Baseline aplicado: schema_migrations marcada en v1 (sin ejecutar up)');
|
|
|
|
if (!MIGRATIONS_QUIET) console.log('ℹ️ Baseline aplicado: schema_migrations marcada en v1 (sin ejecutar up)');
|
|
|
|
try { logEvent('info', 'baseline_applied', { version: 1 }); } catch {}
|
|
|
|
try { logEvent('info', 'baseline_applied', { version: 1 }); } catch {}
|
|
|
|
// Recalcular pendientes
|
|
|
|
// Recalcular pendientes
|
|
|
|
pending.splice(0, pending.length, ...migrations.filter(m => m.version > 1));
|
|
|
|
pending.splice(0, pending.length, ...migrations.filter(m => m.version > 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (pending.length === 0) {
|
|
|
|
if (pending.length === 0) {
|
|
|
|
console.log('ℹ️ No hay migraciones pendientes');
|
|
|
|
if (!MIGRATIONS_QUIET) console.log('ℹ️ No hay migraciones pendientes');
|
|
|
|
try { logEvent('info', 'no_pending', {}); } catch {}
|
|
|
|
try { logEvent('info', 'no_pending', {}); } catch {}
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -127,7 +132,7 @@ export const Migrator = {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const mig of pending) {
|
|
|
|
for (const mig of pending) {
|
|
|
|
console.log(`➡️ Aplicando migración v${mig.version} - ${mig.name}`);
|
|
|
|
if (!MIGRATIONS_QUIET) console.log(`➡️ Aplicando migración v${mig.version} - ${mig.name}`);
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
try { logEvent('info', 'apply_start', { version: mig.version, name: mig.name, checksum: mig.checksum }); } catch {}
|
|
|
|
try { logEvent('info', 'apply_start', { version: mig.version, name: mig.name, checksum: mig.checksum }); } catch {}
|
|
|
|
const t0 = Date.now();
|
|
|
|
const t0 = Date.now();
|
|
|
|
@ -141,7 +146,7 @@ export const Migrator = {
|
|
|
|
insertMigrationRow(db, mig);
|
|
|
|
insertMigrationRow(db, mig);
|
|
|
|
})();
|
|
|
|
})();
|
|
|
|
const ms = Date.now() - t0;
|
|
|
|
const ms = Date.now() - t0;
|
|
|
|
console.log(`✅ Migración v${mig.version} aplicada (${ms} ms)`);
|
|
|
|
if (!MIGRATIONS_QUIET) console.log(`✅ Migración v${mig.version} aplicada (${ms} ms)`);
|
|
|
|
try { logEvent('info', 'apply_success', { version: mig.version, name: mig.name, checksum: mig.checksum, duration_ms: ms }); } catch {}
|
|
|
|
try { logEvent('info', 'apply_success', { version: mig.version, name: mig.name, checksum: mig.checksum, duration_ms: ms }); } catch {}
|
|
|
|
} catch (e) {
|
|
|
|
} catch (e) {
|
|
|
|
console.error(`❌ Error aplicando migración v${mig.version}:`, e);
|
|
|
|
console.error(`❌ Error aplicando migración v${mig.version}:`, e);
|
|
|
|
|