require('dotenv').config(); const express = require('express'); const cors = require('cors'); const { Pool, types } = require('pg'); // Return bigint (oid 20) and numeric (oid 1700) as JS numbers instead of strings, // so apache-arrow's tableFromJSON infers Int/Float64 rather than Dictionary. types.setTypeParser(20, v => v === null ? null : Number(v)); types.setTypeParser(1700, v => v === null ? null : Number(v)); const app = express(); app.use(cors()); app.use(express.json()); app.use(express.static('public/app')); const pool = new Pool({ host: process.env.DB_HOST, port: parseInt(process.env.DB_PORT) || 5432, database: process.env.DB_NAME, user: process.env.DB_USER, password: process.env.DB_PASSWORD, ssl: false }); pool.on('error', (err) => { console.error('pg pool error', err); }); app.use('/api', require('./routes/tables')(pool)); app.use('/api', require('./routes/sources')(pool)); app.use('/api', require('./routes/versions')(pool)); app.use('/api', require('./routes/operations')(pool)); app.use('/api', require('./routes/log')(pool)); // Refuse to start against a database whose schema is behind the migrations on // disk. Without this the mismatch surfaces later as a confusing query error // ('column "x" does not exist') deep inside an unrelated request. // Set PF_SKIP_MIGRATION_CHECK=1 to bypass. async function checkSchema() { if (process.env.PF_SKIP_MIGRATION_CHECK === '1') return; const { status } = require('./lib/migrations'); const client = await pool.connect(); try { const st = await status(client); const problems = [ st.pending.length && `${st.pending.length} pending: ${st.pending.map(m => m.filename).join(', ')}`, st.modified.length && `modified after being applied: ${st.modified.join(', ')}`, st.missing.length && `applied but missing from disk: ${st.missing.join(', ')}` ].filter(Boolean); if (problems.length) { console.error('\n Database schema is out of date:'); for (const p of problems) console.error(` - ${p}`); console.error('\n Run "npm run migrate" (or "npm run migrate:status" for detail).'); console.error(' For a database that already matches, "npm run migrate:baseline".\n'); throw new Error('schema out of date'); } console.log(`schema up to date (${st.applied.length} migrations applied)`); } finally { client.release(); } } const port = process.env.PORT || 3010; checkSchema() .then(() => app.listen(port, '0.0.0.0', () => console.log(`pf_app started on port ${port}`))) .catch((err) => { if (err.message !== 'schema out of date') console.error('startup failed:', err.message); process.exit(1); });