update 9/20/25
This commit is contained in:
131
functions/migrations/migrate.js
Normal file
131
functions/migrations/migrate.js
Normal file
@@ -0,0 +1,131 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { executeQuery, executeTransaction } = require('../database');
|
||||
|
||||
/**
|
||||
* Run all database migrations
|
||||
*/
|
||||
async function runMigrations() {
|
||||
console.log('🚀 Starting database migrations...');
|
||||
|
||||
try {
|
||||
// Create migrations table to track what's been run
|
||||
await executeQuery(`
|
||||
CREATE TABLE IF NOT EXISTS migrations (
|
||||
id SERIAL PRIMARY KEY,
|
||||
filename VARCHAR(255) NOT NULL UNIQUE,
|
||||
executed_at BIGINT NOT NULL DEFAULT EXTRACT(epoch FROM NOW()) * 1000
|
||||
);
|
||||
`);
|
||||
|
||||
// Get list of executed migrations
|
||||
const executedMigrations = await executeQuery(
|
||||
'SELECT filename FROM migrations ORDER BY executed_at'
|
||||
);
|
||||
const executedFiles = new Set(executedMigrations.map(m => m.filename));
|
||||
|
||||
// Read migration files
|
||||
const migrationsDir = path.join(__dirname);
|
||||
const migrationFiles = fs.readdirSync(migrationsDir)
|
||||
.filter(file => file.endsWith('.sql'))
|
||||
.sort();
|
||||
|
||||
console.log(`📁 Found ${migrationFiles.length} migration files`);
|
||||
|
||||
for (const file of migrationFiles) {
|
||||
if (executedFiles.has(file)) {
|
||||
console.log(`⏭️ Skipping ${file} (already executed)`);
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(`🔄 Executing ${file}...`);
|
||||
|
||||
const filePath = path.join(migrationsDir, file);
|
||||
const sql = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
await executeTransaction(async (client) => {
|
||||
// Execute the migration SQL
|
||||
if (process.env.USE_NEON_SERVERLESS === 'true') {
|
||||
// For Neon serverless, split by statements and execute individually
|
||||
const statements = sql
|
||||
.split(';')
|
||||
.map(s => s.trim())
|
||||
.filter(s => s.length > 0);
|
||||
|
||||
for (const statement of statements) {
|
||||
if (statement.trim()) {
|
||||
await client(statement);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await client.query(sql);
|
||||
}
|
||||
|
||||
// Record that this migration was executed
|
||||
if (process.env.USE_NEON_SERVERLESS === 'true') {
|
||||
await client('INSERT INTO migrations (filename) VALUES ($1)', [file]);
|
||||
} else {
|
||||
await client.query('INSERT INTO migrations (filename) VALUES ($1)', [file]);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`✅ Completed ${file}`);
|
||||
}
|
||||
|
||||
console.log('🎉 All migrations completed successfully!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Migration failed:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new migration file
|
||||
* @param {string} name - Migration name
|
||||
*/
|
||||
function createMigration(name) {
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
|
||||
const filename = `${timestamp}_${name}.sql`;
|
||||
const filepath = path.join(__dirname, filename);
|
||||
|
||||
const template = `-- Migration: ${filename}
|
||||
-- Description: ${name}
|
||||
|
||||
-- Add your SQL here
|
||||
|
||||
`;
|
||||
|
||||
fs.writeFileSync(filepath, template);
|
||||
console.log(`📝 Created migration: ${filename}`);
|
||||
return filename;
|
||||
}
|
||||
|
||||
// Run migrations if this file is executed directly
|
||||
if (require.main === module) {
|
||||
const command = process.argv[2];
|
||||
|
||||
if (command === 'create') {
|
||||
const name = process.argv[3];
|
||||
if (!name) {
|
||||
console.error('❌ Please provide a migration name: npm run db:migrate create migration_name');
|
||||
process.exit(1);
|
||||
}
|
||||
createMigration(name);
|
||||
} else {
|
||||
runMigrations()
|
||||
.then(() => {
|
||||
console.log('🏁 Migration process completed');
|
||||
process.exit(0);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('💥 Migration process failed:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
runMigrations,
|
||||
createMigration
|
||||
};
|
||||
Reference in New Issue
Block a user