mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-05 00:03:08 +00:00
feat: mysql named params (#2805)
This commit is contained in:
@@ -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;
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
|
||||
Generated
+4
-4
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user