filter groups

This commit is contained in:
Timo Hocker 2020-06-30 10:00:36 +02:00
parent 7939aaf3a7
commit c9e419d8e9
4 changed files with 77 additions and 18 deletions

2
Jenkinsfile vendored
View File

@ -5,7 +5,7 @@ pipeline {
VERSION = VersionNumber([ VERSION = VersionNumber([
versionNumberString: versionNumberString:
'${BUILDS_ALL_TIME}', '${BUILDS_ALL_TIME}',
versionPrefix: '1.5.', versionPrefix: '1.6.',
worstResultForIncrement: 'SUCCESS' worstResultForIncrement: 'SUCCESS'
]) ])
} }

View File

@ -1,6 +1,6 @@
# @sapphirecode/utilities # @sapphirecode/utilities
version: 1.5.x version: 1.6.x
small utility functions to make much needed features easier to work with small utility functions to make much needed features easier to work with
@ -118,13 +118,34 @@ const result = util.recursive_filter(
[ [
{ {
filter: /foo bar/iu, filter: /foo bar/iu,
fields: ['name', 'name_2'] // fields will be joined with a space in between field: ['name', 'name_2'] // fields will be joined with a space in between
// {name: 'foo', name_2: 'bar'} will become 'foo bar' // {name: 'foo', name_2: 'bar'} will become 'foo bar'
} }
] ]
); );
``` ```
filter groups can be used to connect filters with OR
```js
const result = util.recursive_filter(
[...],
[
{
filter: /foo bar/iu,
field: 'name'
},
{
or: [
{ filter: /foo/u, field: 'bar' },
{ filter: /bar/u, field: 'bar' }
]
}
]
);
```
## License ## License
MIT © Timo Hocker <timo@scode.ovh> MIT © Timo Hocker <timo@scode.ovh>

View File

@ -78,19 +78,45 @@ function is_nil (obj) {
|| (typeof obj === 'number' && isNaN (obj)); || (typeof obj === 'number' && isNaN (obj));
} }
function to_search_string (element, field) { function check_filter (filter, e) {
return Array.isArray (field) const search_str = Array.isArray (filter.field)
? field.map ((f) => element[f]) ? filter.field.map ((f) => e[f])
.filter ((v) => typeof v !== 'undefined') .filter ((v) => typeof v !== 'undefined')
.join (' ') .join (' ')
: element[field]; : e[filter.field];
return filter.filter.test (search_str);
} }
function check_filters (filters, e, or = false) {
for (const filter of filters) {
let res = false;
if (Array.isArray (filter.or))
res = check_filters (filter.or, e, true);
else
res = check_filter (filter, e);
if (or && res)
return true;
if (!res && !or)
return false;
}
return !or;
}
/**
* @typedef Filter
* @type {object}
* @property {string|string[]} field - fields to apply filter on
* @property {RegExp} filter - filter
* @property {Filter[]} or - create an OR group of filters
*/
/** /**
* filter nested objects * filter nested objects
* *
* @param {Array<object>} input * @param {Array<object>} input
* @param {Array<{field: string, filter: RegExp}>} filters * @param {Filter[]} filters
* @returns {Array<object>} filtered data * @returns {Array<object>} filtered data
*/ */
function recursive_filter (input, filters, children_key = 'children') { function recursive_filter (input, filters, children_key = 'children') {
@ -99,16 +125,7 @@ function recursive_filter (input, filters, children_key = 'children') {
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
const e = { ...data[i] }; const e = { ...data[i] };
data[i] = e; data[i] = e;
let match = true; if (check_filters (filters, e)) {
for (const filter of filters) {
const search_str = to_search_string (e, filter.field);
if (!filter.filter.test (search_str)) {
match = false;
break;
}
}
if (match) {
filtered.push (e); filtered.push (e);
} }
else { else {

View File

@ -204,3 +204,24 @@ test ('recursive filter undefined multifield', (t) => {
); );
t.deepEqual (res, []); t.deepEqual (res, []);
}); });
test ('recursive filter with or group', (t) => {
const to_filter = [
{ name: 'foo' },
{ name: 'bar' },
{ name: 'baz' }
];
const filter = [
{
or: [
{ field: 'name', filter: /foo/u },
{ field: 'name', filter: /bar/u }
]
}
];
const res = util.recursive_filter (to_filter, filter);
t.deepEqual (res, to_filter.slice (0, 2));
});