UNPKG

lipgrate

Version:

Lipgrate is a clean and safe migration toolkit for SQL databases. Designed to be readable, minimal, and powerful.

88 lines (69 loc) 3.02 kB
const fs = require('fs'); const path = require('path'); const { getDbAdapter } = require('../../adapters'); const { translate } = require('../../common/translators'); const { loadConfig } = require('../../common/config'); const logger = require('../../common/logger'); const chalk = require('chalk'); const { describe } = require('../../common/operation_logger'); async function execute(args, options = {}) { const db = getDbAdapter(); const client = await db.getClient(); const runnerOptions = { ...options, client }; try { await client.query('BEGIN'); const config = loadConfig(); const migrationsDir = path.resolve(process.cwd(), config.migrations.directory, config.client); if (!fs.existsSync(migrationsDir)) { fs.mkdirSync(migrationsDir, { recursive: true }); logger.info(`Created database-specific migration directory: ${migrationsDir}`); logger.success('Database is up to date.'); return; } const allMigrations = fs.readdirSync(migrationsDir) .filter(file => file.endsWith('.js')) .sort(); for (const migrationFile of allMigrations) { if (!migrationFile.startsWith('lipgrade_')) { throw new Error(`Invalid migration file name: '${migrationFile}'. Please use 'node src/cli.js create' to generate migrations.`); } } if (runnerOptions.dryRun) { logger.info(chalk.yellow('Dry Run Mode: No changes will be made to the database.')); } await db.ensureMigrationsTable(runnerOptions); const completedMigrations = runnerOptions.dryRun ? [] : await db.getCompletedMigrations(runnerOptions); const pendingMigrations = allMigrations.filter(m => !completedMigrations.includes(m)); if (pendingMigrations.length === 0) { logger.success('Database is up to date.'); return; } logger.info(`Found ${pendingMigrations.length} pending migrations.`); for (const migrationFile of pendingMigrations) { const migrationPath = path.join(migrationsDir, migrationFile); const migration = require(migrationPath); logger.running(`Running migration: ${migrationFile}`); // This block handles both declarative and programmatic migrations. const operations = Array.isArray(migration.up) ? migration.up : [migration.up]; for (const op of operations) { logger.info(` -> ${describe(op)}`); const sql = translate(op, config.client); await db.query(sql, [], runnerOptions); } // Log the migration only after all its operations have succeeded. await db.addMigration(migrationFile, runnerOptions); logger.success(`Finished migration: ${migrationFile}`); } logger.success('All migrations completed successfully.'); await client.query('COMMIT'); } catch (e) { await client.query('ROLLBACK'); throw e; // Re-throw the original error to be caught by the CLI } finally { if (client) { client.release(); } await db.disconnect(); } } module.exports = { execute };