mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Profile per-column cardinality and extent; add data-aware chart warnings (M4, A3/A4)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import { profileData } from './profile';
|
||||
import { DISTINCT_CAP, profileData } from './profile';
|
||||
|
||||
describe('profileData', () => {
|
||||
test('profiles a JSON-array dataset fully', () => {
|
||||
@@ -53,3 +53,47 @@ describe('profileData', () => {
|
||||
expect(profile.columnTypes).toEqual([{ name: 'v', type: 'number' }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('profileData — column stats (cardinality + numeric extent)', () => {
|
||||
test('counts distinct values and reports numeric extent for number columns', () => {
|
||||
const rows = [
|
||||
{ region: 'N', sales: 10 },
|
||||
{ region: 'S', sales: -4 },
|
||||
{ region: 'N', sales: 25 }, // region repeats → 2 distinct, not 3
|
||||
];
|
||||
const stats = profileData(rows, 0).columnStats;
|
||||
expect(stats).toEqual([
|
||||
{ name: 'region', distinct: 2, distinctCapped: false, numericExtent: null },
|
||||
{ name: 'sales', distinct: 3, distinctCapped: false, numericExtent: { min: -4, max: 25 } },
|
||||
]);
|
||||
});
|
||||
|
||||
test('distinct counting is empty-insensitive and case/whitespace literal', () => {
|
||||
const rows = [{ c: 'A' }, { c: ' A ' }, { c: '' }, { c: null }, { c: 'b' }];
|
||||
// ' A ' trims to 'A' (one key); '' and null are empties (no signal) → 2 distinct.
|
||||
expect(profileData(rows, 0).columnStats[0]).toEqual({
|
||||
name: 'c',
|
||||
distinct: 2,
|
||||
distinctCapped: false,
|
||||
numericExtent: null,
|
||||
});
|
||||
});
|
||||
|
||||
test('caps distinct at DISTINCT_CAP and flags the overflow', () => {
|
||||
const rows = Array.from({ length: DISTINCT_CAP + 25 }, (_, i) => ({ id: `v${i}` }));
|
||||
const stat = profileData(rows, 0).columnStats[0];
|
||||
expect(stat.distinct).toBe(DISTINCT_CAP);
|
||||
expect(stat.distinctCapped).toBe(true);
|
||||
});
|
||||
|
||||
test('numericExtent is null for a non-numeric column even if some cells parse', () => {
|
||||
// A 'string' column (one non-numeric value knocks the type down) carries no extent.
|
||||
const rows = [{ v: '1' }, { v: '2' }, { v: 'oops' }];
|
||||
const stat = profileData(rows, 0).columnStats[0];
|
||||
expect(stat.numericExtent).toBeNull();
|
||||
});
|
||||
|
||||
test('N/A profile carries empty column stats', () => {
|
||||
expect(profileData(null, 9).columnStats).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user