Files
postgres-middle-api/server.js

266 lines
6.5 KiB
JavaScript
Raw Normal View History

2026-03-18 11:03:49 +01:00
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);
});