@mcabreradev/filter
Version:
A powerful, SQL-like array filtering library for TypeScript and JavaScript with advanced pattern matching, MongoDB-style operators, deep object comparison, and zero dependencies
76 lines (75 loc) • 3.17 kB
JavaScript
import { OPERATORS } from '../../constants';
import { hasWildcard, createWildcardRegex, hasNegation, removeNegation, isString, isObject, isOperatorExpression, } from '../../utils';
import { processOperators } from '../../operators';
import { applyLogicalOperators } from '../../operators/logical/logical.operators';
const isLogicalOperator = (key) => {
return key === OPERATORS.AND || key === OPERATORS.OR || key === OPERATORS.NOT;
};
export function createObjectPredicate(expression, config) {
return function (item) {
for (const key in expression) {
if (isLogicalOperator(key)) {
const logicalExpr = expression;
const operatorValue = logicalExpr[key];
if (operatorValue !== undefined &&
!applyLogicalOperators(item, key, operatorValue, config)) {
return false;
}
continue;
}
let expr = expression[key];
const itemValue = item[key];
if (isObject(expr) && isOperatorExpression(expr)) {
if (!processOperators(itemValue, expr, config, item)) {
return false;
}
continue;
}
if (isObject(expr) && !isOperatorExpression(expr) && isObject(itemValue)) {
const nestedPredicate = createObjectPredicate(expr, config);
if (!nestedPredicate(itemValue)) {
return false;
}
continue;
}
let shouldNegate = false;
if (isString(expr) && hasNegation(expr)) {
expr = removeNegation(expr);
shouldNegate = true;
}
if (Array.isArray(expr)) {
const matchesAny = expr.some((value) => {
if (isString(value) && hasWildcard(value)) {
const regex = createWildcardRegex(value, config.caseSensitive);
return typeof itemValue === 'string' && regex.test(itemValue);
}
return itemValue === value;
});
if (shouldNegate ? matchesAny : !matchesAny) {
return false;
}
continue;
}
if (isString(expr) && hasWildcard(expr)) {
const regex = createWildcardRegex(expr, config.caseSensitive);
const matches = typeof itemValue === 'string' && regex.test(itemValue);
if (shouldNegate ? matches : !matches) {
return false;
}
}
else {
let matches;
if (!config.caseSensitive && typeof itemValue === 'string' && typeof expr === 'string') {
matches = itemValue.toLowerCase() === expr.toLowerCase();
}
else {
matches = itemValue === expr;
}
if (shouldNegate ? matches : !matches) {
return false;
}
}
}
return true;
};
}