Files
DLE/backend/scripts/run-migrations.js

125 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const fs = require('fs').promises;
const path = require('path');
require('dotenv').config();
const { getPool } = require('../db');
const pool = getPool();
const logger = require('../utils/logger');
async function runMigrations() {
try {
console.log('Запуск миграций...');
// Создаем таблицу для отслеживания миграций, если её нет
await pool.query(`
CREATE TABLE IF NOT EXISTS migrations (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
// Получаем список выполненных миграций
const { rows } = await pool.query('SELECT name FROM migrations');
const executedMigrations = new Set(rows.map((row) => row.name));
// Читаем файлы миграций
const migrationsDir = path.join(__dirname, '../db/migrations');
const files = await fs.readdir(migrationsDir);
// Сортируем файлы по номеру
const migrationFiles = files
.filter((f) => f.endsWith('.sql'))
.sort((a, b) => {
const numA = parseInt(a.split('_')[0]);
const numB = parseInt(b.split('_')[0]);
return numA - numB;
});
// Выполняем миграции
for (const file of migrationFiles) {
if (!executedMigrations.has(file)) {
const filePath = path.join(migrationsDir, file);
const fileContent = await fs.readFile(filePath, 'utf-8');
// Ищем начало UP секции (или начало файла)
const upMarker = '-- UP Migration';
const downMarker = '-- DOWN Migration';
let upSqlStartIndex = fileContent.indexOf(upMarker);
if (upSqlStartIndex !== -1) {
// Ищем перевод строки после маркера
let newlineIndex = fileContent.indexOf('\n', upSqlStartIndex);
if (newlineIndex === -1) { // Если маркер в последней строке
newlineIndex = fileContent.length;
}
upSqlStartIndex = newlineIndex + 1; // Начинаем со следующей строки
} else {
upSqlStartIndex = 0; // Если маркера нет, берем все с начала
}
// Ищем конец UP секции (начало DOWN секции)
let upSqlEndIndex = fileContent.indexOf(downMarker);
if (upSqlEndIndex === -1) {
upSqlEndIndex = fileContent.length; // Если маркера DOWN нет, берем все до конца
}
// Извлекаем только UP SQL
const sqlToExecute = fileContent.substring(upSqlStartIndex, upSqlEndIndex).trim();
if (!sqlToExecute) {
logger.warn(`Migration file ${file} has no executable UP SQL content. Skipping.`);
continue; // Пропускаем пустые миграции
}
logger.info(`Executing UP migration from ${file}...`);
await pool.query('BEGIN');
try {
// Выполняем только извлеченный UP SQL
await pool.query(sqlToExecute);
await pool.query('INSERT INTO migrations (name) VALUES ($1)', [file]);
await pool.query('COMMIT');
logger.info(`Migration ${file} executed successfully`);
} catch (error) {
await pool.query('ROLLBACK');
logger.error(`Error executing migration ${file}:`, error); // Логируем ошибку перед пробросом
throw error;
}
}
}
// Выполняем SQL-функции
const functionsDir = path.join(migrationsDir, 'functions');
if (
await fs
.stat(functionsDir)
.then(() => true)
.catch(() => false)
) {
const functionFiles = await fs.readdir(functionsDir);
for (const file of functionFiles) {
if (file.endsWith('.sql')) {
const filePath = path.join(functionsDir, file);
const sql = await fs.readFile(filePath, 'utf-8');
try {
await pool.query(sql);
logger.info(`Function ${file} executed successfully`);
} catch (error) {
logger.error(`Error executing function ${file}:`, error);
throw error;
}
}
}
}
console.log('Все миграции успешно применены');
} catch (error) {
console.error('Ошибка при выполнении миграций:', error);
process.exit(1);
} finally {
await pool.end();
}
}
runMigrations();