commit 1c5b38b23013b13d209a69c5564bd80af49b9f80
parent 66b2e6d65a04578b312e10ed1f124c78d4c6dcd2
Author: paulcanning <pcanning@gmail.com>
Date: Tue, 31 May 2022 14:35:49 +0100
Add number comparison filtering.
Diffstat:
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');
+});