filter groups
This commit is contained in:
		
							
								
								
									
										2
									
								
								Jenkinsfile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Jenkinsfile
									
									
									
									
										vendored
									
									
								
							@@ -5,7 +5,7 @@ pipeline {
 | 
			
		||||
        VERSION = VersionNumber([
 | 
			
		||||
            versionNumberString:
 | 
			
		||||
                '${BUILDS_ALL_TIME}',
 | 
			
		||||
            versionPrefix: '1.5.',
 | 
			
		||||
            versionPrefix: '1.6.',
 | 
			
		||||
            worstResultForIncrement: 'SUCCESS'
 | 
			
		||||
        ])
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README.md
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
# @sapphirecode/utilities
 | 
			
		||||
 | 
			
		||||
version: 1.5.x
 | 
			
		||||
version: 1.6.x
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
      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'
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
MIT © Timo Hocker <timo@scode.ovh>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										47
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								index.js
									
									
									
									
									
								
							@@ -78,19 +78,45 @@ function is_nil (obj) {
 | 
			
		||||
      || (typeof obj === 'number' && isNaN (obj));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function to_search_string (element, field) {
 | 
			
		||||
  return Array.isArray (field)
 | 
			
		||||
    ? field.map ((f) => element[f])
 | 
			
		||||
function check_filter (filter, e) {
 | 
			
		||||
  const search_str = Array.isArray (filter.field)
 | 
			
		||||
    ? filter.field.map ((f) => e[f])
 | 
			
		||||
      .filter ((v) => typeof v !== 'undefined')
 | 
			
		||||
      .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
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Array<object>} input
 | 
			
		||||
 * @param {Array<{field: string, filter: RegExp}>} filters
 | 
			
		||||
 * @param {Filter[]} filters
 | 
			
		||||
 * @returns {Array<object>} filtered data
 | 
			
		||||
 */
 | 
			
		||||
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++) {
 | 
			
		||||
    const e = { ...data[i] };
 | 
			
		||||
    data[i] = e;
 | 
			
		||||
    let match = true;
 | 
			
		||||
    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) {
 | 
			
		||||
    if (check_filters (filters, e)) {
 | 
			
		||||
      filtered.push (e);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
 
 | 
			
		||||
@@ -204,3 +204,24 @@ test ('recursive filter undefined multifield', (t) => {
 | 
			
		||||
  );
 | 
			
		||||
  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));
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user