Files
webshop/shop/migrate.js
DanielS 756ec5c002
All checks were successful
Staging Build / build (push) Successful in 2m47s
feat: add automatic database migration and seeding on docker startup
2026-06-23 03:14:40 +02:00

94 lines
3.0 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 { Client } = require('pg');
const fs = require('fs');
const path = require('path');
async function run() {
const connectionString = process.env.DATABASE_URL;
if (!connectionString) {
console.log('DATABASE_URL not set skipping migrations.');
return;
}
console.log('Starting database migrations...');
const client = new Client({
connectionString,
connectionTimeoutMillis: 10000,
});
await client.connect();
// Create schema_migrations table if not exists
await client.query(`
CREATE TABLE IF NOT EXISTS public.schema_migrations (
version VARCHAR(255) PRIMARY KEY,
inserted_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
);
`);
const migrationsDir = path.join(__dirname, 'supabase', 'migrations');
if (!fs.existsSync(migrationsDir)) {
console.warn(`Migrations directory not found at: ${migrationsDir}`);
await client.end();
return;
}
const files = fs.readdirSync(migrationsDir).sort();
for (const file of files) {
if (!file.endsWith('.sql')) continue;
const { rows } = await client.query('SELECT 1 FROM public.schema_migrations WHERE version = $1', [file]);
if (rows.length === 0) {
console.log(`Running migration: ${file}`);
const sql = fs.readFileSync(path.join(migrationsDir, file), 'utf8');
// We run the migration in a single transaction
await client.query('BEGIN');
try {
await client.query(sql);
await client.query('INSERT INTO public.schema_migrations (version) VALUES ($1)', [file]);
await client.query('COMMIT');
console.log(`Migration ${file} completed successfully.`);
} catch (err) {
await client.query('ROLLBACK');
console.error(`Migration ${file} failed, rolled back.`);
throw err;
}
} else {
console.log(`Skipping migration: ${file} (already run)`);
}
}
// Also check if we should run seed.sql (only if we run it for the first time or if products are empty)
const seedFile = path.join(__dirname, 'supabase', 'seed.sql');
if (fs.existsSync(seedFile)) {
try {
const { rows: productRows } = await client.query('SELECT 1 FROM public.products LIMIT 1');
if (productRows.length === 0) {
console.log('No products found. Seeding database with default products...');
const seedSql = fs.readFileSync(seedFile, 'utf8');
await client.query('BEGIN');
try {
await client.query(seedSql);
await client.query('COMMIT');
console.log('Database seeded successfully.');
} catch (err) {
await client.query('ROLLBACK');
console.error('Seeding failed, rolled back.', err);
}
}
} catch (e) {
// In case products table check fails (e.g. initial_schema wasn't run or failed)
console.error('Failed to run seed check/seed SQL', e);
}
}
await client.end();
console.log('Database migrations completed.');
}
run().catch(err => {
console.error('Migration execution failed:', err);
process.exit(1);
});