From 2979cb892dda427192dea8f0b452db0038b63cef Mon Sep 17 00:00:00 2001 From: Rameez Shuhaib Date: Thu, 10 Mar 2022 15:49:48 +0530 Subject: [PATCH 1/6] added wasm and exported extract_table_names --- Cargo.lock | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 5 ++++ src/lib.rs | 27 ++++++++++++++++---- 3 files changed, 100 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 754579f..e6abeb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,6 +25,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + [[package]] name = "cfg-if" version = "1.0.0" @@ -114,6 +120,15 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +[[package]] +name = "js-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -201,8 +216,10 @@ name = "sqlcli" version = "0.1.0" dependencies = [ "clap", + "js-sys", "simple_logger", "sqlparser", + "wasm-bindgen", ] [[package]] @@ -222,9 +239,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.60" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" dependencies = [ "proc-macro2", "quote", @@ -296,6 +313,60 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +[[package]] +name = "wasm-bindgen" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index a37fbec..1703211 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,12 @@ edition = "2018" [toolchain] channel = "nightly" +[lib] +crate-type = ["cdylib"] + [dependencies] sqlparser = "0.13.0" simple_logger = "1.16.0" clap = "3.0.0-beta.2" +wasm-bindgen = "0.2.17" +js-sys = "0.3.56" diff --git a/src/lib.rs b/src/lib.rs index 8460b54..cf98f9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(box_syntax, box_patterns)] +// #![feature(box_syntax, box_patterns)] #![allow(clippy::clippy::needless_return)] extern crate sqlparser; @@ -8,6 +8,7 @@ use sqlparser::ast::*; use sqlparser::dialect::GenericDialect; use sqlparser::parser::Parser; use std::collections::HashSet; +use wasm_bindgen::prelude::*; pub fn parse_select_statement(sql: String) -> Result { let dialect = GenericDialect {}; @@ -128,12 +129,12 @@ fn table_names_from_set_expr(body: SetExpr) -> Vec { } SetExpr::SetOperation { - box left, - box right, + left, + right, .. } => { - let mut table_names = table_names_from_set_expr(left); - let l2 = table_names_from_set_expr(right); + let mut table_names = table_names_from_set_expr(*left); + let l2 = table_names_from_set_expr(*right); table_names.extend(l2); return table_names; } @@ -558,6 +559,22 @@ fn projection_name_from_expr(e: Expr) -> String { } } +#[wasm_bindgen] +extern { pub fn alert(s: &str); } + +#[wasm_bindgen] +pub fn extract_table_names(sql: String) -> JsValue { + let mut result = vec![]; + match get_table_names(sql) { + Ok(table_names) => result = table_names, + Err(e) => alert(format!("Error in Query: {:?}", e).as_str()) + } + JsValue::from(result.into_iter() + .map(|x| JsValue::from_str(x.as_str())) + .collect::()) +} + + #[cfg(test)] mod projection_tests { From 4ab019d371fba8a2d05023df4b2ceaa82a633cc8 Mon Sep 17 00:00:00 2001 From: Ankit Solanki Date: Thu, 24 Mar 2022 12:08:45 +0530 Subject: [PATCH 2/6] WASM version: signify success / failure with return value Return value = string: parsing failed, this is the error message Return value = array: parsing succeeded, these are table names --- src/lib.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cf98f9f..04f5eae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -456,8 +456,8 @@ mod table_name_tests { #[test] fn case_with_sub_query() { assert( - "select - abc, + "select + abc, (case when user_id > 0 then (select max(active_time) from users where id = user_id) else NULL end) last_active_time from events", vec!["events", "users"]); @@ -466,7 +466,7 @@ vec!["events", "users"]); #[test] fn window_function() { assert( - "select emp_name, dealer_id, sales, avg(sales) over (partition by dealer_id) as avgsales from q1_sales;", + "select emp_name, dealer_id, sales, avg(sales) over (partition by dealer_id) as avgsales from q1_sales;", vec!["q1_sales"]); } } @@ -559,22 +559,17 @@ fn projection_name_from_expr(e: Expr) -> String { } } -#[wasm_bindgen] -extern { pub fn alert(s: &str); } - #[wasm_bindgen] pub fn extract_table_names(sql: String) -> JsValue { - let mut result = vec![]; match get_table_names(sql) { - Ok(table_names) => result = table_names, - Err(e) => alert(format!("Error in Query: {:?}", e).as_str()) + Ok(table_names) => + JsValue::from(table_names.into_iter() + .map(|x| JsValue::from_str(x.as_str())) + .collect::()), + Err(e) => JsValue::from_str(format!("Error in Query: {:?}", e).as_str()) } - JsValue::from(result.into_iter() - .map(|x| JsValue::from_str(x.as_str())) - .collect::()) } - #[cfg(test)] mod projection_tests { From 92e050ea3dfafaa4c7c94371745f7489d4f2a66a Mon Sep 17 00:00:00 2001 From: Ankit Solanki Date: Thu, 24 Mar 2022 12:10:58 +0530 Subject: [PATCH 3/6] README describes how to build the wasm version --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index b528591..2c2001b 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,13 @@ WILDCARD: b.* ## Build & test +Building for WASM: + +``` +# Install wasm-pack first (eg: `brew install wasm-pack`) +$ wasm-pack build --target nodejs +``` + Install [rust](https://www.rust-lang.org/), and run: ``` From 2393ad603b36b32bdb84386505cf4738f7f1e077 Mon Sep 17 00:00:00 2001 From: Ankit Solanki Date: Thu, 24 Mar 2022 16:53:11 +0530 Subject: [PATCH 4/6] Compiling library as both rlib and cdylib -- allows us to create binary as well as wasm versions --- Cargo.toml | 2 +- src/lib.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1703211..b94dbfc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" channel = "nightly" [lib] -crate-type = ["cdylib"] +crate-type = ["cdylib", "rlib"] [dependencies] sqlparser = "0.13.0" diff --git a/src/lib.rs b/src/lib.rs index 04f5eae..cf23b27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,4 @@ -// #![feature(box_syntax, box_patterns)] -#![allow(clippy::clippy::needless_return)] +#![allow(clippy::needless_return)] extern crate sqlparser; From 2229f8c4aadb858fc3aee959f71fec60cbcdb243 Mon Sep 17 00:00:00 2001 From: Ankit Solanki Date: Thu, 24 Mar 2022 16:54:01 +0530 Subject: [PATCH 5/6] Removing some clippy warnings, removing 'nightly' from cargo.toml --- Cargo.toml | 3 --- src/lib.rs | 2 +- src/main.rs | 8 ++++---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b94dbfc..e2bcdc9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,6 @@ homepage = "https://github.com/ClearTax/sqlcli" license = "MIT" edition = "2018" -[toolchain] -channel = "nightly" - [lib] crate-type = ["cdylib", "rlib"] diff --git a/src/lib.rs b/src/lib.rs index cf23b27..5a40537 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ pub fn parse_select_statement(sql: String) -> Result { match results { Err(error) => { - return Err(format!("Parsing error: {}", error.to_string())); + return Err(format!("Parsing error: {}", error)); } Ok(mut ast) => { if ast.is_empty() { diff --git a/src/main.rs b/src/main.rs index 0261d31..1853996 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -#![allow(clippy::clippy::needless_return)] +#![allow(clippy::needless_return)] use clap::App; use clap::AppSettings; @@ -81,7 +81,7 @@ fn main() { SimpleLogger::new().with_utc_timestamps().init().unwrap(); } - if let Some(ref matches) = matches.subcommand_matches("ast") { + if let Some(matches) = matches.subcommand_matches("ast") { let input = matches.value_of("").unwrap(); let sql = read_file_or_stdin(input.to_string()); match parse_select_statement(sql) { @@ -95,7 +95,7 @@ fn main() { } } - if let Some(ref matches) = matches.subcommand_matches("tables") { + if let Some(matches) = matches.subcommand_matches("tables") { let input = matches.value_of("").unwrap(); let sql = read_file_or_stdin(input.to_string()); let result = get_table_names(sql); @@ -113,7 +113,7 @@ fn main() { } } - if let Some(ref matches) = matches.subcommand_matches("columns") { + if let Some(matches) = matches.subcommand_matches("columns") { let input = matches.value_of("").unwrap(); let sql = read_file_or_stdin(input.to_string()); let result = get_projection_names(sql); From 290ec839b3168f050eec2d481c8ac0836d39c084 Mon Sep 17 00:00:00 2001 From: Ankit Solanki Date: Tue, 29 Mar 2022 11:00:36 +0530 Subject: [PATCH 6/6] Adding WASM section to README --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2c2001b..9dd7b7f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # sqlcli -`sqlcli` is a CLI tool written to parse SQL statements and answer questions about them. +`sqlcli` is a CLI (and [WASM](#wasm)) tool written to parse SQL statements and answer questions about them. Currently, it only really does two things: @@ -11,7 +11,7 @@ Currently, it only really does two things: It's written in rust. Probably not very idiomatic rust, since it was written in a hurry. Feedback welcome! -## Usage +## Command Line Usage Display help: @@ -145,7 +145,9 @@ WILDCARD: b.* ``` -## Build & test + + +## WASM Building for WASM: @@ -154,6 +156,8 @@ Building for WASM: $ wasm-pack build --target nodejs ``` +## Build and Test + Install [rust](https://www.rust-lang.org/), and run: ```