Skip to content

Instantly share code, notes, and snippets.

@qfox
Last active December 25, 2017 19:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save qfox/c2ee796969629df53505041f4c58f2b0 to your computer and use it in GitHub Desktop.
Save qfox/c2ee796969629df53505041f4c58f2b0 to your computer and use it in GitHub Desktop.
'use strict';
const filtr = require('filterable');
module.exports = toJSFunction;
function toJSFunction(conditions) {
const keys = [];
const includes = ($v, v) => typeof v === 'string' ?
$v.toLowerCase().indexOf(v.toLowerCase()) !== -1 :
v.some((_v) => $v.toLowerCase() === _v.toLowerCase());
const groups = conditions.groups.reduce((res, originalGroup) => {
if (['in', 'nin'].indexOf(originalGroup.type) !== -1) {
let group = res.find((g) => g.type === originalGroup.type && g.field === originalGroup.field);
if (!group) {
group = Object.assign({}, originalGroup, { value: [] });
keys.push(originalGroup.field);
res.push(group);
}
group.value.push(originalGroup.value);
return res;
}
keys.push(originalGroup.field);
res.push(Object.assign({}, originalGroup));
return res;
}, []);
const fns = groups.map((g) => {
switch (g.type) {
case '=': return (v) => v === g.value;
case '!=': return (v) => v !== g.value;
case 'in': return (v) => v && g.value.some(($v) => includes($v, v));
case 'nin': return (v) => !v || g.value.every(($v) => !includes($v, v));
case '<': return (v) => v < g.value;
case '<=': return (v) => v <= g.value;
case '>': return (v) => v > g.value;
case '>=': return (v) => v >= g.value;
}
// throw 'I DONT KNOW';
return () => true;
});
// console.log(fns.map(f => f.toString()))
return (obj) => keys.every((k, i) => fns[i](obj[k]));
}
if (typeof describe === 'undefined') {
return;
}
function assert(t) {
if(!t) { throw new Error('Assertion error'); }
}
check('Query for tags',
['cat', {}], [{ tags: 'cat' }], [{ tags: 'dog' }, { tags: null }]);
check('Query for description',
['cat', { textField: 'description' }], [{ description: 'cat' }], [{ description: 'dog' }, { description: null }]);
check('Query for multiple tags',
['cat dog "Hello World"', {}],
[{ tags: ['Hello world'] }, { tags: ['cat'] }, { tags: ['dog'] }],
[{}/*, { tags: ['lolka'] }*/]);
check('Exclude results containing a certain word',
['cat NOT dog', {}], [{ tags: 'cat' }], [{ tags: 'cat dog' }, { tags: 'dog' }, { tags: '' }]);
check('Query for equality',
['name:"Samy Pesse"', {}], [{ name: 'Samy Pesse' }], [{ name: 'Pamy Sesse' }]);
check('Query for values greater than another value',
['stars:>10 stars:>=10', {}], [{ stars: 11 }, { stars: 100 }], [/*{ stars: 11 }, */{ stars: 0 }]);
check('Query for values less than another value',
['stars:<100 stars:<=100', {}], [{ stars: 99 }, { stars: 0 }], [{ stars: 1000 }/*, { stars: 100 }*/]);
check('Mix query for tags and condition',
['cat stars:>10 stars:<100', {}],
[{ tags: 'cat', stars: 11 }, { tags: 'cat', stars: 99 }],
[{ tags: 'cat', stars: 10 }, { stars: 100 }]);
check('Filter qualifiers based on exclusion',
['cats stars:>10 NOT language:javascript', {}],
[{ tags: 'cats', stars: 100, language: 'ruby' }],
[
{ tags: 'cats', stars: 100, language: 'javascript' },
{ tags: 'cats', stars: 0, language: 'ruby' },
{ tags: 'dogs', stars: 100, language: 'ruby' }
]);
function check(name, input, valid, invalid) {
describe(name + ': `' + input[0] + '`', () => {
let fn;
before(() => {
fn = toJSFunction(filtr.Query(input[0], input[1]).parse(), input[1]);
});
for (const f of valid) {
it('should match ' + JSON.stringify(f), () => {
assert(fn(f));
});
}
for (const f of invalid) {
it('should NOT match ' + JSON.stringify(f), () => {
assert(!fn(f));
});
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment