|
| 1 | +/** |
| 2 | + * Migration 013: Add missing columns to audit_log for pre-3.7 SQLite databases |
| 3 | + * |
| 4 | + * The Drizzle schema expects ip_address and user_agent columns on audit_log, |
| 5 | + * but databases created before the v3.7 baseline may not have them. |
| 6 | + * Migration 012 added username but missed these two. |
| 7 | + * |
| 8 | + * PostgreSQL/MySQL baselines already include these columns, so those are no-ops. |
| 9 | + */ |
| 10 | +import type { Database } from 'better-sqlite3'; |
| 11 | +import { logger } from '../../utils/logger.js'; |
| 12 | + |
| 13 | +// ============ SQLite ============ |
| 14 | + |
| 15 | +export const migration = { |
| 16 | + up: (db: Database): void => { |
| 17 | + logger.info('Running migration 013 (SQLite): Adding missing audit_log columns...'); |
| 18 | + |
| 19 | + // 1. Add ip_address to audit_log |
| 20 | + try { |
| 21 | + db.exec('ALTER TABLE audit_log ADD COLUMN ip_address TEXT'); |
| 22 | + logger.debug('Added ip_address column to audit_log'); |
| 23 | + } catch (e: any) { |
| 24 | + if (e.message?.includes('duplicate column')) { |
| 25 | + logger.debug('audit_log.ip_address already exists, skipping'); |
| 26 | + } else { |
| 27 | + logger.warn('Could not add ip_address to audit_log:', e.message); |
| 28 | + } |
| 29 | + } |
| 30 | + |
| 31 | + // 2. Add user_agent to audit_log |
| 32 | + try { |
| 33 | + db.exec('ALTER TABLE audit_log ADD COLUMN user_agent TEXT'); |
| 34 | + logger.debug('Added user_agent column to audit_log'); |
| 35 | + } catch (e: any) { |
| 36 | + if (e.message?.includes('duplicate column')) { |
| 37 | + logger.debug('audit_log.user_agent already exists, skipping'); |
| 38 | + } else { |
| 39 | + logger.warn('Could not add user_agent to audit_log:', e.message); |
| 40 | + } |
| 41 | + } |
| 42 | + |
| 43 | + logger.info('Migration 013 complete (SQLite): audit_log columns aligned'); |
| 44 | + }, |
| 45 | + |
| 46 | + down: (_db: Database): void => { |
| 47 | + logger.debug('Migration 013 down: Not implemented (destructive column drops)'); |
| 48 | + } |
| 49 | +}; |
| 50 | + |
| 51 | +// ============ PostgreSQL ============ |
| 52 | + |
| 53 | +export async function runMigration013Postgres(client: import('pg').PoolClient): Promise<void> { |
| 54 | + logger.info('Running migration 013 (PostgreSQL): Ensuring audit_log columns exist...'); |
| 55 | + |
| 56 | + try { |
| 57 | + await client.query('ALTER TABLE audit_log ADD COLUMN IF NOT EXISTS "ipAddress" TEXT'); |
| 58 | + await client.query('ALTER TABLE audit_log ADD COLUMN IF NOT EXISTS "userAgent" TEXT'); |
| 59 | + logger.debug('Ensured ipAddress/userAgent exist on audit_log'); |
| 60 | + } catch (error: any) { |
| 61 | + logger.error('Migration 013 (PostgreSQL) failed:', error.message); |
| 62 | + throw error; |
| 63 | + } |
| 64 | + |
| 65 | + logger.info('Migration 013 complete (PostgreSQL): audit_log columns aligned'); |
| 66 | +} |
| 67 | + |
| 68 | +// ============ MySQL ============ |
| 69 | + |
| 70 | +export async function runMigration013Mysql(pool: import('mysql2/promise').Pool): Promise<void> { |
| 71 | + logger.info('Running migration 013 (MySQL): Ensuring audit_log columns exist...'); |
| 72 | + |
| 73 | + try { |
| 74 | + const [ipRows] = await pool.query(` |
| 75 | + SELECT COLUMN_NAME FROM information_schema.COLUMNS |
| 76 | + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_log' AND COLUMN_NAME = 'ipAddress' |
| 77 | + `); |
| 78 | + if (!Array.isArray(ipRows) || ipRows.length === 0) { |
| 79 | + await pool.query('ALTER TABLE audit_log ADD COLUMN ipAddress TEXT'); |
| 80 | + logger.debug('Added ipAddress to audit_log'); |
| 81 | + } else { |
| 82 | + logger.debug('audit_log.ipAddress already exists, skipping'); |
| 83 | + } |
| 84 | + |
| 85 | + const [uaRows] = await pool.query(` |
| 86 | + SELECT COLUMN_NAME FROM information_schema.COLUMNS |
| 87 | + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_log' AND COLUMN_NAME = 'userAgent' |
| 88 | + `); |
| 89 | + if (!Array.isArray(uaRows) || uaRows.length === 0) { |
| 90 | + await pool.query('ALTER TABLE audit_log ADD COLUMN userAgent TEXT'); |
| 91 | + logger.debug('Added userAgent to audit_log'); |
| 92 | + } else { |
| 93 | + logger.debug('audit_log.userAgent already exists, skipping'); |
| 94 | + } |
| 95 | + } catch (error: any) { |
| 96 | + logger.error('Migration 013 (MySQL) failed:', error.message); |
| 97 | + throw error; |
| 98 | + } |
| 99 | + |
| 100 | + logger.info('Migration 013 complete (MySQL): audit_log columns aligned'); |
| 101 | +} |
0 commit comments