Skip to content

Commit

Permalink
feat: use lodash's property function to extract prop
Browse files Browse the repository at this point in the history
Allows to pass a jpath in the form a dot-string ('a.b.c') or an array
(['a', 'b', 'c']).
  • Loading branch information
targos committed Sep 28, 2017
1 parent 6978554 commit f14fa8e
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 26 deletions.
5 changes: 3 additions & 2 deletions src/ConnectedFilter.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Component, createElement} from 'react';
import {connect} from 'react-redux';
import {createSelector} from 'reselect';
import lodashProperty from 'lodash-es/property';

import {
updateFilter,
Expand All @@ -26,13 +27,13 @@ class ConnectedFilter extends Component {
setupSelector() {
const data = (props) => props.data;
const name = (props) => props.name;
const prop = (props) => props.prop;
const propFunc = (props) => lodashProperty(props.prop);
const kind = (props) => props.kind;
const filters = (props) => props.filters;
this.selector = createSelector(
data,
name,
prop,
propFunc,
kind,
filters,
filterOneSelector
Expand Down
11 changes: 7 additions & 4 deletions src/__tests__/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import {Map} from 'immutable';
import filterData from '../filterData';

const data = [
{A: ['Y'], B: 'Y', C: 1},
{A: ['Y'], B: 'Y', C: 1, D: {X: 'X'}},
{A: ['Z'], B: 'Z', C: 3},
{A: ['Z', 'Y'], B: 'X', C: 2},
{A: ['X'], B: 'Y', C: -1},
{A: ['Z', 'Y'], B: 'X', C: 2, D: {Y: 'Y'}},
{A: ['X'], B: 'Y', C: -1, D: {X: 'OTHER'}},
];
data.forEach((d, idx) => d.idx = idx);

Expand Down Expand Up @@ -41,7 +41,10 @@ describe('Test filter', () => {
{prop: 'B', value: ['X'], expected: [2]},
{prop: 'B', value: ['X', 'Y'], operator: 'AND', negated: true, expected: [1]},
{prop: 'B', value: ['X', 'Y'], operator: 'OR', negated: true, expected: [0, 1, 2, 3]},
{prop: 'B', value: ['Y'], negated: false, expected: [0, 3], operator: 'AND'}
{prop: 'B', value: ['Y'], negated: false, expected: [0, 3], operator: 'AND'},
{prop: 'D.X', value: ['X'], expected: [0]},
{prop: ['D', 'X'], value: ['OTHER'], expected: [3]},
{prop: 'D.Y', value: ['Y'], expected: [2]},
];

for (let filter of filters) {
Expand Down
13 changes: 8 additions & 5 deletions src/filterData.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import {AND, OR} from './constants/operators';
import lodashProperty from 'lodash-es/property';

export default function filterData(data, filters) {
filters = Array.from(filters);
filters = filters.map(([name, filterOptions]) => [name, filterOptions, lodashProperty(filterOptions.prop)]);
return data.filter((item) => {
main: for (const [, filterOptions] of filters) {
main: for (const [, filterOptions, filterProp] of filters) {
const filterValue = filterOptions.value;
const filterProp = filterOptions.prop;
let operator = filterOptions.operator;
let negated = filterOptions.negated;
const itemValue = item[filterProp];
const itemValue = filterProp(item);
if (filterValue) {
if (filterValue.length > 0) {
if (Array.isArray(itemValue)) { // kind: multiple
Expand Down Expand Up @@ -40,7 +42,7 @@ export default function filterData(data, filters) {
}
} else { // kind: value
operator = operator || OR;
const isIncluded = filterValue.includes(item[filterProp]);
const isIncluded = filterValue.includes(filterProp(item));
if (operator === AND) {
if (negated) {
if (isIncluded) {
Expand Down Expand Up @@ -69,7 +71,8 @@ export default function filterData(data, filters) {
}
}
} else { // kind: range
if (item[filterProp] < filterOptions.min || item[filterProp] > filterOptions.max) {
const value = filterProp(item);
if (value < filterOptions.min || value > filterOptions.max) {
return false;
}
}
Expand Down
30 changes: 15 additions & 15 deletions src/filterOneSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,44 @@ import max from 'ml-array-max';
import filterData from './filterData';
import * as kinds from './constants/kinds';

export default function filterOneSelector(data, name, prop, kind, filters) {
export default function filterOneSelector(data, name, propFunc, kind, filters) {
switch (kind) {
case kinds.value:
return filterValue(data, name, prop, filters);
return filterValue(data, name, propFunc, filters);
case kinds.multiple:
return filterMultiple(data, name, prop, filters);
return filterMultiple(data, name, propFunc, filters);
case kinds.range:
return filterRange(data, name, prop, filters);
return filterRange(data, name, propFunc, filters);
default:
throw new Error(`invalid filter kind: ${kind}`);
}
}

function filterValue(data, name, prop, filters) {
function filterValue(data, name, propFunc, filters) {
data = filterDataFor(data, name, filters);
return makeArray(countBy(data, prop));
return makeArray(countBy(data, propFunc));
}

function filterMultiple(data, name, prop, filters) {
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, prop));
return makeArray(countMultipleNegated(data, propFunc));
} else {
return makeArray(countMultiple(data, prop));
return makeArray(countMultiple(data, propFunc));
}

}

function filterRange(data, name, prop, filters) {
function filterRange(data, name, propFunc, filters) {
data = filterDataFor(data, name, filters);
if (data.length === 0) {
return {
min: 0,
max: 1
};
}
data = data.map((item) => item[prop]);
data = data.map((item) => propFunc(item));
return {
min: min(data),
max: max(data)
Expand Down Expand Up @@ -74,10 +74,10 @@ function makeArray(map) {
return result;
}

function countMultiple(data, prop) {
function countMultiple(data, propFunc) {
const counts = {};
for (const item of data) {
const value = item[prop];
const value = propFunc(item);
for (const str of value) {
if (counts[str] === undefined) {
counts[str] = 1;
Expand All @@ -89,8 +89,8 @@ function countMultiple(data, prop) {
return counts;
}

function countMultipleNegated(data, prop) {
const counts = countMultiple(data, prop);
function countMultipleNegated(data, propFunc) {
const counts = countMultiple(data, propFunc);
for (const key in counts) {
counts[key] = data.length - counts[key];
}
Expand Down

0 comments on commit f14fa8e

Please sign in to comment.