import pg from 'pg'; import type { DB } from '../../server'; const { Pool } = pg; let pool: pg.Pool | null = null; export function getPgPool(): pg.Pool | null { if (pool) return pool; const connectionString = process.env.DATABASE_URL || process.env.POSTGRES_URL || process.env.DATABASE_PRIVATE_URL; const host = process.env.POSTGRES_HOST || process.env.SQL_HOST; const user = process.env.POSTGRES_USER || process.env.SQL_USER; const password = process.env.POSTGRES_PASSWORD || process.env.SQL_PASSWORD; const database = process.env.POSTGRES_DB || process.env.SQL_DB_NAME || 'balance_sheet_db'; const port = parseInt(process.env.POSTGRES_PORT || '5432', 10); if (connectionString) { console.log('[PostgreSQL] Initializing connection pool via DATABASE_URL'); pool = new Pool({ connectionString, max: 10, idleTimeoutMillis: 30000, connectionTimeoutMillis: 5000, }); } else if (host && user) { console.log(`[PostgreSQL] Initializing connection pool via host ${host}:${port}, db: ${database}`); pool = new Pool({ host, port, user, password, database, max: 10, idleTimeoutMillis: 30000, connectionTimeoutMillis: 5000, }); } else { console.log('[PostgreSQL] No DATABASE_URL or POSTGRES_HOST provided. Operating in file-backed mode.'); return null; } pool.on('error', (err) => { console.error('[PostgreSQL] Unexpected idle client error:', err); }); return pool; } /** * Initializes PostgreSQL schema table if needed */ export async function initPgDatabase(): Promise { const p = getPgPool(); if (!p) return false; try { const client = await p.connect(); try { await client.query(` CREATE TABLE IF NOT EXISTS app_portal_state ( id VARCHAR(50) PRIMARY KEY, data JSONB NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); `); console.log('[PostgreSQL] Database table app_portal_state ensured.'); return true; } finally { client.release(); } } catch (err) { console.error('[PostgreSQL] Initialization failed:', err); return false; } } /** * Load state from PostgreSQL */ export async function loadStateFromPg(): Promise { const p = getPgPool(); if (!p) return null; try { const res = await p.query(`SELECT data FROM app_portal_state WHERE id = $1`, ['main_state']); if (res.rows.length > 0 && res.rows[0].data) { console.log('[PostgreSQL] Successfully restored portal state from PostgreSQL database.'); return res.rows[0].data as DB; } return null; } catch (err) { console.error('[PostgreSQL] Error loading state:', err); return null; } } /** * Save state to PostgreSQL asynchronously */ export async function saveStateToPg(state: DB): Promise { const p = getPgPool(); if (!p) return; try { await p.query( ` INSERT INTO app_portal_state (id, data, updated_at) VALUES ($1, $2, NOW()) ON CONFLICT (id) DO UPDATE SET data = EXCLUDED.data, updated_at = NOW(); `, ['main_state', JSON.stringify(state)] ); } catch (err) { console.error('[PostgreSQL] Error saving state:', err); } }