filterDataset = (data, filters) => {
  const {columns} = data;
  if (!columns || columns.length === 0) {
    return null;
  }
  const idArray = dotRange(columns[0].length);
  if (!filters || filters.length === 0) {
    return idArray;
  }
  const filterArray = Array.isArray(filters) ? filters : [filters];

  return idArray.filter(id => {
    return filterArray.every(({type, key, value}) => {
      const columnToFilter = columns[key];
      switch (type) {
        case FILTER_TYPE.RANGE:
          return (
            columnToFilter[id] >= value[0] && columnToFilter[id] <= value[1]
          );
        case FILTER_TYPE.INCLUDE:
          return value.includes(columnToFilter[id]);
        case FILTER_TYPE.EXCLUDE:
          return !value.includes(columnToFilter[id]);
        case FILTER_TYPE.FUNC:
          return Boolean(value(columnToFilter[id]));
        default:
          return false;
      }
    });
  });
}
filter data items w/ a set of filters
@param  {Object} data {columns, fields}
@param  {Array<Array<Number|String|Boolean>>>} data.columns an array of data rows
@param  {Array<Object>} data.fields an array of field definitions w/ attributes: {name, type, tableFieldIndex}
@param  {Array<Object>} filters an array of filters w/ attributes: {name, type, key, value}
@param  {String} filters.type filter type, one of FILTER_TYPE
@param  {Number} filters.key feature.tableFieldIndex of the feature to be filtered on
@return {Array<Number>} an array of data ids suffice all the filters