feat: mysql named params (#2805)

This commit is contained in:
HugoCasa
2023-12-07 18:55:14 +01:00
committed by GitHub
parent c37d73d1df
commit 6e138528dd
8 changed files with 85 additions and 35 deletions
+36 -6
View File
@@ -61,24 +61,27 @@ lazy_static::lazy_static! {
static ref RE_CODE_PGSQL: Regex = Regex::new(r#"(?m)\$(\d+)(?:::(\w+(?:\[\])?))?"#).unwrap();
// -- $1 name (type) = default
static ref RE_ARG_MYSQL: Regex = Regex::new(r#"(?m)^-- \? (\w+) \((\w+)\)(?: ?\= ?(.+))? *[\r\n$]"#).unwrap();
static ref RE_ARG_MYSQL: Regex = Regex::new(r#"(?m)^-- \? (\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
pub static ref RE_ARG_MYSQL_NAMED: Regex = Regex::new(r#"(?m)^-- :([a-z_][a-z0-9_]*) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
static ref RE_ARG_PGSQL: Regex = Regex::new(r#"(?m)^-- \$(\d+) (\w+)(?: ?\= ?(.+))? *[\r\n$]"#).unwrap();
static ref RE_ARG_PGSQL: Regex = Regex::new(r#"(?m)^-- \$(\d+) (\w+)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
// -- @name (type) = default
static ref RE_ARG_BIGQUERY: Regex = Regex::new(r#"(?m)^-- @(\w+) \((\w+(?:\[\])?)\)(?: ?\= ?(.+))? *[\r\n$]"#).unwrap();
static ref RE_ARG_BIGQUERY: Regex = Regex::new(r#"(?m)^-- @(\w+) \((\w+(?:\[\])?)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
static ref RE_ARG_SNOWFLAKE: Regex = Regex::new(r#"(?m)^-- \? (\w+) \((\w+)\)(?: ?\= ?(.+))? *[\r\n$]"#).unwrap();
static ref RE_ARG_SNOWFLAKE: Regex = Regex::new(r#"(?m)^-- \? (\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
static ref RE_ARG_MSSQL: Regex = Regex::new(r#"(?m)^-- @(?:P|p)\d+ (\w+) \((\w+)\)(?: ?\= ?(.+))? *[\r\n$]"#).unwrap();
static ref RE_ARG_MSSQL: Regex = Regex::new(r#"(?m)^-- @(?:P|p)\d+ (\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
}
fn parse_mysql_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
let mut args: Vec<Arg> = vec![];
for cap in RE_ARG_MYSQL.captures_iter(code) {
let mut using_named_args = false;
for cap in RE_ARG_MYSQL_NAMED.captures_iter(code) {
using_named_args = true;
let name = cap.get(1).map(|x| x.as_str().to_string()).unwrap();
let typ = cap
.get(2)
@@ -102,6 +105,33 @@ fn parse_mysql_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
});
}
if !using_named_args {
// backwards compatibility
for cap in RE_ARG_MYSQL.captures_iter(code) {
let name = cap.get(1).map(|x| x.as_str().to_string()).unwrap();
let typ = cap
.get(2)
.map(|x| x.as_str().to_string().to_lowercase())
.unwrap();
let default = cap.get(3).map(|x| x.as_str().to_string());
let has_default = default.is_some();
let parsed_typ = parse_mysql_typ(typ.as_str());
let parsed_default = default.and_then(|x| match parsed_typ {
Typ::Int => x.parse::<i64>().ok().map(|x| json!(x)),
Typ::Float => x.parse::<f64>().ok().map(|x| json!(x)),
_ => Some(json!(x)),
});
args.push(Arg {
name,
typ: parsed_typ,
default: parsed_default,
otyp: Some(typ),
has_default,
});
}
}
Ok(Some(args))
}
@@ -3,7 +3,7 @@
"collaborators": [
"Ruben Fiszel <ruben@windmill.dev>"
],
"version": "1.219.1",
"version": "1.221.0",
"files": [
"windmill_parser_wasm_bg.wasm",
"windmill_parser_wasm.js",
@@ -97,15 +97,6 @@ function getInt32Memory0() {
return cachedInt32Memory0;
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
@@ -115,6 +106,15 @@ function getStringFromWasm0(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
let cachedFloat64Memory0 = null;
function getFloat64Memory0() {
@@ -515,6 +515,10 @@ async function __wbg_load(module, imports) {
function __wbg_get_imports() {
const imports = {};
imports.wbg = {};
imports.wbg.__wbg_eval_815c246ab40cdfe4 = function(arg0, arg1) {
const ret = eval(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
takeObject(arg0);
};
@@ -526,8 +530,8 @@ function __wbg_get_imports() {
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
imports.wbg.__wbg_eval_a7fb8f2e206bad71 = function(arg0, arg1) {
const ret = eval(getStringFromWasm0(arg0, arg1));
imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_boolean_get = function(arg0) {
@@ -551,10 +555,6 @@ function __wbg_get_imports() {
const ret = BigInt.asUintN(64, arg0);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_number_get = function(arg0, arg1) {
const obj = getObject(arg1);
const ret = typeof(obj) === 'number' ? obj : undefined;
+25 -5
View File
@@ -1,3 +1,5 @@
use std::collections::HashMap;
use base64::Engine;
use mysql_async::{
consts::ColumnType, prelude::*, FromValueError, OptsBuilder, Params, Row, SslOpts,
@@ -9,7 +11,7 @@ use windmill_common::{
error::{to_anyhow, Error},
jobs::QueuedJob,
};
use windmill_parser_sql::parse_mysql_sig;
use windmill_parser_sql::{parse_mysql_sig, RE_ARG_MYSQL_NAMED};
use crate::{common::build_args_map, AuthedClientBackgroundTask};
@@ -63,14 +65,19 @@ pub async fn do_mysql(
let pool = mysql_async::Pool::new(opts);
let mut conn = pool.get_conn().await.map_err(to_anyhow)?;
let mut statement_values: Vec<mysql_async::Value> = vec![];
let sig = parse_mysql_sig(&query)
.map_err(|x| Error::ExecutionErr(x.to_string()))?
.args;
let using_named_params = RE_ARG_MYSQL_NAMED.captures_iter(&query).count() > 0;
let mut statement_values: Params = match using_named_params {
true => Params::Named(HashMap::new()),
false => Params::Positional(vec![]),
};
for arg in &sig {
let arg_t = arg.otyp.clone().unwrap_or_else(|| "text".to_string());
let arg_n = arg.clone().name;
let mysql_v = match job
.args
.as_ref()
@@ -103,10 +110,23 @@ pub async fn do_mysql(
)))
}
};
statement_values.push(mysql_v);
match &mut statement_values {
Params::Positional(v) => v.push(mysql_v),
Params::Named(m) => {
m.insert(arg_n.into_bytes(), mysql_v);
}
_ => {}
}
}
let rows: Vec<Row> = conn
.exec(query, Params::Positional(statement_values))
.exec(
query,
match statement_values {
Params::Positional(v) => Params::Positional(v),
Params::Named(m) => Params::Named(m),
_ => Params::Empty,
},
)
.await
.map_err(to_anyhow)?;
let rows = rows
+4 -4
View File
@@ -48,7 +48,7 @@
"vscode-languageclient": "~9.0.1",
"vscode-uri": "~3.0.8",
"vscode-ws-jsonrpc": "~3.1.0",
"windmill-parser-wasm": "^1.219.1",
"windmill-parser-wasm": "^1.221.0",
"y-monaco": "^0.1.4",
"y-websocket": "^1.5.0",
"yaml": "^2.3.4",
@@ -9585,9 +9585,9 @@
}
},
"node_modules/windmill-parser-wasm": {
"version": "1.219.1",
"resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.219.1.tgz",
"integrity": "sha512-nmiS1F5Lfjb3SIescYIH3Zd333wZzekeZxjMgH3barj6LJn/sqpEFcJn9J1kptrIycth9ec5urQj5J1lMJfuvg=="
"version": "1.221.0",
"resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.221.0.tgz",
"integrity": "sha512-HxrwI+ihtw6XhWqGH8p3nsMIHswNsVoy1wp+ZlViYDxXJVApHQjKTINZo1w4x169zjtm62M1GmJivz5AYpAnrg=="
},
"node_modules/wordwrap": {
"version": "1.0.0",
+1 -1
View File
@@ -131,7 +131,7 @@
"vscode-languageclient": "~9.0.1",
"vscode-uri": "~3.0.8",
"vscode-ws-jsonrpc": "~3.1.0",
"windmill-parser-wasm": "^1.219.1",
"windmill-parser-wasm": "^1.221.0",
"y-monaco": "^0.1.4",
"y-websocket": "^1.5.0",
"yaml": "^2.3.4",
+3 -3
View File
@@ -143,9 +143,9 @@ export const POSTGRES_INIT_CODE = `-- $1 name1 = default arg
INSERT INTO demo VALUES (\$1::TEXT, \$2::INT, \$3::TEXT[]) RETURNING *
`
export const MYSQL_INIT_CODE = `-- ? name1 (text) = default arg
-- ? name2 (int)
INSERT INTO demo VALUES (?, ?)
export const MYSQL_INIT_CODE = `-- :name1 (text) = default arg
-- :name2 (int)
INSERT INTO demo VALUES (:name1, :name2)
`
export const BIGQUERY_INIT_CODE = `-- @name1 (string) = default arg