feat(export): X-coordinate helpers (date, # days reach, daily field)

This commit is contained in:
Experiments DB Dev
2026-07-19 14:54:25 -04:00
parent 3e52117c1a
commit 8510903771
2 changed files with 116 additions and 0 deletions
+52
View File
@@ -335,3 +335,55 @@ describe('listParameterMembers / listDimensionMembers', () => {
expect(listDimensionMembers('parameter', ctx)[0].id).toBe('__total__');
});
});
import { numericFieldVal, listSampleMembers, buildSampleIndex } from '../src/lib/dataExport';
const sDaily = [{ fieldId: 'c-w', key: 'w', label: 'Weight', builtin: false, active: true }];
const sStatuses = [
{ animal_id: 'a1', date: '2026-07-01T00:00:00Z', custom_fields: { 'c-w': '250' } },
{ animal_id: 'a1', date: '2026-07-03T00:00:00Z', custom_fields: { 'c-w': '260' } },
{ animal_id: 'a2', date: '2026-07-01T00:00:00Z', custom_fields: { 'c-w': '250' } },
];
describe('numericFieldVal', () => {
it('reads builtin via key and custom via fieldId, parsed to number', () => {
expect(numericFieldVal({ weight: '250' }, { builtin: true, key: 'weight' })).toBe(250);
expect(numericFieldVal({ custom_fields: { 'c-w': '12.5' } }, { builtin: false, fieldId: 'c-w' })).toBe(12.5);
});
it('returns null for non-numeric, missing, or no field', () => {
expect(numericFieldVal({ custom_fields: { 'c-w': 'abc' } }, { builtin: false, fieldId: 'c-w' })).toBeNull();
expect(numericFieldVal({}, { builtin: true, key: 'weight' })).toBeNull();
expect(numericFieldVal({ weight: 1 }, null)).toBeNull();
});
});
describe('listSampleMembers', () => {
it('date: distinct dates sorted', () => {
expect(listSampleMembers(sStatuses, '__date__', sDaily).map((m) => m.sampleValue)).toEqual(['2026-07-01', '2026-07-03']);
});
it('# days reach: 1..max records per subject', () => {
expect(listSampleMembers(sStatuses, '__days__', sDaily).map((m) => m.sampleValue)).toEqual([1, 2]);
});
it('daily field: distinct numeric values sorted ascending', () => {
expect(listSampleMembers(sStatuses, 'c-w', sDaily).map((m) => m.sampleValue)).toEqual([250, 260]);
});
});
describe('buildSampleIndex', () => {
it('date coord maps animalId -> dateKey -> status', () => {
const idx = buildSampleIndex(sStatuses, '__date__', sDaily);
expect(idx.get('a1').get('2026-07-03').date).toContain('2026-07-03');
});
it('# days reach assigns per-subject ordinals in date order', () => {
const idx = buildSampleIndex(sStatuses, '__days__', sDaily);
expect(idx.get('a1').get(1).date).toContain('2026-07-01');
expect(idx.get('a1').get(2).date).toContain('2026-07-03');
expect(idx.get('a2').get(1).date).toContain('2026-07-01');
expect(idx.get('a2').has(2)).toBe(false);
});
it('daily field maps numeric value to first status by date', () => {
const idx = buildSampleIndex(sStatuses, 'c-w', sDaily);
expect(idx.get('a1').get(250).date).toContain('2026-07-01');
expect(idx.get('a1').get(260).date).toContain('2026-07-03');
});
});