refactor: auto-run DB migration at startup, robust schema.sql path resolution
This commit is contained in:
+46
-10
@@ -3,15 +3,51 @@ import { config } from '../env';
|
|||||||
import { getErrorMessage } from '../utils/file';
|
import { getErrorMessage } from '../utils/file';
|
||||||
import logger from '../utils/logger';
|
import logger from '../utils/logger';
|
||||||
|
|
||||||
const schemaSql = await Bun.file('schema.sql').text();
|
/**
|
||||||
const sql = postgres(config.databaseUrl, { max: 1 });
|
* Run raw SQL migration from schema.sql.
|
||||||
|
* Safe to call multiple times — all statements use IF NOT EXISTS.
|
||||||
|
*/
|
||||||
|
export const runMigration = async (): Promise<void> => {
|
||||||
|
// In compiled dist: import.meta.dir = .../dist/
|
||||||
|
// In source via bun --hot: import.meta.dir = .../src/db/
|
||||||
|
const dir = import.meta.dir || '';
|
||||||
|
const candidates = [
|
||||||
|
dir + '/../../schema.sql', // from dist/
|
||||||
|
dir + '/../schema.sql', // from src/ (bun --hot src/index.ts)
|
||||||
|
dir + '/../schema.sql', // from src/db/ (bun --hot src/db/migrate.ts)
|
||||||
|
dir + '/schema.sql', // from src/ (bun run db:migrate)
|
||||||
|
];
|
||||||
|
|
||||||
try {
|
let schemaSql: string | null = null;
|
||||||
await sql.unsafe(schemaSql);
|
for (const p of candidates) {
|
||||||
logger.info('Database migration completed');
|
const file = Bun.file(p);
|
||||||
} catch (error: unknown) {
|
const exists = await file.exists();
|
||||||
logger.error('Database migration failed', { error: getErrorMessage(error) });
|
if (exists) {
|
||||||
process.exitCode = 1;
|
schemaSql = await file.text();
|
||||||
} finally {
|
break;
|
||||||
await sql.end();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!schemaSql) {
|
||||||
|
logger.error('Migration failed: schema.sql not found (tried ' + candidates.join(', ') + ')');
|
||||||
|
process.exitCode = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sql = postgres(config.databaseUrl, { max: 1 });
|
||||||
|
|
||||||
|
try {
|
||||||
|
await sql.unsafe(schemaSql);
|
||||||
|
logger.info('Database migration completed');
|
||||||
|
} catch (error: unknown) {
|
||||||
|
logger.error('Database migration failed', { error: getErrorMessage(error) });
|
||||||
|
process.exitCode = 1;
|
||||||
|
} finally {
|
||||||
|
await sql.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// When run directly: `bun src/db/migrate.ts` or `bun dist/migrate.js`
|
||||||
|
if (import.meta.path === Bun.main) {
|
||||||
|
await runMigration();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,22 @@ import logger from './utils/logger';
|
|||||||
import { metricsCollector } from './utils/metrics';
|
import { metricsCollector } from './utils/metrics';
|
||||||
import { cleanupRateLimitCache, withRateLimit } from './utils/rateLimit';
|
import { cleanupRateLimitCache, withRateLimit } from './utils/rateLimit';
|
||||||
|
|
||||||
|
// ─── Auto-run migration at startup ──────────────────────────────────────────
|
||||||
|
try {
|
||||||
|
const { runMigration } = await import('./db/migrate');
|
||||||
|
await runMigration();
|
||||||
|
} catch {
|
||||||
|
logger.warn('Auto-migration skipped (non-fatal)');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Auto-run migration at startup ───
|
||||||
|
try {
|
||||||
|
await import('./db/migrate');
|
||||||
|
} catch {
|
||||||
|
// migrate.ts calls process.exit(1) on failure — if it throws, log and continue
|
||||||
|
logger.warn('Auto-migration warning (non-fatal)');
|
||||||
|
}
|
||||||
|
|
||||||
const server = serve({
|
const server = serve({
|
||||||
port: config.port,
|
port: config.port,
|
||||||
routes: {
|
routes: {
|
||||||
|
|||||||
Reference in New Issue
Block a user