Skip to main content

v_common/search/
sql_params.rs

1use v_individual_model::onto::individual::Individual;
2use v_individual_model::onto::resource::Value;
3use crate::search::sql_lex_tree::tr_statement;
4use klickhouse::query_parser::parse_query_arguments;
5use regex::Regex;
6use sqlparser::dialect::AnsiDialect;
7use sqlparser::dialect::MySqlDialect;
8use sqlparser::parser::Parser;
9use std::io::{Error, ErrorKind};
10
11pub fn parse_sql_query_arguments(query: &str, params: &mut Individual, dialect: &str) -> Result<String, Error> {
12    match dialect {
13        "clickhouse" => {
14            let re = Regex::new(r"(\{[^\}]+\}|'\{[^\}]+\}')").unwrap();
15
16            let mut arg_names = Vec::new();
17            let mut arg_values = Vec::new();
18            let res_query = re
19                .replace_all(query, |caps: &regex::Captures| {
20                    let arg_name_with_braces = caps.get(1).unwrap().as_str();
21                    let arg_name = arg_name_with_braces.trim_start_matches("'{").trim_end_matches("}'").trim_start_matches("{").trim_end_matches("}");
22                    arg_names.push(arg_name.to_string());
23                    let arg_index = arg_names.len();
24                    format!("${}", arg_index)
25                })
26                .to_string();
27
28            //info!("@res_query={:?}", res_query);
29            //info!("@arg_names={:?}", arg_names);
30
31            for arg_name in &arg_names {
32                //info!("@arg_name={}", arg_name);
33                if let Some(res) = params.get_obj().get_resources().get(arg_name) {
34                    let arg_value = match &res[0].value {
35                        Value::Uri(v) | Value::Str(v, _) => klickhouse::Value::string(v),
36                        Value::Int(v) => klickhouse::Value::Int64(*v),
37                        Value::Bool(v) => klickhouse::Value::UInt8(*v as u8),
38                        Value::Num(_m, _d) => klickhouse::Value::Float64(res[0].get_float()),
39                        Value::Datetime(v) => klickhouse::Value::DateTime(klickhouse::DateTime(klickhouse::Tz::UTC, *v as u32)),
40                        _ => return Err(Error::new(ErrorKind::Other, format!("Unsupported value type {:?}", res[0].value))),
41                    };
42                    arg_values.push(arg_value);
43                } else {
44                    return Err(Error::new(ErrorKind::Other, format!("Variable {} not found in params", arg_name)));
45                }
46            }
47
48            let res_query = parse_query_arguments(&res_query, &arg_values);
49            //info!("@res_query={:?}", res_query);
50
51            return Ok(res_query);
52        },
53        "mysql" | _ => {
54            let lex_tree = match dialect {
55                "mysql" => Parser::parse_sql(&MySqlDialect {}, query),
56                _ => Parser::parse_sql(&AnsiDialect {}, query),
57            };
58
59            match lex_tree {
60                Ok(mut ast) => {
61                    if let Some(el) = ast.iter_mut().next() {
62                        tr_statement(el, params)?;
63                        debug!("NEW: {}", el);
64                        return match dialect {
65                            "mysql" => Ok(el.to_string()),
66                            _ => Err(Error::new(ErrorKind::Other, "unknown SQL dialect")),
67                        };
68                    }
69                },
70                Err(e) => {
71                    error!("{:?}", e);
72                },
73            }
74            Err(Error::new(ErrorKind::Other, "?"))
75        },
76    }
77}