Close the write-only surface left behind by the ordinals
bucket_order and log.seq were still settable -- PUT /versions/:id took the first, PATCH /log/:logid the second -- with nothing left to read either. A field that only ever gets written is worse than a missing one: the call succeeds, so the caller has no way to find out it did nothing. The columns themselves stay, marked vestigial where they are declared. Dropping a column is not worth a migration to reclaim two that cost nothing. pf.log.bucket is untouched and stays exactly as it was -- what a row counts toward, read first by BUCKET_EXPR. It is the bucket *order* that no longer needs storing, the text having become the order. Also removes a comment head in Forecast.jsx that survived its function and had glued itself onto fitColumns. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3299bfe10b
commit
98322a6080
@ -131,11 +131,11 @@ module.exports = function(pool) {
|
|||||||
// a closed version, where relabelling history is still legitimate.
|
// a closed version, where relabelling history is still legitimate.
|
||||||
router.patch('/log/:logid', async (req, res) => {
|
router.patch('/log/:logid', async (req, res) => {
|
||||||
const logId = parseInt(req.params.logid);
|
const logId = parseInt(req.params.logid);
|
||||||
const { note, tag, bucket, seq, label } = req.body;
|
const { note, tag, bucket, label } = req.body;
|
||||||
if (note === undefined && tag === undefined && bucket === undefined
|
if (note === undefined && tag === undefined
|
||||||
&& seq === undefined && label === undefined) {
|
&& bucket === undefined && label === undefined) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
error: 'Nothing to update — send note, tag, bucket, label and/or seq'
|
error: 'Nothing to update — send note, tag, bucket and/or label'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -146,16 +146,13 @@ module.exports = function(pool) {
|
|||||||
note = CASE WHEN $2::bool THEN $3::text ELSE note END,
|
note = CASE WHEN $2::bool THEN $3::text ELSE note END,
|
||||||
tag = CASE WHEN $4::bool THEN $5::text ELSE tag END,
|
tag = CASE WHEN $4::bool THEN $5::text ELSE tag END,
|
||||||
bucket = CASE WHEN $6::bool THEN $7::text ELSE bucket END,
|
bucket = CASE WHEN $6::bool THEN $7::text ELSE bucket END,
|
||||||
seq = CASE WHEN $8::bool THEN $9::int ELSE seq END,
|
label = CASE WHEN $8::bool THEN $9::text ELSE label END
|
||||||
label = CASE WHEN $10::bool THEN $11::text ELSE label END
|
|
||||||
WHERE id = $1 RETURNING *`,
|
WHERE id = $1 RETURNING *`,
|
||||||
[
|
[
|
||||||
logId,
|
logId,
|
||||||
note !== undefined, note === undefined ? null : (String(note).trim() || null),
|
note !== undefined, note === undefined ? null : (String(note).trim() || null),
|
||||||
tag !== undefined, tag === undefined ? null : (String(tag).trim() || null),
|
tag !== undefined, tag === undefined ? null : (String(tag).trim() || null),
|
||||||
bucket !== undefined, bucket === undefined ? null : (String(bucket).trim() || null),
|
bucket !== undefined, bucket === undefined ? null : (String(bucket).trim() || null),
|
||||||
seq !== undefined, (seq === undefined || seq === null || seq === '')
|
|
||||||
? null : parseInt(seq),
|
|
||||||
label !== undefined, label === undefined ? null : (String(label).trim() || null),
|
label !== undefined, label === undefined ? null : (String(label).trim() || null),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|||||||
@ -308,27 +308,25 @@ ${colDefs},
|
|||||||
});
|
});
|
||||||
|
|
||||||
// update version name, description, or exclude_iters
|
// update version name, description, or exclude_iters
|
||||||
|
//
|
||||||
|
// bucket_order is deliberately not settable: the bucket column order is the
|
||||||
|
// text in pf.log.bucket now, so a stored order would be a second answer to
|
||||||
|
// the same question, and a silent one -- nothing reads it.
|
||||||
router.put('/versions/:id', async (req, res) => {
|
router.put('/versions/:id', async (req, res) => {
|
||||||
const { name, description, exclude_iters, bucket_order } = req.body;
|
const { name, description, exclude_iters } = req.body;
|
||||||
try {
|
try {
|
||||||
// bucket_order is a flag-and-value pair rather than COALESCE: an empty
|
|
||||||
// array is a meaningful value (no ordering), and COALESCE could not tell
|
|
||||||
// it from "not mentioned".
|
|
||||||
const result = await pool.query(`
|
const result = await pool.query(`
|
||||||
UPDATE pf.version SET
|
UPDATE pf.version SET
|
||||||
name = COALESCE($2, name),
|
name = COALESCE($2, name),
|
||||||
description = COALESCE($3, description),
|
description = COALESCE($3, description),
|
||||||
exclude_iters = COALESCE($4, exclude_iters),
|
exclude_iters = COALESCE($4, exclude_iters)
|
||||||
bucket_order = CASE WHEN $5::bool THEN $6::jsonb ELSE bucket_order END
|
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING *
|
RETURNING *
|
||||||
`, [
|
`, [
|
||||||
req.params.id,
|
req.params.id,
|
||||||
name || null,
|
name || null,
|
||||||
description || null,
|
description || null,
|
||||||
exclude_iters ? JSON.stringify(exclude_iters) : null,
|
exclude_iters ? JSON.stringify(exclude_iters) : null
|
||||||
bucket_order !== undefined,
|
|
||||||
bucket_order === undefined ? null : JSON.stringify(bucket_order || [])
|
|
||||||
]);
|
]);
|
||||||
if (result.rows.length === 0) {
|
if (result.rows.length === 0) {
|
||||||
return res.status(404).json({ error: 'Version not found' });
|
return res.status(404).json({ error: 'Version not found' });
|
||||||
|
|||||||
@ -83,15 +83,6 @@ WHERE TRUE
|
|||||||
|
|
||||||
-- Display order for the pivot's segment and bucket columns.
|
-- Display order for the pivot's segment and bucket columns.
|
||||||
--
|
--
|
||||||
-- Perspective orders column groups by the value string, and SortDir's col asc /
|
|
||||||
-- col desc only reverses that -- so no sort setting can produce
|
|
||||||
-- Prior Year -> Plan -> Actual -> Forecast, which is alphabetical in neither
|
|
||||||
-- direction. The order has to be carried in the value itself, as a "01 · " style
|
|
||||||
-- prefix applied when the rows are served.
|
|
||||||
--
|
|
||||||
-- bucket_order lives on the version rather than the source because the Baseline
|
|
||||||
-- page, where it is maintained, is version-scoped. log.seq orders the segments
|
|
||||||
-- within that.
|
|
||||||
-- The segment's display name in the pivot, falling back to tag then note.
|
-- The segment's display name in the pivot, falling back to tag then note.
|
||||||
--
|
--
|
||||||
-- Separate from both because those have jobs already -- tag groups adjustments
|
-- Separate from both because those have jobs already -- tag groups adjustments
|
||||||
@ -101,6 +92,11 @@ WHERE TRUE
|
|||||||
-- note would put it in every note.
|
-- note would put it in every note.
|
||||||
ALTER TABLE pf.log ADD COLUMN IF NOT EXISTS label text;
|
ALTER TABLE pf.log ADD COLUMN IF NOT EXISTS label text;
|
||||||
|
|
||||||
|
-- Vestigial, both of them. They held the ordinal when the "01 - " prefix was
|
||||||
|
-- computed for the pivot rather than typed into label and bucket: bucket_order
|
||||||
|
-- sequenced the bucket columns, log.seq the segments within them. Nothing reads
|
||||||
|
-- either now, and nothing writes them -- kept only because dropping a column is
|
||||||
|
-- not worth a migration to reclaim two that cost nothing.
|
||||||
ALTER TABLE pf.version ADD COLUMN IF NOT EXISTS bucket_order jsonb;
|
ALTER TABLE pf.version ADD COLUMN IF NOT EXISTS bucket_order jsonb;
|
||||||
ALTER TABLE pf.log ADD COLUMN IF NOT EXISTS seq integer;
|
ALTER TABLE pf.log ADD COLUMN IF NOT EXISTS seq integer;
|
||||||
|
|
||||||
|
|||||||
@ -841,10 +841,6 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep the ordering expressions in step with the version's bucket_order and the
|
|
||||||
// log's seq values. Merged into the live config rather than replacing
|
|
||||||
// expressions, so anything the user defined themselves survives.
|
|
||||||
//
|
|
||||||
// Size every column to its contents.
|
// Size every column to its contents.
|
||||||
//
|
//
|
||||||
// Values fit on their own: draw() calls regular_table.resetAutoSize(), which
|
// Values fit on their own: draw() calls regular_table.resetAutoSize(), which
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user