smart-table-filter
Version:
takes a configuration object and returns a filter function operating on arrays
88 lines (85 loc) • 3.19 kB
JavaScript
import { compose } from 'smart-table-operators';
import { pointer } from 'smart-table-json-pointer';
var Type;
(function (Type) {
Type["BOOLEAN"] = "boolean";
Type["NUMBER"] = "number";
Type["DATE"] = "date";
Type["STRING"] = "string";
})(Type || (Type = {}));
const typeExpression = (type) => {
switch (type) {
case Type.BOOLEAN:
return Boolean;
case Type.NUMBER:
return Number;
case Type.DATE:
return val => new Date(val);
case Type.STRING:
return compose(String, val => val.toLowerCase());
default:
return val => val;
}
};
var FilterOperator;
(function (FilterOperator) {
FilterOperator["INCLUDES"] = "includes";
FilterOperator["IS"] = "is";
FilterOperator["IS_NOT"] = "isNot";
FilterOperator["LOWER_THAN"] = "lt";
FilterOperator["GREATER_THAN"] = "gt";
FilterOperator["GREATER_THAN_OR_EQUAL"] = "gte";
FilterOperator["LOWER_THAN_OR_EQUAL"] = "lte";
FilterOperator["EQUALS"] = "equals";
FilterOperator["NOT_EQUALS"] = "notEquals";
FilterOperator["ANY_OF"] = "anyOf";
})(FilterOperator || (FilterOperator = {}));
const not = fn => input => !fn(input);
const is = value => input => Object.is(value, input);
const lt = value => input => input < value;
const gt = value => input => input > value;
const equals = value => input => value === input;
const includes = value => input => input.includes(value);
const anyOf = value => input => value.includes(input);
const operators = {
["includes" /* INCLUDES */]: includes,
["is" /* IS */]: is,
["isNot" /* IS_NOT */]: compose(is, not),
["lt" /* LOWER_THAN */]: lt,
["gte" /* GREATER_THAN_OR_EQUAL */]: compose(lt, not),
["gt" /* GREATER_THAN */]: gt,
["lte" /* LOWER_THAN_OR_EQUAL */]: compose(gt, not),
["equals" /* EQUALS */]: equals,
["notEquals" /* NOT_EQUALS */]: compose(equals, not),
["anyOf" /* ANY_OF */]: anyOf
};
const every = fns => (...args) => fns.every(fn => fn(...args));
const predicate = ({ value = '', operator = "includes" /* INCLUDES */, type }) => {
const typeIt = typeExpression(type);
const operateOnTyped = compose(typeIt, operators[operator]);
const predicateFunc = operateOnTyped(value);
return compose(typeIt, predicateFunc);
};
// Avoid useless filter lookup (improve perf)
const normalizeClauses = (conf) => {
const output = {};
const validPath = Object.keys(conf).filter(path => Array.isArray(conf[path]));
validPath.forEach(path => {
const validClauses = conf[path].filter(c => c.value !== '');
if (validClauses.length > 0) {
output[path] = validClauses;
}
});
return output;
};
const filter = (filter) => {
const normalizedClauses = normalizeClauses(filter);
const funcList = Object.keys(normalizedClauses).map(path => {
const getter = pointer(path).get;
const clauses = normalizedClauses[path].map(predicate);
return compose(getter, every(clauses));
});
const filterPredicate = every(funcList);
return array => array.filter(filterPredicate);
};
export { FilterOperator, filter, predicate };