const express = require('express'); const { fcTable } = require('../lib/utils'); module.exports = function(pool) { const router = express.Router(); // list all log entries for a version, newest first, with row counts from fc_table router.get('/versions/:id/log', async (req, res) => { try { const verResult = await pool.query(` SELECT v.*, s.tname FROM pf.version v JOIN pf.source s ON s.id = v.source_id WHERE v.id = $1 `, [req.params.id]); if (verResult.rows.length === 0) return res.status(404).json({ error: 'Version not found' }); const { tname, id: version_id } = verResult.rows[0]; const table = fcTable(tname, version_id); const result = await pool.query( `SELECT l.*, counts.row_count FROM pf.log l LEFT JOIN ( SELECT pf_logid, count(*)::int AS row_count FROM ${table} GROUP BY pf_logid ) counts ON counts.pf_logid = l.id WHERE l.version_id = $1 ORDER BY l.stamp DESC`, [req.params.id] ); res.json(result.rows); } catch (err) { console.error(err); res.status(500).json({ error: err.message }); } }); // update note on a log entry router.patch('/log/:logid', async (req, res) => { const { note } = req.body; try { const result = await pool.query( `UPDATE pf.log SET note = $1 WHERE id = $2 RETURNING *`, [note ?? null, parseInt(req.params.logid)] ); if (result.rows.length === 0) return res.status(404).json({ error: 'Log entry not found' }); res.json(result.rows[0]); } catch (err) { console.error(err); res.status(500).json({ error: err.message }); } }); // undo an operation — deletes all forecast rows with this logid, then the log entry // two separate queries in a transaction to avoid FK ordering issues router.delete('/log/:logid', async (req, res) => { const logid = parseInt(req.params.logid); const client = await pool.connect(); try { // look up the log entry to find the version and fc_table name const logResult = await client.query(` SELECT l.*, v.id AS version_id, s.tname FROM pf.log l JOIN pf.version v ON v.id = l.version_id JOIN pf.source s ON s.id = v.source_id WHERE l.id = $1 `, [logid]); if (logResult.rows.length === 0) { return res.status(404).json({ error: 'Log entry not found' }); } const { tname, version_id } = logResult.rows[0]; const table = fcTable(tname, version_id); await client.query('BEGIN'); // delete forecast rows first (logid has no FK constraint — managed by app) const del = await client.query( `DELETE FROM ${table} WHERE pf_logid = $1 RETURNING pf_id`, [logid] ); await client.query(`DELETE FROM pf.log WHERE id = $1`, [logid]); await client.query('COMMIT'); res.json({ message: 'Operation undone', rows_deleted: del.rowCount, pf_ids: del.rows.map(r => r.pf_id) }); } catch (err) { await client.query('ROLLBACK'); console.error(err); res.status(500).json({ error: err.message }); } finally { client.release(); } }); return router; };