add error when not found

This commit is contained in:
ryan 2019-03-13 17:16:20 -07:00
parent a17b1912c2
commit c690598557
3 changed files with 114 additions and 28 deletions

View File

@ -32,9 +32,22 @@ export class TableReducePicker extends PureComponent<Props> {
checkInput = () => {
const { reducers, allowMultiple, defaultReducer, onChange } = this.props;
if (!allowMultiple && reducers.length > 1) {
onChange(reducers.slice(0, 1));
// Check that the selected reducers are all real
const notFound: string[] = [];
const current = getTableReducers(reducers, notFound);
if (notFound.length > 0) {
console.warn('Unknown reducers', notFound, reducers);
onChange(current.map(reducer => reducer.value));
}
// Make sure there is only one
if (!allowMultiple && reducers.length > 1) {
console.warn('Removing extra reducers', reducers);
onChange([reducers[0]]);
}
// Set the reducer from callback
if (defaultReducer && reducers.length < 1) {
onChange([defaultReducer]);
}

View File

@ -9,20 +9,32 @@ describe('Table Reducer', () => {
TableReducerID.sum,
TableReducerID.max,
TableReducerID.min,
// TableReducerID.logmin,
TableReducerID.logmin,
TableReducerID.mean,
TableReducerID.last,
TableReducerID.first,
TableReducerID.count,
TableReducerID.range,
TableReducerID.diff,
TableReducerID.step,
TableReducerID.delta,
// TableReducerID.allIsZero,
// TableReducerID.allIsNull,
];
const reducers = getTableReducers(names);
const notFound: string[] = [];
const reducers = getTableReducers(names, notFound);
reducers.forEach((reducer, index) => {
expect(reducer ? reducer.value : '<missing>').toEqual(names[index]);
});
expect(notFound.length).toBe(0);
});
it('should fail to load unknown reducers', () => {
const names = ['not a reducer', TableReducerID.max, TableReducerID.min, 'also not a reducer'];
const notFound: string[] = [];
const reducers = getTableReducers(names, notFound);
expect(reducers.length).toBe(2);
expect(notFound.length).toBe(2);
});
it('should calculate stats', () => {

View File

@ -14,6 +14,8 @@ export enum TableReducerID {
count = 'count',
range = 'range',
diff = 'diff',
delta = 'delta',
step = 'step',
allIsZero = 'allIsZero',
allIsNull = 'allIsNull',
@ -32,15 +34,24 @@ export interface TableReducerInfo {
reducer?: TableReducer;
}
/** Get a list of the known reducing functions */
export function getTableReducers(ids?: string[]): TableReducerInfo[] {
if (!hasBuiltIndex) {
getById(TableReducerID.sum); // Force the registry to load
}
/**
* Get a list of the known reducing functions
* @param ids list of reducer names or null to get all of them
* @param notFound optional error object that will be filled with the names on unknown reducers
*/
export function getTableReducers(ids?: string[], notFound?: string[]): TableReducerInfo[] {
if (ids === null || ids === undefined) {
return listOfReducers;
}
return ids.map(id => getById(id));
return ids.reduce((list, id) => {
const reducer = getById(id);
if (reducer) {
list.push(reducer);
} else if (notFound && id) {
notFound.push(id);
}
return list;
}, new Array<TableReducerInfo>());
}
export interface TableReducerOptions {
@ -114,7 +125,7 @@ const listOfReducers: TableReducerInfo[] = [];
const index: TableReducerIndex = {};
let hasBuiltIndex = false;
function getById(id: string): TableReducerInfo {
function getById(id: string): TableReducerInfo | undefined {
if (!hasBuiltIndex) {
[
{
@ -144,12 +155,30 @@ function getById(id: string): TableReducerInfo {
description: 'Difference between minimum and maximum values',
standard: true,
},
{
value: TableReducerID.delta,
label: 'Delta',
description: 'Cumulative change in value', // HELP! not totally sure what this does
standard: true,
},
{
value: TableReducerID.step,
label: 'Step',
description: 'Minimum interval between values',
standard: true,
},
{
value: TableReducerID.diff,
label: 'Difference',
description: 'Difference between first and last values',
standard: true,
},
{
value: TableReducerID.logmin,
label: 'Min (above zero)',
description: 'Used for log min scale',
standard: true,
},
].forEach(calc => {
const { value, alias } = calc;
if (index.hasOwnProperty(value)) {
@ -197,7 +226,8 @@ interface StandardStats {
nonNullCount: number;
range: number | null;
diff: number | null;
delta: number | null;
step: number | null;
allIsZero: boolean;
allIsNull: boolean;
}
@ -223,7 +253,12 @@ function standardStatsReducer(
allIsZero: false,
range: null,
diff: null,
} as StandardStats;
delta: 0,
step: 0,
// Just used for calcutations -- not exposed as a reducer
previousDeltaUp: true,
};
});
for (let i = 0; i < data.rows.length; i++) {
@ -240,40 +275,66 @@ function standardStatsReducer(
}
}
if (stats.first === null) {
stats.first = currentValue;
}
if (currentValue !== null) {
stats.last = currentValue;
const isFirst = stats.first === null;
if (isFirst) {
stats.first = currentValue;
}
if (isNumber(currentValue)) {
stats.sum! += currentValue;
stats.sum += currentValue;
stats.allIsNull = false;
stats.nonNullCount++;
}
if (currentValue > stats.max!) {
stats.max = currentValue;
}
if (!isFirst) {
const step = currentValue - stats.last!;
if (stats.step > step) {
stats.step = step; // the minimum interval
}
if (currentValue < stats.min!) {
stats.min = currentValue;
}
if (stats.last! > currentValue) {
// counter reset
stats.previousDeltaUp = false;
if (i === data.rows.length - 1) {
// reset on last
stats.delta += currentValue;
}
} else {
if (stats.previousDeltaUp) {
stats.delta += step; // normal increment
} else {
stats.delta += currentValue; // account for counter reset
}
stats.previousDeltaUp = true;
}
}
if (currentValue < stats.logmin && currentValue > 0) {
stats.logmin = currentValue;
if (currentValue > stats.max) {
stats.max = currentValue;
}
if (currentValue < stats.min) {
stats.min = currentValue;
}
if (currentValue < stats.logmin && currentValue > 0) {
stats.logmin = currentValue;
}
}
if (currentValue !== 0) {
stats.allIsZero = false;
}
stats.last = currentValue;
}
}
}
for (let x = 0; x < column.length; x++) {
const stats = column[x];
const stats = column[x] as StandardStats;
if (stats.max === -Number.MAX_VALUE) {
stats.max = null;