Expose load segments and adjustment notes as separate pivot columns
The label on a baseline or reference load ("Open Orders", "Prior Year")
lived only on the pf.log row; the data stream was a straight dump of the
forecast table, so Perspective saw pf_logid and never the name.
The stream now joins pf.log and emits two columns rather than one, because
commingling them makes neither useful: pf_segment names the load a row came
from, and is '(adjustment)' for everything else; pf_note carries the free
text on scale/recode/clone and is null on loads. The operation routes stamp
the same two fields on the rows they push back incrementally.
The tag column those labels belong in is declared in 01_schema.sql but
predates some installs, so the backfill seeding it from note joins the
ALTER already there. Adjustment notes are free text, not labels, and are
left alone.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0e87f22e24
commit
81c2324220
@ -267,7 +267,16 @@ module.exports = function(pool) {
|
|||||||
await client.query('BEGIN');
|
await client.query('BEGIN');
|
||||||
await client.query(`
|
await client.query(`
|
||||||
DECLARE pf_cur CURSOR FOR
|
DECLARE pf_cur CURSOR FOR
|
||||||
SELECT * FROM ${tbl}
|
SELECT t.*
|
||||||
|
,CASE WHEN l.operation IN ('baseline','reference')
|
||||||
|
THEN COALESCE(NULLIF(l.tag, ''), NULLIF(l.note, ''), '(unlabeled load)')
|
||||||
|
ELSE '(adjustment)' END AS pf_segment
|
||||||
|
,CASE WHEN l.operation IN ('baseline','reference')
|
||||||
|
THEN NULL
|
||||||
|
ELSE COALESCE(NULLIF(l.tag, ''), NULLIF(l.note, '')) END AS pf_note
|
||||||
|
FROM ${tbl} t
|
||||||
|
LEFT JOIN pf.log l
|
||||||
|
ON l.id = t.pf_logid
|
||||||
`);
|
`);
|
||||||
|
|
||||||
// Accumulate into column arrays (not row objects) to avoid allocating one JS
|
// Accumulate into column arrays (not row objects) to avoid allocating one JS
|
||||||
@ -550,7 +559,8 @@ module.exports = function(pool) {
|
|||||||
|
|
||||||
await client.query('COMMIT');
|
await client.query('COMMIT');
|
||||||
committed = true;
|
committed = true;
|
||||||
const rows = allRows.map(r => ({ ...r, pf_note: note || null, pf_op: 'scale' }));
|
const opLabel = (req.body.tag || '').trim() || note || null;
|
||||||
|
const rows = allRows.map(r => ({ ...r, pf_segment: '(adjustment)', pf_note: opLabel, pf_op: 'scale' }));
|
||||||
res.json({
|
res.json({
|
||||||
rows,
|
rows,
|
||||||
rows_affected: rows.length,
|
rows_affected: rows.length,
|
||||||
@ -609,7 +619,8 @@ module.exports = function(pool) {
|
|||||||
}
|
}
|
||||||
await client.query('COMMIT');
|
await client.query('COMMIT');
|
||||||
committed = true;
|
committed = true;
|
||||||
const rows = allRows.map(r => ({ ...r, pf_note: note || null, pf_op: 'recode' }));
|
const opLabel = (req.body.tag || '').trim() || note || null;
|
||||||
|
const rows = allRows.map(r => ({ ...r, pf_segment: '(adjustment)', pf_note: opLabel, pf_op: 'recode' }));
|
||||||
res.json({ rows, rows_affected: rows.length, slices_applied: units.length });
|
res.json({ rows, rows_affected: rows.length, slices_applied: units.length });
|
||||||
} finally {
|
} finally {
|
||||||
if (!committed) try { await client.query('ROLLBACK'); } catch {}
|
if (!committed) try { await client.query('ROLLBACK'); } catch {}
|
||||||
@ -665,7 +676,8 @@ module.exports = function(pool) {
|
|||||||
}
|
}
|
||||||
await client.query('COMMIT');
|
await client.query('COMMIT');
|
||||||
committed = true;
|
committed = true;
|
||||||
const rows = allRows.map(r => ({ ...r, pf_note: note || null, pf_op: 'clone' }));
|
const opLabel = (req.body.tag || '').trim() || note || null;
|
||||||
|
const rows = allRows.map(r => ({ ...r, pf_segment: '(adjustment)', pf_note: opLabel, pf_op: 'clone' }));
|
||||||
res.json({ rows, rows_affected: rows.length, slices_applied: units.length });
|
res.json({ rows, rows_affected: rows.length, slices_applied: units.length });
|
||||||
} finally {
|
} finally {
|
||||||
if (!committed) try { await client.query('ROLLBACK'); } catch {}
|
if (!committed) try { await client.query('ROLLBACK'); } catch {}
|
||||||
|
|||||||
@ -64,6 +64,17 @@ CREATE TABLE IF NOT EXISTS pf.log (
|
|||||||
ALTER TABLE pf.log ADD COLUMN IF NOT EXISTS tag text;
|
ALTER TABLE pf.log ADD COLUMN IF NOT EXISTS tag text;
|
||||||
CREATE INDEX IF NOT EXISTS log_tag_idx ON pf.log (tag) WHERE tag IS NOT NULL;
|
CREATE INDEX IF NOT EXISTS log_tag_idx ON pf.log (tag) WHERE tag IS NOT NULL;
|
||||||
|
|
||||||
|
-- seed tags for loads that predate the column: a baseline/reference note is the
|
||||||
|
-- segment's name ('Open Orders', 'Prior Year'), which is exactly what tag holds.
|
||||||
|
-- Adjustment notes are free text, not labels, so they are left alone.
|
||||||
|
UPDATE pf.log
|
||||||
|
SET tag = note
|
||||||
|
WHERE TRUE
|
||||||
|
AND tag IS NULL
|
||||||
|
AND note IS NOT NULL
|
||||||
|
AND note <> ''
|
||||||
|
AND operation IN ('baseline', 'reference');
|
||||||
|
|
||||||
-- generated operation SQL per source, stored after col_meta is configured
|
-- generated operation SQL per source, stored after col_meta is configured
|
||||||
CREATE TABLE IF NOT EXISTS pf.sql (
|
CREATE TABLE IF NOT EXISTS pf.sql (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user