Last active
August 8, 2022 11:21
-
-
Save dmitry-tuzenkov/341cf0ef3945b22476d5485a1fc86e14 to your computer and use it in GitHub Desktop.
Filters Implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const _get = require('lodash.get') | |
const _isEmpty = require('lodash.isempty') | |
const _sumBy = require('lodash.sumby') | |
const _max = require('lodash.max') | |
const _flatten = require('lodash.flatten') | |
const _last = require('lodash.last') | |
const _size = require('lodash.size') | |
const _first = require('lodash.first') | |
const _map = (arr = [], fn) => Array.from(arr).map(fn) | |
const _filter = (arr = [], fn) => Array.from(arr).filter(fn) | |
const _omit = (obj = {}, arr = []) => | |
Object.entries(obj).reduce((acc, x) => { | |
const [key, value] = x | |
if (arr.includes(key)) { | |
return acc | |
} | |
return { ...acc, [key]: value } | |
}, {}) | |
module.exports = { | |
_first, | |
_filter, | |
_flatten, | |
_get, | |
_map, | |
_omit, | |
_isEmpty, | |
_sumBy, | |
_max, | |
_size, | |
_last, | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const FILTER_CONDITION = { OR: '+', AND: '*' } | |
const FILTER_TYPE = { ROWS: 'r', COLUMNS: 'c', GROUP: 'g' } | |
const FILTER_ACTIONS = { | |
CONTAIN: 'cn', | |
NOT_CONTAIN: '!cn', | |
EQUAL: 'eq', | |
NOT_EQUAL: '!eq', | |
EMPTY: 'emp', | |
NOT_EMPTY: '!emp', | |
} | |
module.exports = { | |
FILTER_ACTIONS, | |
FILTER_CONDITION, | |
FILTER_TYPE, | |
IHUB_API_URL, | |
PRODUCT, | |
USERAGENT, | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const filters = [ | |
{ | |
id: _last(workflow).id, | |
type: FILTER_TYPE.ROWS, | |
expr: [ | |
[FILTER_CONDITION.AND, FILTER_ACTIONS.NOT_EMPTY, 'twitterTweet'], | |
[ | |
FILTER_CONDITION.OR, | |
FILTER_ACTIONS.CONTAIN, | |
'websiteUrl', | |
URL_CONSTANT, | |
], | |
], | |
}, | |
{ | |
id: _last(workflow).id, | |
type: FILTER_TYPE.ROWS, | |
expr: [ | |
[ | |
FILTER_CONDITION.AND, | |
FILTER_ACTIONS.CONTAIN, | |
'twitterTweet', | |
TWEET_CONSTANT, | |
], | |
], | |
}, | |
{ | |
id: _last(workflow).id, | |
type: FILTER_TYPE.COLUMNS, | |
expr: [[FILTER_CONDITION.AND, FILTER_ACTIONS.NOT_EMPTY, 'tags']], | |
}, | |
] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable indent */ | |
const { | |
FILTER_ACTIONS, | |
FILTER_CONDITION, | |
FILTER_TYPE, | |
} = require('./constants') | |
const { | |
_size, | |
_filter, | |
_map, | |
_omit, | |
_last, | |
_first, | |
_isEmpty, | |
} = require('./common') | |
// Expressions example array: | |
// [FILTER_CONDITION.OR, 'twitterTweet', FILTER_ACTIONS.NOT_EMPTY], | |
// [ | |
// FILTER_CONDITION.OR, | |
// 'websiteUrl', | |
// FILTER_ACTIONS.CONTAIN, | |
// URL_CONSTANT, | |
// ], | |
const isConst = (key = '') => { | |
const arr = Array.from(key) | |
return _first(arr) === '"' && _last(arr) === '"' | |
} | |
/** | |
* Extract a value from data object | |
* @param {Object} data | |
* @param {string} key | |
* @returns {string} | |
*/ | |
const toValue = (data = {}, key = '') => { | |
if (!isConst(key)) { | |
return data[key] | |
} | |
// if value or constant | |
const arr = Array.from(key) | |
arr.shift() | |
arr.pop() | |
return arr.join('') | |
} | |
/** | |
* Expressions cmparator | |
* @param {string} op operator | |
* @returns {function} | |
*/ | |
const compareExpression = | |
(op) => | |
/** | |
* Compare expression | |
* | |
* @param {string} aVal | |
* @param {string} bVal | |
* @returns {Boolean} | |
*/ | |
(aVal = '', bVal = '') => { | |
switch (op) { | |
case FILTER_ACTIONS.CONTAIN: | |
return String(aVal).includes(String(bVal)) | |
case FILTER_ACTIONS.NOT_CONTAIN: | |
return !String(aVal).includes(String(bVal)) | |
case FILTER_ACTIONS.EMPTY: | |
return _isEmpty(String(aVal)) | |
case FILTER_ACTIONS.NOT_EMPTY: | |
return !_isEmpty(String(aVal)) | |
default: | |
return false | |
} | |
} | |
/** | |
* Filters expressions comparator | |
* | |
* @param {Object} data | |
* @param {Array} expr | |
* @returns {Boolean} | |
*/ | |
const compareExpressions = (data = {}, expr = []) => { | |
return expr.reduce((acc, x) => { | |
const [fCond, fOp, aKey, bKey] = x | |
const toCompare = compareExpression(fOp) | |
const compared = toCompare(toValue(data, aKey), toValue(data, bKey)) | |
if (fCond === FILTER_CONDITION.AND) { | |
return acc && compared | |
} | |
return acc || compared | |
}, true) | |
} | |
const isConditionTrue = (data = {}, cond = {}) => | |
compareExpressions(data, cond.expr) | |
/** | |
* Extract condition keys filter is [FILTER_CONDITION.AND, FILTER_ACTIONS.NOT_EMPTY, 'tags'] | |
* | |
* @param {Object} cond | |
* @returns {Array} of keys | |
* | |
*/ | |
const getCondKeys = ({ expr = [] }) => _map(Array.from(expr), (x) => x[2]) | |
/** | |
* Handles a piece of data | |
* | |
* @param {Array} arrContext of collection of objects | |
* @param {Object} match a filter object | |
*/ | |
const handle = (arrContext = [], cond = {}) => { | |
let _arrContext = [] | |
switch (cond.type) { | |
case FILTER_TYPE.ROWS: { | |
_arrContext = _filter(arrContext, (x) => isConditionTrue(x, cond)) | |
break | |
} | |
case FILTER_TYPE.COLUMNS: { | |
// Expiremental | |
_arrContext = _map(arrContext, (x) => { | |
return isConditionTrue(x, cond) ? _omit(x, getCondKeys(cond)) : x | |
}) | |
break | |
} | |
// TODO: TBD | |
case FILTER_TYPE.GROUP: | |
default: { | |
_arrContext = [...arrContext] | |
break | |
} | |
} | |
return _arrContext | |
} | |
/** | |
* Filter content arrays | |
* | |
* @param {Object} action action object | |
* @param {Array} conditions of filters collection of objects | |
* @param {Array} arrContext of collection of objects | |
* @returns {Array} collection of filtrated objects by filters | |
*/ | |
const applyFilters = (action = {}, conditions = [], arrContext = []) => { | |
const _conditions = _filter(conditions, (x) => x.id === action.id) | |
if (_size(_conditions)) { | |
return _conditions.reduce(handle, arrContext) | |
} | |
return arrContext | |
} | |
module.exports = { applyFilters } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
N I B A G A N A