From 534ac4b75d5dd5220d233a767a8858acd01e0ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A1n=20D=C3=A9nes?= Date: Sun, 26 Dec 2021 14:06:30 +0100 Subject: [PATCH] Filter implementation started --- src/filter.js | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/filter.js diff --git a/src/filter.js b/src/filter.js new file mode 100644 index 0000000..ff7a33e --- /dev/null +++ b/src/filter.js @@ -0,0 +1,86 @@ +const u = require('./utils') +const a = require('./assert') +const anchor = require('./anchor').parse + +const _true = () => true +const _and = arr => p => arr.map(e => e(p)).reduce((a, b) => a && b) +const _or = arr => p => arr.map(e => e(p)).reduce((a, b) => a || b) + +const similar = (a, b, name, units) => { + let neg = false + + if (b.startsWith('-')) { + neg = true + b = b.slice(1) + } + + if (b.startsWith('/')) { + //... + } +} + +const comparators = { + '~': similar + // TODO: extension point for other operators... +} +const symbols = Object.keys(comparators) + +const simple = (exp, name, units) => { + + let a = ['meta.name', 'meta.tags'] + let op = '~' + let b + const parts = exp.split(/\s+/g) + + // full case + if (symbols.includes(parts[1])) { + a = parts[0].split(',') + op = parts[1] + b = parts.slice(2).join(' ') + + // middle case, just an operator spec, default "a" + } else if (symbols.includes(parts[0])) { + op = parts[0] + b = parts.slice(1).join(' ') + + // basic case, only "b" + } else { + b = exp + } + + return comparators[op](a, b, name, units) +} + +const complex = (config, name, units, aggregator=_and) => { + + // default is all points + if (config === undefined) { + return _true + } + + // otherwise we branch by type + const type = a.type(config)() + switch(type) { + + // base case is a string, meaning a simple/single filter + case 'string': + return simple(config, name, units) + + // arrays are aggregated with alternating and/or conditions + case 'array': + const alternate = aggregator == _and ? _or : _and + return aggregator(config.map(elem => complex(elem, name, units, alternate))) + + default: + throw new Error(`Unexpected type "${type}" found at filter "${name}"!`) + } +} + +exports.parse = (config, name, points={}, units={}) => { + + if (a.type(config)() == 'object') { + return [anchor(config, name, points)(units)] + } + + return Object.values(points).filter(complex(config, name, units)) +} \ No newline at end of file