require('dotenv').config(); const express = require('express'); const { Pool } = require('pg'); // Install required packages // npm install express pg const app = express(); app.use(express.json()); // Configure PostgreSQL connection const pool = new Pool({ user: process.env.PGUSER, host: process.env.PGHOST, database: process.env.PGDATABASE, password: process.env.PGPASSWORD, port: process.env.PGPORT, }); // GET all records with pagination app.get('/data', async (req, res) => { console.log("Get all records with the table"); try { const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 10; const offset = (page - 1) * limit; const query = { text: 'SELECT * FROM test_db_table ORDER BY id LIMIT $1 OFFSET $2', values: [limit, offset], }; const result = await pool.query(query); res.json(result.rows); } catch (err) { res.status(500).json({ error: err.message }); } }); // GET record by ID app.get('/data/:id', async (req, res) => { console.log("Get record by ID"); try { const { id } = req.params; const query = { text: 'SELECT * FROM test_db_table WHERE id = $1', values: [id], }; const result = await pool.query(query); if (result.rows.length === 0) { return res.status(404).json({ message: 'Record not found' }); } res.json(result.rows[0]); } catch (err) { res.status(500).json({ error: err.message }); } }); // POST new record app.post('/data', async (req, res) => { console.log("Post new record"); try { const { x, y, z } = req.body; const query = { text: 'INSERT INTO test_db_table(x, y, z) VALUES($1, $2, $3) RETURNING *', values: [x, y, z], }; const result = await pool.query(query); res.status(201).json(result.rows[0]); } catch (err) { res.status(500).json({ error: err.message }); } }); // PUT update record app.put('/data/:id', async (req, res) => { console.log("Update record by ID"); try { const { id } = req.params; const { x, y, z } = req.body; const query = { text: 'UPDATE test_db_table SET x = $1, y = $2, z = $3 WHERE id = $4 RETURNING *', values: [x, y, z, id], }; const result = await pool.query(query); if (result.rows.length === 0) { return res.status(404).json({ message: 'Record not found' }); } res.json(result.rows[0]); } catch (err) { res.status(500).json({ error: err.message }); } }); // DELETE record app.delete('/data/:id', async (req, res) => { console.log("Delete record by ID"); try { const { id } = req.params; const query = { text: 'DELETE FROM test_db_table WHERE id = $1 RETURNING *', values: [id], }; const result = await pool.query(query); if (result.rows.length === 0) { return res.status(404).json({ message: 'Record not found' }); } res.json({ message: 'Record deleted successfully' }); } catch (err) { res.status(500).json({ error: err.message }); } }); // Advanced query endpoint with filtering and sorting app.get('/data/search', async (req, res) => { console.log("Advanced query endpoint with filtering and sorting"); try { const { min_x, max_x, min_y, max_y, min_z, max_z, start_time, end_time, sort_by, order = 'ASC' } = req.query; let conditions = []; let values = []; let valueIndex = 1; if (min_x) { conditions.push(`x >= $${valueIndex++}`); values.push(min_x); } if (max_x) { conditions.push(`x <= $${valueIndex++}`); values.push(max_x); } // Similar for y and z ranges if (start_time) { conditions.push(`time >= $${valueIndex++}`); values.push(start_time); } if (end_time) { conditions.push(`time <= $${valueIndex++}`); values.push(end_time); } const whereClause = conditions.length > 0 ? 'WHERE ' + conditions.join(' AND ') : ''; const orderClause = sort_by ? `ORDER BY ${sort_by} ${order}` : 'ORDER BY id'; const query = { text: `SELECT * FROM test_db_table ${whereClause} ${orderClause}`, values: values, }; const result = await pool.query(query); res.json(result.rows); } catch (err) { res.status(500).json({ error: err.message }); } }); // GET latest single record app.get('/latest_data', async (req, res) => { console.log("require the latest data on the database table"); try { const query = { text: 'SELECT * FROM test_db_table ORDER BY time DESC LIMIT 1' }; const result = await pool.query(query); if (result.rows.length === 0) { return res.status(404).json({ message: 'No records found' }); } res.json(result.rows[0]); } catch (err) { res.status(500).json({ error: err.message }); } }); // This will handle both "/latest_data" and "/latest data" app.get('/latest%20data', async (req, res) => { console.log("require the latest data on the database table (20%))"); try { const query = { text: 'SELECT * FROM test_db_table ORDER BY time DESC LIMIT 1' }; const result = await pool.query(query); if (result.rows.length === 0) { return res.status(404).json({ message: 'No records found' }); } res.json(result.rows[0]); } catch (err) { res.status(500).json({ error: err.message }); } }); // GET latest N records app.get('/latest_data/:count', async (req, res) => { try { const count = parseInt(req.params.count) || 1; // Add a reasonable limit to prevent excessive requests const safeCount = Math.min(count, 100); const query = { text: 'SELECT * FROM test_db_table ORDER BY time DESC LIMIT $1', values: [safeCount] }; const result = await pool.query(query); res.json(result.rows); } catch (err) { res.status(500).json({ error: err.message }); } }); // GET latest data within a time window (e.g., last 5 minutes) app.get('/latest_data/window', async (req, res) => { try { const minutes = parseInt(req.query.minutes) || 5; // Add a reasonable limit to prevent excessive time windows const safeMinutes = Math.min(minutes, 60); const query = { text: ` SELECT * FROM test_db_table WHERE time >= NOW() - INTERVAL '${safeMinutes} minutes' ORDER BY time DESC ` }; const result = await pool.query(query); res.json(result.rows); } catch (err) { res.status(500).json({ error: err.message }); } }); // GET latest data with real-time updates using Server-Sent Events (SSE) app.get('/latest_data/stream', async (req, res) => { // Set headers for SSE res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); // Send initial data try { const query = { text: 'SELECT * FROM test_db_table ORDER BY time DESC LIMIT 1' }; const result = await pool.query(query); if (result.rows.length > 0) { res.write(`data: ${JSON.stringify(result.rows[0])}\n\n`); } } catch (err) { console.error('Error fetching initial data:', err); } // Set up polling interval (e.g., every 5 seconds) const intervalId = setInterval(async () => { try { const query = { text: 'SELECT * FROM test_db_table ORDER BY time DESC LIMIT 1' }; const result = await pool.query(query); if (result.rows.length > 0) { res.write(`data: ${JSON.stringify(result.rows[0])}\n\n`); } } catch (err) { console.error('Error fetching update:', err); } }, 5000); // Clean up on client disconnect req.on('close', () => { clearInterval(intervalId); }); }); // Error handling middleware app.use((err, req, res, next) => { console.error(err.stack); res.status(500).json({ error: 'Something broke!' }); }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); });