Files
budget-app/db/migrations/001_initial_schema.js
Christian Hood adebe10f52 Add PostgreSQL schema and migration runner
All tables per PRD data model with default config seeds.
Migration runner tracks applied migrations in DB.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 19:03:57 -04:00

52 lines
1.4 KiB
JavaScript

const fs = require('fs');
const path = require('path');
async function runMigrations(pool) {
// Create migrations tracking table if it doesn't exist
await pool.query(`
CREATE TABLE IF NOT EXISTS migrations (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
`);
// Read all .sql files in this directory, sorted by name
const migrationsDir = __dirname;
const sqlFiles = fs
.readdirSync(migrationsDir)
.filter((f) => f.endsWith('.sql'))
.sort();
for (const file of sqlFiles) {
// Check if this migration has already been applied
const { rows } = await pool.query(
'SELECT id FROM migrations WHERE name = $1',
[file]
);
if (rows.length > 0) {
continue; // already applied
}
const sql = fs.readFileSync(path.join(migrationsDir, file), 'utf8');
// Run the migration in a transaction
const client = await pool.connect();
try {
await client.query('BEGIN');
await client.query(sql);
await client.query('INSERT INTO migrations (name) VALUES ($1)', [file]);
await client.query('COMMIT');
console.log(`Migration applied: ${file}`);
} catch (err) {
await client.query('ROLLBACK');
throw new Error(`Migration failed for ${file}: ${err.message}`);
} finally {
client.release();
}
}
}
module.exports = { runMigrations };