const express = require('express'); const { Pool } = require('pg'); const dotenv = require('dotenv'); const cors = require('cors'); // Load environment variables dotenv.config(); const app = express(); const PORT = process.env.PORT || 3000; // Middleware app.use(cors()); app.use(express.json()); // PostgreSQL connection pool const pool = new Pool({ host: process.env.DB_HOST, port: process.env.DB_PORT, database: process.env.DB_DATABASE, user: process.env.DB_USER, password: process.env.DB_PASSWORD, max: 20, idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000, }); // Health check endpoint app.get('/api/health', (req, res) => { res.json({ status: 'ok', timestamp: new Date().toISOString(), node_version: process.version }); }); // SELECT query endpoint app.post('/api/postgres/select', async (req, res) => { const { query, bindings = [] } = req.body; if (!query) { return res.status(422).json({ success: false, error: 'Query is required' }); } try { const result = await pool.query(query, bindings); res.json({ success: true, data: result.rows, count: result.rowCount }); } catch (error) { console.error('SELECT Error:', error); res.status(500).json({ success: false, error: error.message }); } }); // EXECUTE query endpoint (INSERT, UPDATE, DELETE) app.post('/api/postgres/execute', async (req, res) => { const { query, bindings = [] } = req.body; if (!query) { return res.status(422).json({ success: false, error: 'Query is required' }); } try { const result = await pool.query(query, bindings); res.json({ success: true, affected_rows: result.rowCount }); } catch (error) { console.error('EXECUTE Error:', error); res.status(500).json({ success: false, error: error.message }); } }); // TRANSACTION endpoint app.post('/api/postgres/transaction', async (req, res) => { const { queries } = req.body; if (!queries || !Array.isArray(queries)) { return res.status(422).json({ success: false, error: 'Queries array is required' }); } const client = await pool.connect(); try { await client.query('BEGIN'); const results = []; for (const item of queries) { const result = await client.query(item.query, item.bindings || []); results.push({ rowCount: result.rowCount, success: true }); } await client.query('COMMIT'); res.json({ success: true, results: results }); } catch (error) { await client.query('ROLLBACK'); console.error('TRANSACTION Error:', error); res.status(500).json({ success: false, error: error.message }); } finally { client.release(); } }); // INSERT simplified endpoint app.post('/api/postgres/insert', async (req, res) => { const { table, data } = req.body; if (!table || !data) { return res.status(422).json({ success: false, error: 'Table and data are required' }); } try { const columns = Object.keys(data); const values = Object.values(data); const placeholders = values.map((_, i) => `$${i + 1}`).join(', '); const query = ` INSERT INTO "${table}" (${columns.map(c => `"${c}"`).join(', ')}) VALUES (${placeholders}) RETURNING * `; const result = await pool.query(query, values); res.json({ success: true, data: result.rows[0] }); } catch (error) { console.error('INSERT Error:', error); res.status(500).json({ success: false, error: error.message }); } }); // UPDATE simplified endpoint app.post('/api/postgres/update', async (req, res) => { const { table, data, where } = req.body; if (!table || !data || !where) { return res.status(422).json({ success: false, error: 'Table, data and where are required' }); } try { const setColumns = Object.keys(data); const setValues = Object.values(data); const whereColumns = Object.keys(where); const whereValues = Object.values(where); const setClause = setColumns .map((col, i) => `"${col}" = $${i + 1}`) .join(', '); const whereClause = whereColumns .map((col, i) => `"${col}" = $${setValues.length + i + 1}`) .join(' AND '); const query = ` UPDATE "${table}" SET ${setClause} WHERE ${whereClause} `; const result = await pool.query(query, [...setValues, ...whereValues]); res.json({ success: true, affected_rows: result.rowCount }); } catch (error) { console.error('UPDATE Error:', error); res.status(500).json({ success: false, error: error.message }); } }); // DELETE simplified endpoint app.post('/api/postgres/delete', async (req, res) => { const { table, where } = req.body; if (!table || !where) { return res.status(422).json({ success: false, error: 'Table and where are required' }); } try { const whereColumns = Object.keys(where); const whereValues = Object.values(where); const whereClause = whereColumns .map((col, i) => `"${col}" = $${i + 1}`) .join(' AND '); const query = `DELETE FROM "${table}" WHERE ${whereClause}`; const result = await pool.query(query, whereValues); res.json({ success: true, affected_rows: result.rowCount }); } catch (error) { console.error('DELETE Error:', error); res.status(500).json({ success: false, error: error.message }); } }); // Start server app.listen(PORT, () => { console.log(`✓ Postgres API running on http://localhost:${PORT}`); console.log(`✓ Health check: http://localhost:${PORT}/api/health`); }); // Handle shutdown gracefully process.on('SIGINT', async () => { console.log('\nShutting down gracefully...'); await pool.end(); process.exit(0); });