pf_app/routes/log.js
Paul Trowbridge 6b69b00645 Undo deletes rows in place instead of reloading the forecast
Perspective table is now created with index: 'pf_id'. Delete endpoints
return the pf_ids they removed; the client calls table.remove(pf_ids)
in undoEntry. Avoids the full /data refetch that dominated undo time.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 20:21:13 -04:00

68 lines
2.4 KiB
JavaScript

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
router.get('/versions/:id/log', async (req, res) => {
try {
const result = await pool.query(
`SELECT * FROM pf.log WHERE version_id = $1 ORDER BY stamp DESC`,
[req.params.id]
);
res.json(result.rows);
} 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;
};