Spaces:
Paused
Paused
| const fs = require("fs"); | |
| const path = require("path"); | |
| function listSqlFiles(directory) { | |
| if (!fs.existsSync(directory)) { | |
| return []; | |
| } | |
| return fs | |
| .readdirSync(directory) | |
| .filter((name) => name.toLowerCase().endsWith(".sql")) | |
| .sort((a, b) => a.localeCompare(b, "en")); | |
| } | |
| async function ensureTrackingTable(pool, tableName) { | |
| if (!["schema_migrations", "seed_runs"].includes(tableName)) { | |
| throw new Error(`Unsupported migration tracking table: ${tableName}`); | |
| } | |
| await pool.query(` | |
| CREATE TABLE IF NOT EXISTS ${tableName} ( | |
| id BIGSERIAL PRIMARY KEY, | |
| filename TEXT NOT NULL UNIQUE, | |
| applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | |
| ) | |
| `); | |
| } | |
| async function readApplied(pool, tableName) { | |
| const result = await pool.query(`SELECT filename FROM ${tableName}`); | |
| return new Set(result.rows.map((row) => row.filename)); | |
| } | |
| async function executeSqlFile(pool, filePath) { | |
| const sql = fs.readFileSync(filePath, "utf8"); | |
| await pool.query(sql); | |
| } | |
| async function runSqlDirectory(pool, options) { | |
| const { directory, trackingTable, logger, label } = options; | |
| await ensureTrackingTable(pool, trackingTable); | |
| const applied = await readApplied(pool, trackingTable); | |
| const files = listSqlFiles(directory); | |
| let appliedCount = 0; | |
| for (const filename of files) { | |
| if (applied.has(filename)) { | |
| logger.debug(`${label} already applied`, { filename }); | |
| continue; | |
| } | |
| const absolutePath = path.join(directory, filename); | |
| logger.info(`Applying ${label}`, { filename }); | |
| await executeSqlFile(pool, absolutePath); | |
| await pool.query(`INSERT INTO ${trackingTable}(filename) VALUES ($1)`, [filename]); | |
| appliedCount += 1; | |
| } | |
| return { | |
| totalFiles: files.length, | |
| appliedCount, | |
| }; | |
| } | |
| async function runMigrations(pool, migrationsDir, logger) { | |
| return runSqlDirectory(pool, { | |
| directory: migrationsDir, | |
| trackingTable: "schema_migrations", | |
| logger, | |
| label: "migration", | |
| }); | |
| } | |
| async function runSeeds(pool, seedsDir, logger) { | |
| return runSqlDirectory(pool, { | |
| directory: seedsDir, | |
| trackingTable: "seed_runs", | |
| logger, | |
| label: "seed", | |
| }); | |
| } | |
| module.exports = { | |
| runMigrations, | |
| runSeeds, | |
| }; | |