about summary refs log tree commit diff
path: root/users/wpcarro
diff options
context:
space:
mode:
authorWilliam Carroll <wpcarro@gmail.com>2023-01-13T00·38-0800
committerwpcarro <wpcarro@gmail.com>2023-01-17T21·13+0000
commita9d866c7759bc6ac0ffde5e048c15ca846ca05f4 (patch)
tree3ca4b61c50c0d8acff08939425debf47a3bf3995 /users/wpcarro
parent0d4f3433deffd127075209480427f43b4c5c4e6a (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')
-rw-r--r--users/wpcarro/scratch/simple-select/index.js61
-rw-r--r--users/wpcarro/ynabsql/dataviz/index.js4
2 files changed, 57 insertions, 8 deletions
diff --git a/users/wpcarro/scratch/simple-select/index.js b/users/wpcarro/scratch/simple-select/index.js
index 85d057e117..4be5b5e265 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) {
diff --git a/users/wpcarro/ynabsql/dataviz/index.js b/users/wpcarro/ynabsql/dataviz/index.js
index cc58591d7f..4a6aaa5d1b 100644
--- a/users/wpcarro/ynabsql/dataviz/index.js
+++ b/users/wpcarro/ynabsql/dataviz/index.js
@@ -59,10 +59,10 @@ new Chart(mount, {
     plugins: {
       tooltip: {
         callbacks: {
-          title: function (x) {
+          title: function(x) {
             return `$${x[0].raw.y}`;
           },
-          label: function (x) {
+          label: function(x) {
             return JSON.stringify(x.raw.metadata);
           },
         },