lucene-filter.js

Data filter for lucene queries
git clone git://git.finwo.net/lib/lucene-filter.js
Log | Files | Refs | README | LICENSE

commit 1c5b38b23013b13d209a69c5564bd80af49b9f80
parent 66b2e6d65a04578b312e10ed1f124c78d4c6dcd2
Author: paulcanning <pcanning@gmail.com>
Date:   Tue, 31 May 2022 14:35:49 +0100

Add number comparison filtering.

Diffstat:
Asrc/filters/number/comparison.js | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/filters/number/comparison.test.js | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 108 insertions(+), 0 deletions(-)

diff --git a/src/filters/number/comparison.js b/src/filters/number/comparison.js @@ -0,0 +1,48 @@ +const field = require('../../field'); + +module.exports = { + detect : function (query) { + if (!query) { + return false; + } + if ('object' !== typeof query) { + return false; + } + if (!query.term) { + return false; + } + return Array.isArray(query.term.match(/^[<=>]+/)); + }, + compile: function (query) { + query.similarity = query.similarity || 0; + return function (data) { + return field(query.field, data, function (value) { + let sign, num; + value = parseFloat(value); + if (sign = query.term.match(/^[<=>]+/)) { + [sign] = sign; + } + num = query.term.match(/[0-9.]+/); + if (!num) { + return false; + } + num = Number(num[0]); + if (sign) { + if (sign === '>') { + return value > num; + } else if (sign === '>=') { + return value >= num; + } else if (sign === '<') { + return value < num; + } else if (sign === '<=') { + return value <= num; + } else { + throw new Error(`Invalid sign: ${sign}`); + } + } else { + return value === num; + } + }); + }; + }, +}; diff --git a/src/filters/number/comparison.test.js b/src/filters/number/comparison.test.js @@ -0,0 +1,60 @@ +const tape = require('tape'); +const comparison = require('./comparison'); + +tape('filter.number.comparison -- structure', async t => { + t.plan(2); + t.ok('detect' in comparison, 'comparison filter has detect method'); + t.ok('compile' in comparison, 'comparison filter has compile method'); +}); + +tape('filter.number.comparison -- detect', async t => { + t.plan(9); + t.notOk(comparison.detect(false), 'contains.detect doesn\'t trigger on false query'); + t.notOk(comparison.detect(null), 'contains.detect doesn\'t trigger on null query'); + t.notOk(comparison.detect(true), 'contains.detect doesn\'t trigger on true query'); + t.notOk(comparison.detect([]), 'contains.detect doesn\'t trigger on empty array query'); + t.notOk(comparison.detect({}), 'contains.detect doesn\'t trigger on empty object query'); + t.notOk(comparison.detect({ field: 'something' }), 'contains.detect doesn\'t trigger on termless query'); + t.notOk(comparison.detect({ term: 'something' }), 'contains.detect doesn\'t trigger on fieldless query'); + t.ok(comparison.detect({ field: 'hello', term: '>1' }), 'contains.detect triggers on properly structured query'); + t.notOk(comparison.detect({ field: 'hello', term: '1' }), 'contains.detect doesn\'t trigger on query with no comparator'); +}); + +tape('filter.number.comparison, gt -- compile', async t => { + t.plan(3); + + const extractor = comparison.compile({ field: 'age', term: '>21' }); + t.equal(typeof extractor, 'function', 'comparison.compile returns a function'); + + t.ok(extractor({ age: 22 }), 'finds term in comparison'); + t.notOk(extractor({ age: 21 }), 'doesn\'t find term in comparison'); +}); +tape('filter.number.comparison, gte -- compile', async t => { + t.plan(4); + + const extractor = comparison.compile({ field: 'age', term: '>=21' }); + t.equal(typeof extractor, 'function', 'comparison.compile returns a function'); + + t.ok(extractor({ age: 22 }), 'finds term in comparison'); + t.ok(extractor({ age: 21 }), 'finds term in comparison'); + t.notOk(extractor({ age: 20 }), 'doesn\'t find term in comparison'); +}); +tape('filter.number.comparison, lt -- compile', async t => { + t.plan(3); + + const extractor = comparison.compile({ field: 'age', term: '<21' }); + t.equal(typeof extractor, 'function', 'comparison.compile returns a function'); + + t.ok(extractor({ age: 20 }), 'finds term in comparison'); + t.notOk(extractor({ age: 21 }), 'doesn\'t find term in comparison'); +}); +tape('filter.number.comparison, lte -- compile', async t => { + t.plan(4); + + const extractor = comparison.compile({ field: 'age', term: '<=21' }); + t.equal(typeof extractor, 'function', 'comparison.compile returns a function'); + + t.ok(extractor({ age: 20 }), 'finds term in comparison'); + t.ok(extractor({ age: 21 }), 'finds term in comparison'); + t.notOk(extractor({ age: 22 }), 'doesn\'t find term in comparison'); +});