diff options
author | William Carroll <wpcarro@gmail.com> | 2023-01-13T00·38-0800 |
---|---|---|
committer | wpcarro <wpcarro@gmail.com> | 2023-01-17T21·13+0000 |
commit | a9d866c7759bc6ac0ffde5e048c15ca846ca05f4 (patch) | |
tree | 3ca4b61c50c0d8acff08939425debf47a3bf3995 /users/wpcarro/scratch | |
parent | 0d4f3433deffd127075209480427f43b4c5c4e6a (diff) |
feat(wpcarro/slx): Match against all columns r/5681
With `MATCH_ALL` type. Change-Id: I2fe537c2b277a86be5c04a27da088f31fe7eb09e Reviewed-on: https://cl.tvl.fyi/c/depot/+/7817 Tested-by: BuildkiteCI Reviewed-by: wpcarro <wpcarro@gmail.com>
Diffstat (limited to 'users/wpcarro/scratch')
-rw-r--r-- | users/wpcarro/scratch/simple-select/index.js | 61 |
1 files changed, 55 insertions, 6 deletions
diff --git a/users/wpcarro/scratch/simple-select/index.js b/users/wpcarro/scratch/simple-select/index.js index 85d057e117bc..4be5b5e265fe 100644 --- a/users/wpcarro/scratch/simple-select/index.js +++ b/users/wpcarro/scratch/simple-select/index.js @@ -1,6 +1,3 @@ -// const input = '-director:"Von \\"Fluke\\" Neumann" foo:/this is a test/ (director:"Tarantino" OR director:"Scorsese")'; -const input = 'director:"Tarantino" OR director:"Scorsese"'; - const state = { // Match values case sensitively when filtering. caseSensitive: false, @@ -8,8 +5,8 @@ const state = { preferRegex: false, }; -// TODO(wpcarro): Support global queries like "Tarantino" that try to match against all columns in a row. // TODO(wpcarro): Support filtering by date (before, after). +// TODO(wpcarro): Support grouping with parentheses. function select(query, xs) { const predicate = compile(parse(query)); @@ -38,6 +35,24 @@ function compile(ast) { return ast.negate ? f(row[ast.key]) : f(row[ast.key]); }; } + if (ast.type === 'MATCH_ALL') { + if (ast.matchType === 'STRING') { + return function(row) { + return Object.values(row).some(x => { + if (state.caseSensitive) { + return x === ast.val; + } else { + return x.toLowerCase() === ast.val.toLowerCase(); + } + }) + }; + } + if (ast.matchType === 'REGEX') { + return function(row) { + return Object.values(row).some(x => ast.val.test(x)); + }; + } + } if (ast.type === 'STRING') { return function(x) { if (state.caseSensitive) { @@ -225,9 +240,18 @@ function conjunction(p) { }; } +function peekType(n, p) { + if (p.i + n < p.tokens.length) { + return p.tokens[p.i + n][0]; + } + return null; +} + function selection(p) { // column:value OR -column:value - if (matches((type, _) => type === 'ATOM' || type === 'NEGATE', p)) { + + if ((peekType(0, p) === 'ATOM' && peekType(1, p) === 'COLON') || + (peekType(0, p) === 'NEGATE' && peekType(1, p) === 'ATOM' && peekType(2, p) === 'COLON')) { let negate = false; if (p.tokens[p.i][0] === 'NEGATE') { negate = true; @@ -243,8 +267,33 @@ function selection(p) { val, }; } else { - return value(p); + return matchAll(p); + } +} + +function matchAll(p) { + const [type, val] = p.tokens[p.i]; + + // Cast atoms into strings or regexes depending on the current state. + if (type === 'ATOM') { + p.i += 1; + if (state.preferRegex) { + const regex = state.caseSensitive ? new RegExp(val) : new RegExp(val, "i"); + return { type: 'MATCH_ALL', matchType: 'REGEX', val: regex }; + } else { + return { type: 'MATCH_ALL', matchType: 'STRING', val } + } } + if (type === 'STRING') { + p.i += 1; + return { type: 'MATCH_ALL', matchType: 'STRING', val }; + } + if (type === 'REGEX') { + p.i += 1; + const regex = state.caseSensitive ? new RegExp(val) : new RegExp(val, "i"); + return { type: 'MATCH_ALL', matchType: 'REGEX', val: regex }; + } + throw `Parse Error: Expected a regular expression or a string, but got: ${p.tokens[p.i]}; ${JSON.stringify(p)}`; } function value(p) { |