Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 62 additions & 49 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,67 +243,80 @@ export function applyLocalSearchCriteria(data, options) {

if (options.filter && options.filter.length > 0) {
options.filter.forEach(group => {
const orFilters = group.split(/\s*\|\|\s*/);
result = result.filter(item => {
return orFilters.some(f => {
const match = f.match(/^([\w\.]+)(?::([a-z!]+))?(?:(<=|>=|<|>|=|!=|!~|~|\?|!|@@)(.*))?$/);
if (!match) return false;
const orFiltersStrings = group.split(/\s*\|\|\s*/);
const parsedFilters = orFiltersStrings.map(f => {
const match = f.match(/^([\w\.]+)(?::([a-z!]+))?(?:(<=|>=|<|>|=|!=|!~|~|\?|!|@@)(.*))?$/);
if (!match) return null;

const field = match[1];
const opString = match[2];
const shorthand = match[3];
let value = match[4] || '';

let condition = 'eq';
if (opString) {
condition = opString === '!in' ? 'nin' : opString;
} else if (shorthand) {
switch (shorthand) {
case '>': condition = 'gt'; break;
case '<': condition = 'lt'; break;
case '>=': condition = 'gteq'; break;
case '<=': condition = 'lteq'; break;
case '!=': condition = 'neq'; break;
case '~': condition = 'like'; break;
case '!~': condition = 'nlike'; break;
case '@@': condition = 'finset'; break;
case '?': condition = 'null'; value = '1'; break;
case '!': condition = 'notnull'; value = '1'; break;
default: condition = 'eq';
}
}

const field = match[1];
const opString = match[2];
const shorthand = match[3];
let value = match[4] || '';
if ((condition === 'like' || condition === 'nlike') && value.includes('*')) {
value = value.replaceAll('*', '%');
}

let condition = 'eq';
if (opString) {
condition = opString === '!in' ? 'nin' : opString;
} else if (shorthand) {
switch (shorthand) {
case '>': condition = 'gt'; break;
case '<': condition = 'lt'; break;
case '>=': condition = 'gteq'; break;
case '<=': condition = 'lteq'; break;
case '!=': condition = 'neq'; break;
case '~': condition = 'like'; break;
case '!~': condition = 'nlike'; break;
case '@@': condition = 'finset'; break;
case '?': condition = 'null'; value = '1'; break;
case '!': condition = 'notnull'; value = '1'; break;
default: condition = 'eq';
}
}
const strVal = String(value).toLowerCase();
const numVal = Number(value);
const stringValue = String(value);

if ((condition === 'like' || condition === 'nlike') && value.includes('*')) {
value = value.replaceAll('*', '%');
}
let inValues = null;
if (condition === 'in' || condition === 'nin') {
inValues = stringValue.split(',').map(s => s.trim());
}

const itemValue = item[field];
const strItemVal = String(itemValue || '').toLowerCase();
const strVal = String(value).toLowerCase();
let regex = null;
if (condition === 'like' || condition === 'nlike') {
regex = new RegExp('^' + strVal.replace(/%/g, '.*') + '$', 'i');
}

return { field, condition, value, strVal, numVal, stringValue, inValues, regex };
}).filter(f => f !== null);

result = result.filter(item => {
return parsedFilters.some(f => {
const itemValue = item[f.field];
const numItemVal = Number(itemValue);
const numVal = Number(value);

switch (condition) {
case 'eq': return String(itemValue) === String(value);
case 'neq': return String(itemValue) !== String(value);
case 'gt': return numItemVal > numVal;
case 'gteq': return numItemVal >= numVal;
case 'lt': return numItemVal < numVal;
case 'lteq': return numItemVal <= numVal;

switch (f.condition) {
case 'eq': return String(itemValue) === f.stringValue;
case 'neq': return String(itemValue) !== f.stringValue;
case 'gt': return numItemVal > f.numVal;
case 'gteq': return numItemVal >= f.numVal;
case 'lt': return numItemVal < f.numVal;
case 'lteq': return numItemVal <= f.numVal;
case 'like':
const regexFromLike = new RegExp('^' + strVal.replace(/%/g, '.*') + '$', 'i');
return regexFromLike.test(strItemVal);
return f.regex.test(String(itemValue || '').toLowerCase());
case 'nlike':
const nregexFromLike = new RegExp('^' + strVal.replace(/%/g, '.*') + '$', 'i');
return !nregexFromLike.test(strItemVal);
return !f.regex.test(String(itemValue || '').toLowerCase());
case 'in':
return String(value).split(',').map(s => s.trim()).includes(String(itemValue));
return f.inValues.includes(String(itemValue));
case 'nin':
return !String(value).split(',').map(s => s.trim()).includes(String(itemValue));
return !f.inValues.includes(String(itemValue));
case 'null': return itemValue === null || itemValue === undefined;
case 'notnull': return itemValue !== null && itemValue !== undefined;
case 'finset':
return String(itemValue).split(',').map(s => s.trim()).includes(String(value));
return String(itemValue).split(',').map(s => s.trim()).includes(f.stringValue);
default: return false;
}
});
Expand Down
Loading