import pg from 'pg'; const { Pool } = pg; // Configuration from environment variables const config = { host: process.env.DB_HOST || 'localhost', port: parseInt(process.env.DB_PORT || '5432'), database: process.env.DB_NAME || 'litellm', user: process.env.DB_USER || 'litellm', password: process.env.DB_PASSWORD || 'litellm', max: 5, idleTimeoutMillis: 30000, connectionTimeoutMillis: 5000, }; // Create connection pool const pool = new Pool(config); // Log connection errors pool.on('error', (err) => { console.error('Unexpected database error:', err); }); /** * Execute a query and return all rows */ export async function query>( text: string, params?: unknown[] ): Promise { const result = await pool.query(text, params); return result.rows as T[]; } /** * Execute a query and return the first row */ export async function queryOne>( text: string, params?: unknown[] ): Promise { const result = await pool.query(text, params); return (result.rows[0] as T) || null; } /** * Execute a query without returning results (INSERT, UPDATE, DELETE) */ export async function execute( text: string, params?: unknown[] ): Promise { const result = await pool.query(text, params); return result.rowCount || 0; } /** * Get the next task ID for a project */ export async function getNextTaskId(projectKey: string): Promise { const result = await queryOne<{ next_id: number }>( `INSERT INTO task_sequences (project, next_id) VALUES ($1, 1) ON CONFLICT (project) DO UPDATE SET next_id = task_sequences.next_id + 1 RETURNING next_id`, [projectKey] ); return `${projectKey}-${result?.next_id || 1}`; } /** * Get project key from name, or generate one */ export async function getProjectKey(projectName: string): Promise { // First check if already registered const existing = await queryOne<{ key: string }>( `SELECT key FROM projects WHERE name = $1 LIMIT 1`, [projectName] ); if (existing) { return existing.key; } // Generate a key from the name (uppercase first letters) let generated = projectName.replace(/[a-z]/g, '').slice(0, 4); if (!generated) { generated = projectName.slice(0, 3).toUpperCase(); } // Register the new project await execute( `INSERT INTO projects (key, name) VALUES ($1, $2) ON CONFLICT (key) DO NOTHING`, [generated, projectName] ); return generated; } /** * Test database connection */ export async function testConnection(): Promise { try { await query('SELECT 1'); return true; } catch (error) { console.error('Database connection failed:', error); return false; } } /** * Close the connection pool */ export async function close(): Promise { await pool.end(); } export default pool;