feat(export): dimension primitives, date members, status index

This commit is contained in:
Experiments DB Dev
2026-07-19 13:16:33 -04:00
parent cd4e213d6f
commit a411d59305
2 changed files with 113 additions and 0 deletions
+48
View File
@@ -54,6 +54,54 @@ export function listExportableParams(dailyTemplate, statuses) {
return params;
}
export const EXPORT_DIMENSIONS = [
{ dim: 'date', label: 'Date' },
{ dim: 'subject', label: 'Subject' },
{ dim: 'parameter', label: 'Parameter' },
];
export function dimLabel(dim) {
return EXPORT_DIMENSIONS.find((d) => d.dim === dim)?.label ?? '';
}
export function otherDimension(rowDim, colDim) {
return EXPORT_DIMENSIONS.map((d) => d.dim).find((d) => d !== rowDim && d !== colDim) ?? null;
}
// Resolve a subject's group value for a given group field id.
// null -> no grouping (field is falsy or '__none__')
// '—' -> grouping is on but this subject has no value
export function subjectGroupValue(animal, groupField) {
if (!groupField || groupField === '__none__') return null;
if (groupField === '__name__') return animal?.animal_name ?? '—';
if (groupField === '__id__') return animal?.animal_id_string ?? '—';
const v = animal?.subject_info?.[groupField];
return v === null || v === undefined || v === '' ? '—' : v;
}
export function listDateMembers(statuses) {
const keys = new Set();
for (const s of statuses ?? []) {
if (s?.date) keys.add(dateKey(s.date));
}
return [...keys].sort().map((k) => ({ id: k, label: k, dateKey: k }));
}
// dateKey -> Map(animalId -> status); first status per (date, animal) wins,
// scanning in date order (matches the legacy buildMatrix tie-break).
export function buildStatusIndex(statuses) {
const index = new Map();
const ordered = [...(statuses ?? [])].sort((a, b) => dateKey(a?.date).localeCompare(dateKey(b?.date)));
for (const s of ordered) {
if (!s?.date || s.animal_id === null || s.animal_id === undefined) continue;
const dk = dateKey(s.date);
if (!index.has(dk)) index.set(dk, new Map());
const byAnimal = index.get(dk);
if (!byAnimal.has(s.animal_id)) byAnimal.set(s.animal_id, s);
}
return index;
}
// A cell has a value unless it is null, undefined, or the empty string.
// (0 and false are real values.)
function hasValue(v) {