Skip to content

Commit

Permalink
feat: move filters to components
Browse files Browse the repository at this point in the history
  • Loading branch information
sgratzl committed Apr 19, 2021
1 parent f5ac38c commit d68041b
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 48 deletions.
26 changes: 26 additions & 0 deletions packages/components/src/filters/filterByCategoricalFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* @lineup-lite/components
* https://github.com/sgratzl/lineup-lite
*
* Copyright (c) 2021 Samuel Gratzl <[email protected]>
*/

import { ALWAYS_TRUE } from './utils';

/**
* filter function by a set of filter values
*/
export default function filterByCategoricalFilter(
filterValue?: readonly string[] | null
): (value?: string | null) => boolean {
if (filterValue == null) {
return ALWAYS_TRUE;
}
const lookup = new Set(filterValue);
return (v) => {
if (v == null) {
return false;
}
return !lookup.has(v);
};
}
49 changes: 49 additions & 0 deletions packages/components/src/filters/filterByCategoricalSetFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @lineup-lite/components
* https://github.com/sgratzl/lineup-lite
*
* Copyright (c) 2021 Samuel Gratzl <[email protected]>
*/

import type { FilterSetValue } from '../components';
import { ALWAYS_TRUE } from './utils';

/**
* filter function by a set of filter values
*/
export default function filterByCategoricalSetFilter(
filterValue?: readonly FilterSetValue<string>[] | null
): (value?: readonly string[] | ReadonlySet<string> | null) => boolean {
if (filterValue == null) {
return ALWAYS_TRUE;
}
const must: string[] = [];
const mustNot: string[] = [];
for (const v of filterValue) {
if (v.value) {
must.push(v.set);
} else {
mustNot.push(v.set);
}
}
return (v) => {
const hasV = v instanceof Set ? v : new Set(v);
if (mustNot.length > 0) {
// if any must not value is in the values -> false
for (const mi of mustNot) {
if (hasV.has(mi)) {
return false;
}
}
}
if (must.length > 0) {
// if any must value is not in the values -> false
for (const mi of must) {
if (!hasV.has(mi)) {
return false;
}
}
}
return true;
};
}
28 changes: 28 additions & 0 deletions packages/components/src/filters/filterByRangeFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @lineup-lite/components
* https://github.com/sgratzl/lineup-lite
*
* Copyright (c) 2021 Samuel Gratzl <[email protected]>
*/

import { ALWAYS_TRUE } from './utils';

/**
* a range numeric filter
*/
export default function filterByRangeFilter<T>(filterValue?: readonly [T, T] | null): (v?: T | null) => boolean {
if (filterValue == null) {
return ALWAYS_TRUE;
}
const matches = (v: T) =>
(filterValue[0] == null || v >= filterValue[0]) && (filterValue[1] == null || v <= filterValue[1]);
return (v) => {
if (v == null) {
return false;
}
if (Array.isArray(v)) {
return v.every((vi) => v != null && matches(vi));
}
return matches(v);
};
}
11 changes: 11 additions & 0 deletions packages/components/src/filters/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @lineup-lite/components
* https://github.com/sgratzl/lineup-lite
*
* Copyright (c) 2021 Samuel Gratzl <[email protected]>
*/

export * from './utils';
export { default as filterByCategoricalSetFilter } from './filterByCategoricalSetFilter';
export { default as filterByRangeFilter } from './filterByRangeFilter';
export { default as filterByCategoricalFilter } from './filterByCategoricalFilter';
8 changes: 8 additions & 0 deletions packages/components/src/filters/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @lineup-lite/components
* https://github.com/sgratzl/lineup-lite
*
* Copyright (c) 2021 Samuel Gratzl <[email protected]>
*/

export const ALWAYS_TRUE = () => true;
2 changes: 2 additions & 0 deletions packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@

export * from './components';
export * from './math';
export * from './filters';

10 changes: 4 additions & 6 deletions packages/hooks/src/filters/categoricalFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import type { IdType, Row } from 'react-table';
import type { AnyObject, UnknownObject } from '../interfaces';
import { filterByCategoricalFilter, ALWAYS_TRUE } from '@lineup-lite/components';

/**
* filter function by a set of filter values
Expand All @@ -19,17 +20,14 @@ export function categoricalFilter<D extends AnyObject = UnknownObject>(
ids: readonly IdType<D>[],
filterValue: readonly string[]
): Row<D>[] {
if (filterValue == null) {
const f = filterByCategoricalFilter(filterValue);
if (f === ALWAYS_TRUE) {
return rows as Row<D>[];
}
const lookup = new Set(filterValue);
return rows.filter((row) =>
ids.some((id) => {
const v = row.values[id];
if (v == null) {
return false;
}
return !lookup.has(v);
return f(v);
})
);
}
Expand Down
36 changes: 4 additions & 32 deletions packages/hooks/src/filters/categoricalSetFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import type { IdType, Row } from 'react-table';
import type { FilterSetValue } from '@lineup-lite/components';
import { filterByCategoricalSetFilter, ALWAYS_TRUE, FilterSetValue } from '@lineup-lite/components';
import type { AnyObject, UnknownObject } from '../interfaces';

/**
Expand All @@ -20,42 +20,14 @@ export function categoricalSetFilter<D extends AnyObject = UnknownObject>(
ids: readonly IdType<D>[],
filterValue: readonly FilterSetValue<string>[]
): Row<D>[] {
if (filterValue == null) {
const f = filterByCategoricalSetFilter(filterValue);
if (f === ALWAYS_TRUE) {
return rows as Row<D>[];
}
const must: string[] = [];
const mustNot: string[] = [];
for (const v of filterValue) {
if (v.value) {
must.push(v.set);
} else {
mustNot.push(v.set);
}
}
return rows.filter((row) =>
ids.some((id) => {
const v = row.values[id] as readonly string[] | Set<string>;
if (v == null) {
return false;
}
const hasV = v instanceof Set ? v : new Set(v);
if (mustNot.length > 0) {
// if any must not value is in the values -> false
for (const mi of mustNot) {
if (hasV.has(mi)) {
return false;
}
}
}
if (must.length > 0) {
// if any must value is not in the values -> false
for (const mi of must) {
if (!hasV.has(mi)) {
return false;
}
}
}
return true;
return f(v);
})
);
}
Expand Down
14 changes: 4 additions & 10 deletions packages/hooks/src/filters/rangeFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import type { Row } from 'react-table';
import { filterByRangeFilter, ALWAYS_TRUE } from '@lineup-lite/components';
import type { AnyObject, UnknownObject } from '../interfaces';

/**
Expand All @@ -16,21 +17,14 @@ export function rangeFilter<D extends AnyObject = UnknownObject, T = unknown>(
ids: readonly string[],
filterValue: readonly [T, T]
): Row<D>[] {
if (filterValue == null) {
const f = filterByRangeFilter(filterValue);
if (f === ALWAYS_TRUE) {
return rows as Row<D>[];
}
const matches = (v: T) =>
(filterValue[0] == null || v >= filterValue[0]) && (filterValue[1] == null || v <= filterValue[1]);
return rows.filter((row) =>
ids.some((id) => {
const v = row.values[id];
if (v == null) {
return false;
}
if (Array.isArray(v)) {
return v.every((vi) => v != null && matches(vi));
}
return matches(v);
return f(v);
})
);
}
Expand Down

0 comments on commit d68041b

Please sign in to comment.