ch_grafana_cache/
variables.rs1use std::collections::HashMap;
2
3use itertools::Itertools;
4
5lazy_static::lazy_static! {
6 pub static ref VARIABLE_RE: regex::Regex = regex::Regex::new(r#"\$\{(.*?)\}"#).unwrap();
7}
8
9pub type VariablesAssignment<'a> = HashMap<&'a str, String>;
10
11#[derive(thiserror::Error, Debug)]
12enum SubsError {
13 #[error("Variable {0} not found")]
14 NotFound(String),
15}
16
17fn substitute_variable(
18 cap: ®ex::Captures,
19 variables: &VariablesAssignment<'_>,
20) -> Result<String, SubsError> {
21 let name = cap.get(1).unwrap().as_str();
22 variables
23 .get(name)
24 .ok_or_else(|| SubsError::NotFound(name.into()))
25 .cloned()
26 .map(|s| s.to_string())
27}
28pub fn substitute_variables(
29 sql: &str,
30 variables: &VariablesAssignment<'_>,
31) -> anyhow::Result<String> {
32 let mut errors = Vec::<SubsError>::default();
33
34 let sql = VARIABLE_RE
35 .replace_all(sql, |cap: ®ex::Captures| {
36 substitute_variable(cap, variables).unwrap_or_else(|e| {
37 errors.push(e);
38 "ERROR".into()
39 })
40 })
41 .into_owned();
42 if !errors.is_empty() {
43 anyhow::bail!(
44 "Encountered substitution errors:\n {}",
45 errors.into_iter().map(|e| e.to_string()).join("\n ")
46 );
47 }
48 Ok(sql)
49}
50
51#[cfg(test)]
52mod test {
53 #[test]
54 fn substitute_variables() -> anyhow::Result<()> {
55 assert_eq!(
56 "SELECT * FROM test",
57 super::substitute_variables(
58 "SELECT * FROM ${table}",
59 &std::collections::HashMap::from([("table", "test".into())])
60 )?
61 );
62 assert!(super::substitute_variables("${table}", &Default::default()).is_err());
64 Ok(())
65 }
66}