const { Pool } = require('pg'); const parseBoolean = (value, fallback = false) => { if (typeof value !== 'string') return fallback; const normalized = value.trim().toLowerCase(); if (['1', 'true', 'yes', 'on'].includes(normalized)) return true; if (['0', 'false', 'no', 'off'].includes(normalized)) return false; return fallback; }; const buildDatabaseUrlFromParts = () => { const host = (process.env.POSTGRES_HOST || 'postgres').trim(); const port = Number(process.env.POSTGRES_PORT || 5432); const database = (process.env.POSTGRES_DB || 'greenlns').trim(); const user = (process.env.POSTGRES_USER || 'greenlns').trim(); const password = process.env.POSTGRES_PASSWORD; if (!password) { return ''; } return `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${host}:${port}/${encodeURIComponent(database)}`; }; const getDefaultDbPath = () => { return (process.env.DATABASE_URL || buildDatabaseUrlFromParts()).trim(); }; const getPoolConfig = () => { const connectionString = getDefaultDbPath(); if (!connectionString) { throw new Error('DATABASE_URL or POSTGRES_* environment variables are required.'); } const sslEnabled = parseBoolean(process.env.DATABASE_SSL, false); return { connectionString, max: Number(process.env.PGPOOL_MAX || 10), ssl: sslEnabled ? { rejectUnauthorized: false } : false, }; }; const translateSql = (sql) => { if (typeof sql !== 'string') return sql; let placeholderIndex = 0; return sql .replace(/\?/g, () => { placeholderIndex += 1; return `$${placeholderIndex}`; }) .replace(/BEGIN\s+IMMEDIATE\s+TRANSACTION/gi, 'BEGIN') .replace(/datetime\('now'\)/gi, 'CURRENT_TIMESTAMP') .replace(/\s+COLLATE\s+NOCASE/gi, ''); }; const openDatabase = async () => { const pool = new Pool(getPoolConfig()); await pool.query('SELECT 1'); return pool; }; const closeDatabase = async (db) => { if (!db || typeof db.end !== 'function') return; await db.end(); }; const run = async (db, sql, params = []) => { const result = await db.query(translateSql(sql), params); return { lastId: result.rows?.[0]?.id ?? null, changes: result.rowCount || 0, rows: result.rows || [], }; }; const get = async (db, sql, params = []) => { const result = await db.query(translateSql(sql), params); return result.rows[0] || null; }; const all = async (db, sql, params = []) => { const result = await db.query(translateSql(sql), params); return result.rows || []; }; module.exports = { all, closeDatabase, get, getDefaultDbPath, openDatabase, run, };