transceiver-db/scripts/migrate.ts
Rene Fichtmueller de5bdb24ca Initial TIP foundation: schema, seed data, crawlers, API, MCP server
- PostgreSQL 17 + TimescaleDB schema with 12 tables
- 48 standards (IEEE, SFF, ITU-T, OIF, MSA)
- 33 form factors (SFP through OSFP-XD/CPO)
- 85+ vendors (OEM, compatible, manufacturers, marketplaces)
- 80+ seed transceivers (1G-1.6T, CWDM, BiDi, DAC, AOC, FC, PON)
- 60+ network devices (Cisco, Juniper, Arista, HPE, Dell, etc.)
- Crawler framework with fs.com and eBay crawlers
- REST API (15 endpoints) on port 3200
- MCP server (12 tools) on port 3201
- PM2 ecosystem for production deployment on Erik (.82)
2026-03-31 08:11:49 +02:00

56 lines
1.4 KiB
TypeScript

import 'dotenv/config';
import { readFileSync, readdirSync } from 'fs';
import { join } from 'path';
import { query, pool } from '../src/utils/db.js';
import { pino } from 'pino';
const log = pino({ name: 'migrate' });
async function main() {
log.info('Running migrations...');
// Create migrations tracking table
await query(`
CREATE TABLE IF NOT EXISTS _migrations (
id SERIAL PRIMARY KEY,
name VARCHAR(200) NOT NULL UNIQUE,
applied_at TIMESTAMPTZ DEFAULT NOW()
)
`);
// Get applied migrations
const applied = await query('SELECT name FROM _migrations ORDER BY id');
const appliedSet = new Set(applied.rows.map(r => r.name));
// Read migration files
const migrationsDir = join(import.meta.dirname ?? '.', '..', 'migrations');
const files = readdirSync(migrationsDir)
.filter(f => f.endsWith('.sql'))
.sort();
for (const file of files) {
if (appliedSet.has(file)) {
log.info(`Skip (already applied): ${file}`);
continue;
}
log.info(`Applying: ${file}`);
const sql = readFileSync(join(migrationsDir, file), 'utf-8');
try {
await query(sql);
await query('INSERT INTO _migrations (name) VALUES ($1)', [file]);
log.info(`Applied: ${file}`);
} catch (err) {
log.error({ err, file }, 'Migration failed');
process.exit(1);
}
}
log.info('All migrations applied');
await pool.end();
process.exit(0);
}
main();