const { Pool } = require('pg'); const fs = require('fs'); const path = require('path'); require('dotenv').config(); const SCHEMA_PATH = path.join(__dirname, 'schema.sql'); // Database configuration const config = { host: process.env.DB_HOST || 'localhost', port: parseInt(process.env.DB_PORT || '5432'), user: process.env.DB_USER || 'dashboard_user', password: process.env.DB_PASSWORD, database: process.env.DB_NAME || 'dashboard_db', // Connection pool settings min: parseInt(process.env.DB_POOL_MIN || '2'), max: parseInt(process.env.DB_POOL_MAX || '10'), // Connection timeout connectionTimeoutMillis: 5000, // Idle timeout (30 seconds) idleTimeoutMillis: 30000, // SSL configuration ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: false, } : false, }; // Create connection pool const pool = new Pool(config); // Handle pool errors pool.on('error', (err) => { console.error('Unexpected error on idle PostgreSQL client', err); process.exit(-1); }); // Initialize database with schema async function initializeDatabase() { const client = await pool.connect(); try { const schema = fs.readFileSync(SCHEMA_PATH, 'utf8'); await client.query(schema); } catch (error) { console.error('✗ Error initializing database:', error.message); throw error; } finally { client.release(); } } // Helper function to convert date to ISO string (YYYY-MM-DD for DATE columns) function toISODate(date) { if (!date) return null; if (date instanceof Date) { return date.toISOString().split('T')[0]; } return date; } // Helper function to parse ISO date function parseISODate(dateString) { if (!dateString) return null; return new Date(dateString); } // Query helper with parameter binding async function query(text, params) { const start = Date.now(); try { const res = await pool.query(text, params); const duration = Date.now() - start; if (process.env.NODE_ENV === 'development') { } return res; } catch (error) { console.error('Query error:', error.message); console.error('Query:', text); console.error('Params:', params); throw error; } } // Transaction helper async function transaction(callback) { const client = await pool.connect(); try { await client.query('BEGIN'); const result = await callback(client); await client.query('COMMIT'); return result; } catch (error) { await client.query('ROLLBACK'); throw error; } finally { client.release(); } } // Graceful shutdown async function closePool() { await pool.end(); } // Initialize on first load - store promise so callers can await it const dbReady = initializeDatabase().catch((error) => { console.error('Failed to initialize database:', error); process.exit(1); }); module.exports = { pool, query, transaction, toISODate, parseISODate, closePool, dbReady, };