redux-search-filter
Version:
[![NPM version][npm-image]][npm-url] [![build status][travis-image]][travis-url] [![Test coverage][codecov-image]][codecov-url] [![npm download][download-image]][download-url]
123 lines (111 loc) • 2.96 kB
JavaScript
import min from 'ml-array-min';
import max from 'ml-array-max';
import filterData from './filterData';
import * as kinds from './constants/kinds';
import { MULTIPLE_EMPTY } from './constants/sentinels';
export default function filterOneSelector(data, name, propFunc, kind, filters) {
switch (kind) {
case kinds.value:
return filterValue(data, name, propFunc, filters);
case kinds.multiple:
return filterMultiple(data, name, propFunc, filters);
case kinds.range:
return filterRange(data, name, propFunc, filters);
default:
throw new Error(`invalid filter kind: ${kind}`);
}
}
function filterValue(data, name, propFunc, filters) {
data = filterDataFor(data, name, filters);
return makeArray(countBy(data, propFunc));
}
function filterMultiple(data, name, propFunc, filters) {
data = filterDataFor(data, name, filters);
const filter = filters && filters.get(name);
if (filter && filter.negated) {
return makeArray(countMultipleNegated(data, propFunc));
} else {
return makeArray(countMultiple(data, propFunc));
}
}
function filterRange(data, name, propFunc, filters) {
data = filterDataFor(data, name, filters);
data = data.map((item) => propFunc(item)).filter(isNumber);
if (data.length === 0) {
return {
min: 0,
max: 0
};
}
return {
min: min(data),
max: max(data)
};
}
function filterDataFor(data, name, filters) {
if (!filters) return data;
filters = filters.filter((item, key) => {
return key !== name;
});
if (filters.size > 0) {
data = filterData(data, filters);
}
return data;
}
function makeArray(counts) {
const result = [];
for (const [value, count] of counts) {
result.push({
value,
count
});
}
result.sort((a, b) => b.count - a.count);
return result;
}
function countMultiple(data, propFunc) {
const counts = new Map();
for (const item of data) {
const value = propFunc(item);
if (!value || !value[Symbol.iterator]) {
continue;
}
if (value.length === 0) {
if (!counts.has(MULTIPLE_EMPTY)) {
counts.set(MULTIPLE_EMPTY, 1);
} else {
counts.set(MULTIPLE_EMPTY, counts.get(MULTIPLE_EMPTY) + 1);
}
}
for (const el of value) {
if (!counts.has(el)) {
counts.set(el, 1);
} else {
counts.set(el, counts.get(el) + 1);
}
}
}
return counts;
}
function countMultipleNegated(data, propFunc) {
const counts = countMultiple(data, propFunc);
for (const [key, value] of counts) {
counts.set(key, data.length - value);
}
return counts;
}
function countBy(array, accessor) {
const counts = new Map();
for (const element of array) {
const value = accessor(element);
if (!counts.has(value)) {
counts.set(value, 1);
} else {
counts.set(value, counts.get(value) + 1);
}
}
return counts;
}
function isNumber(x) {
return typeof x === 'number';
}