fix(migrations): use Node.js runner instead of psql

- Improve migrate.js with error handling for idempotent migrations
- Add 'npm run migrate' script to seeder-api/package.json
- Update start.sh option 4 to use Node.js-based migration runner
- Handles duplicate tables, columns, constraints gracefully
This commit is contained in:
Tiago Yamamoto 2025-12-24 10:47:25 -03:00
parent db1a9b9edc
commit 2fb81a6d1a
3 changed files with 61 additions and 29 deletions

View file

@ -7,11 +7,16 @@
"scripts": {
"seed": "node src/index.js",
"seed:reset": "node src/index.js --reset",
"migrate": "node src/migrate.js",
"seed:users": "node src/seeders/users.js",
"seed:companies": "node src/seeders/companies.js",
"seed:jobs": "node src/seeders/jobs.js"
},
"keywords": ["seeder", "jobs", "database"],
"keywords": [
"seeder",
"jobs",
"database"
],
"author": "",
"license": "MIT",
"dependencies": {
@ -19,4 +24,4 @@
"bcrypt": "^5.1.1",
"dotenv": "^16.3.1"
}
}
}

View file

@ -1,6 +1,6 @@
import fs from 'fs';
import path from 'path';
import { pool } from './db.js';
import { pool, testConnection, closePool } from './db.js';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
@ -9,24 +9,68 @@ const __dirname = path.dirname(__filename);
const MIGRATIONS_DIR = path.join(__dirname, '../../backend/migrations');
async function runMigrations() {
console.log('📦 Running migrations from:', MIGRATIONS_DIR);
console.log('🗄️ Running Migrations...\n');
try {
const connected = await testConnection();
if (!connected) {
throw new Error('Could not connect to database');
}
console.log(`📁 Reading from: ${MIGRATIONS_DIR}\n`);
const files = fs.readdirSync(MIGRATIONS_DIR)
.filter(f => f.endsWith('.sql'))
.sort();
console.log(`📄 Found ${files.length} migration files\n`);
let success = 0;
let skipped = 0;
let failed = 0;
for (const file of files) {
console.log(` ▶️ Executing ${file}...`);
console.log(`🔹 Running: ${file}`);
const sql = fs.readFileSync(path.join(MIGRATIONS_DIR, file), 'utf8');
await pool.query(sql);
try {
await pool.query(sql);
console.log(` ✅ Success`);
success++;
} catch (error) {
// Handle idempotent errors gracefully
if (error.code === '42P07') {
console.log(` ⏭️ Table already exists (skipped)`);
skipped++;
} else if (error.code === '42710') {
console.log(` ⏭️ Object already exists (skipped)`);
skipped++;
} else if (error.code === '23505') {
console.log(` ⏭️ Data already exists (skipped)`);
skipped++;
} else if (error.code === '42701') {
console.log(` ⏭️ Column already exists (skipped)`);
skipped++;
} else if (error.code === '42P16') {
console.log(` ⏭️ Constraint already exists (skipped)`);
skipped++;
} else {
console.error(` ❌ Error: ${error.message}`);
failed++;
}
}
}
console.log('✅ All migrations executed successfully');
console.log('\n' + '═'.repeat(50));
console.log(`✅ Migrations completed!`);
console.log(` Success: ${success} | Skipped: ${skipped} | Failed: ${failed}`);
console.log('═'.repeat(50));
} catch (error) {
console.error('❌ Error running migrations:', error);
console.error('❌ Migration failed:', error.message);
process.exit(1);
} finally {
await pool.end();
await closePool();
}
}

View file

@ -164,26 +164,9 @@ case $choice in
4)
echo -e "\n${GREEN}🗄️ Running Migrations...${NC}\n"
cd backend
# Load DB config from .env
if [ -f .env ]; then
source .env
fi
DB_HOST=${DB_HOST:-localhost}
DB_PORT=${DB_PORT:-5432}
DB_USER=${DB_USER:-postgres}
DB_NAME=${DB_NAME:-gohorsejobs}
echo -e "${BLUE}🔹 Connecting to ${DB_HOST}:${DB_PORT}/${DB_NAME}...${NC}"
for file in migrations/*.sql; do
echo -e "${YELLOW}🔹 Running: $(basename $file)${NC}"
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -f "$file" 2>&1 | head -5
done
echo -e "\n${GREEN}✅ Migrations completed!${NC}"
cd seeder-api
[ ! -d "node_modules" ] && npm install
npm run migrate
;;
5)