const router = require('express').Router(); const { query } = require('../db'); // List all tables in the database router.get('/tables', async (req, res, next) => { try { const result = await query( `SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_name` ); res.json(result.rows); } catch (err) { next(err); } }); // Get rows from any table (with optional limit) router.get('/tables/:table', async (req, res, next) => { try { const { table } = req.params; const limit = Math.min(parseInt(req.query.limit) || 100, 1000); const offset = parseInt(req.query.offset) || 0; // Validate table name to prevent SQL injection const tableCheck = await query( `SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = $1`, [table] ); if (tableCheck.rows.length === 0) { return res.status(404).json({ error: `Table "${table}" not found` }); } const result = await query( `SELECT * FROM "${table}" LIMIT $1 OFFSET $2`, [limit, offset] ); res.json({ table, count: result.rows.length, rows: result.rows }); } catch (err) { next(err); } }); // Execute raw SQL (POST, restricted — use carefully) router.post('/query', async (req, res, next) => { try { const { sql, params } = req.body; if (!sql) return res.status(400).json({ error: 'Missing "sql" field' }); // Block destructive statements without explicit confirmation header const dangerous = /^\s*(drop|truncate|delete\s+from\s+\w+\s*;)/i; if (dangerous.test(sql) && req.headers['x-confirm-destructive'] !== 'yes') { return res.status(400).json({ error: 'Destructive statement detected. Set header X-Confirm-Destructive: yes to proceed.', }); } const result = await query(sql, params || []); res.json({ rowCount: result.rowCount, rows: result.rows }); } catch (err) { next(err); } }); module.exports = router;