From 63a3b65a84656547c1fb1f4cc1f11427cb4c11de Mon Sep 17 00:00:00 2001 From: Ruihang Xia Date: Thu, 27 Apr 2023 17:48:13 +0800 Subject: [PATCH 1/7] feat: impl ENV interceptor Signed-off-by: Ruihang Xia --- sqlness/Cargo.toml | 1 + .../examples/bad-case/simple/select.result | 2 +- sqlness/src/interceptor.rs | 6 +- sqlness/src/interceptor/env.rs | 80 +++++++++++++++++++ 4 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 sqlness/src/interceptor/env.rs diff --git a/sqlness/Cargo.toml b/sqlness/Cargo.toml index 2d68a5e..59595d4 100644 --- a/sqlness/Cargo.toml +++ b/sqlness/Cargo.toml @@ -12,6 +12,7 @@ readme = { workspace = true } [dependencies] async-trait = "0.1" derive_builder = "0.11" +handlebars = "4" mysql = { version = "23.0.1", optional = true } prettydiff = { version = "0.6.2", default_features = false } regex = "1.7.1" diff --git a/sqlness/examples/bad-case/simple/select.result b/sqlness/examples/bad-case/simple/select.result index a6c3ac4..776d77e 100644 --- a/sqlness/examples/bad-case/simple/select.result +++ b/sqlness/examples/bad-case/simple/select.result @@ -3,5 +3,5 @@ SELECT FROM `table`; -ok +Unexpected diff --git a/sqlness/src/interceptor.rs b/sqlness/src/interceptor.rs index 315599b..a5e8551 100644 --- a/sqlness/src/interceptor.rs +++ b/sqlness/src/interceptor.rs @@ -6,10 +6,13 @@ use std::sync::Arc; use crate::{ case::QueryContext, - interceptor::{arg::ArgInterceptorFactory, replace::ReplaceInterceptorFactory}, + interceptor::{ + arg::ArgInterceptorFactory, env::EnvInterceptorFactory, replace::ReplaceInterceptorFactory, + }, }; pub mod arg; +pub mod env; pub mod replace; pub type InterceptorRef = Box; @@ -33,5 +36,6 @@ pub fn builtin_interceptors() -> Vec { vec![ Arc::new(ArgInterceptorFactory {}), Arc::new(ReplaceInterceptorFactory {}), + Arc::new(EnvInterceptorFactory {}), ] } diff --git a/sqlness/src/interceptor/env.rs b/sqlness/src/interceptor/env.rs new file mode 100644 index 00000000..cb6ff21 --- /dev/null +++ b/sqlness/src/interceptor/env.rs @@ -0,0 +1,80 @@ +// Copyright 2023 CeresDB Project Authors. Licensed under Apache-2.0. + +use std::collections::HashMap; + +use handlebars::Handlebars; + +use crate::case::QueryContext; +use crate::interceptor::{Interceptor, InterceptorFactory, InterceptorRef}; + +const PREFIX: &str = "ENV"; + +/// Read environment variables and fill them in query. +#[derive(Debug)] +pub struct EnvInterceptor { + data: HashMap, +} + +impl Interceptor for EnvInterceptor { + fn before_execute(&self, query_lines: &mut Vec, _: &mut QueryContext) { + let mut handlebars = Handlebars::new(); + handlebars.set_strict_mode(true); + for line in query_lines { + let rendered = handlebars + .render_template(line.as_str(), &self.data) + .unwrap(); + *line = rendered; + } + } +} + +pub struct EnvInterceptorFactory; + +impl InterceptorFactory for EnvInterceptorFactory { + fn try_new(&self, interceptor: &str) -> Option { + Self::create(interceptor).map(|i| Box::new(i) as InterceptorRef) + } +} + +impl EnvInterceptorFactory { + fn create(interceptor: &str) -> Option { + if interceptor.starts_with(PREFIX) { + let input = interceptor + .trim_start_matches(PREFIX) + .trim_start() + .trim_end(); + let envs = input.split(' ').collect::>(); + + let mut env_data = HashMap::new(); + for env in envs { + let value = std::env::var(env).unwrap_or_default(); + env_data.insert(env.to_string(), value); + } + + Some(EnvInterceptor { data: env_data }) + } else { + None + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn cut_env_string() { + let input = "ENV SECRET NONEXIST"; + std::env::set_var("SECRET", "2333"); + + let expected = [ + ("SECRET".to_string(), "2333".to_string()), + ("NONEXIST".to_string(), "".to_string()), + ] + .into_iter() + .collect(); + + let interceptor = EnvInterceptorFactory::create(input).unwrap(); + assert_eq!(interceptor.data, expected); + } +} From 95c296d022efca195e157fd3a20d51fa883e31d4 Mon Sep 17 00:00:00 2001 From: Ruihang Xia Date: Thu, 27 Apr 2023 18:01:10 +0800 Subject: [PATCH 2/7] add examples Signed-off-by: Ruihang Xia --- Makefile | 6 +++--- sqlness/examples/{interceptor_replace.rs => echo.rs} | 2 +- sqlness/examples/echo/interceptor-env/env.result | 10 ++++++++++ sqlness/examples/echo/interceptor-env/env.sql | 5 +++++ .../simple => echo/interceptor-replace}/replace.result | 0 .../simple => echo/interceptor-replace}/replace.sql | 0 sqlness/src/interceptor/env.rs | 4 ++-- sqlness/src/interceptor/replace.rs | 2 +- 8 files changed, 22 insertions(+), 7 deletions(-) rename sqlness/examples/{interceptor_replace.rs => echo.rs} (94%) create mode 100644 sqlness/examples/echo/interceptor-env/env.result create mode 100644 sqlness/examples/echo/interceptor-env/env.sql rename sqlness/examples/{interceptor-replace/simple => echo/interceptor-replace}/replace.result (100%) rename sqlness/examples/{interceptor-replace/simple => echo/interceptor-replace}/replace.sql (100%) diff --git a/Makefile b/Makefile index 8b9b4cf..4ba3425 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ cli-test: example: good-example bad-example -good-example: basic-example interceptor-arg-example interceptor-replace-example +good-example: basic-example interceptor-arg-example echo-example basic-example: cd $(DIR)/sqlness; cargo run --example basic @@ -37,5 +37,5 @@ bad-example: interceptor-arg-example: cd $(DIR)/sqlness; cargo run --example interceptor_arg -interceptor-replace-example: - cd $(DIR)/sqlness; cargo run --example interceptor_replace +echo-example: + cd $(DIR)/sqlness; SECRET=23333 cargo run --example echo diff --git a/sqlness/examples/interceptor_replace.rs b/sqlness/examples/echo.rs similarity index 94% rename from sqlness/examples/interceptor_replace.rs rename to sqlness/examples/echo.rs index 23f3dda..10a3a49 100644 --- a/sqlness/examples/interceptor_replace.rs +++ b/sqlness/examples/echo.rs @@ -42,7 +42,7 @@ impl EnvController for MyController { async fn main() { let env = MyController; let config = ConfigBuilder::default() - .case_dir("examples/interceptor-replace".to_string()) + .case_dir("examples/echo".to_string()) .build() .unwrap(); let runner = Runner::new(config, env); diff --git a/sqlness/examples/echo/interceptor-env/env.result b/sqlness/examples/echo/interceptor-env/env.result new file mode 100644 index 00000000..596cb7f --- /dev/null +++ b/sqlness/examples/echo/interceptor-env/env.result @@ -0,0 +1,10 @@ +-- SQLNESS ENV SECRET +select 23333 from data; + +select 23333 from data; + +-- SQLNESS ENV SECRET NONEXISTENT +select 23333 from data; + +select 23333 from data; + diff --git a/sqlness/examples/echo/interceptor-env/env.sql b/sqlness/examples/echo/interceptor-env/env.sql new file mode 100644 index 00000000..5160163 --- /dev/null +++ b/sqlness/examples/echo/interceptor-env/env.sql @@ -0,0 +1,5 @@ +-- SQLNESS ENV SECRET +select {{ SECRET }} from data; + +-- SQLNESS ENV SECRET NONEXISTENT +select {{ SECRET }} from data; \ No newline at end of file diff --git a/sqlness/examples/interceptor-replace/simple/replace.result b/sqlness/examples/echo/interceptor-replace/replace.result similarity index 100% rename from sqlness/examples/interceptor-replace/simple/replace.result rename to sqlness/examples/echo/interceptor-replace/replace.result diff --git a/sqlness/examples/interceptor-replace/simple/replace.sql b/sqlness/examples/echo/interceptor-replace/replace.sql similarity index 100% rename from sqlness/examples/interceptor-replace/simple/replace.sql rename to sqlness/examples/echo/interceptor-replace/replace.sql diff --git a/sqlness/src/interceptor/env.rs b/sqlness/src/interceptor/env.rs index cb6ff21..4d35025 100644 --- a/sqlness/src/interceptor/env.rs +++ b/sqlness/src/interceptor/env.rs @@ -64,12 +64,12 @@ mod test { #[test] fn cut_env_string() { - let input = "ENV SECRET NONEXIST"; + let input = "ENV SECRET NONEXISTENT"; std::env::set_var("SECRET", "2333"); let expected = [ ("SECRET".to_string(), "2333".to_string()), - ("NONEXIST".to_string(), "".to_string()), + ("NONEXISTENT".to_string(), "".to_string()), ] .into_iter() .collect(); diff --git a/sqlness/src/interceptor/replace.rs b/sqlness/src/interceptor/replace.rs index 3922537..c4b8c99 100644 --- a/sqlness/src/interceptor/replace.rs +++ b/sqlness/src/interceptor/replace.rs @@ -1,4 +1,4 @@ -// Copyright 2022 CeresDB Project Authors. Licensed under Apache-2.0. +// Copyright 2023 CeresDB Project Authors. Licensed under Apache-2.0. use regex::Regex; From 3fb675c20d81f4fc8ec553c6de1aeae0206bab81 Mon Sep 17 00:00:00 2001 From: Ruihang Xia Date: Sat, 7 Oct 2023 22:12:06 +0800 Subject: [PATCH 3/7] add example Signed-off-by: Ruihang Xia --- Makefile | 5 +- sqlness/Cargo.toml | 1 - .../interceptor-env/simple/env.result | 22 ++++++++ .../examples/interceptor-env/simple/env.sql | 15 +++++ .../interceptor-replace/simple/replace.result | 21 +++++++ .../interceptor-replace/simple/replace.sql | 12 ++++ sqlness/examples/interceptor_env.rs | 55 +++++++++++++++++++ sqlness/examples/interceptor_replace.rs | 53 ++++++++++++++++++ sqlness/src/case.rs | 23 ++++++-- sqlness/src/interceptor.rs | 8 ++- sqlness/src/interceptor/arg.rs | 2 +- sqlness/src/interceptor/env.rs | 35 ++++++------ 12 files changed, 225 insertions(+), 27 deletions(-) create mode 100644 sqlness/examples/interceptor-env/simple/env.result create mode 100644 sqlness/examples/interceptor-env/simple/env.sql create mode 100644 sqlness/examples/interceptor-replace/simple/replace.result create mode 100644 sqlness/examples/interceptor-replace/simple/replace.sql create mode 100644 sqlness/examples/interceptor_env.rs create mode 100644 sqlness/examples/interceptor_replace.rs diff --git a/Makefile b/Makefile index a6db970..cc26a95 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ cli-test: example: good-example bad-example -good-example: basic-example interceptor-arg-example interceptor-replace-example interceptor-sort-result-example +good-example: basic-example interceptor-arg-example interceptor-replace-example interceptor-sort-result-example interceptor-env-example basic-example: cd $(DIR)/sqlness; cargo run --example basic @@ -43,3 +43,6 @@ interceptor-replace-example: interceptor-sort-result-example: cd $(DIR)/sqlness; cargo run --example interceptor_sort_result + +interceptor-env-example: + cd $(DIR)/sqlness; cargo run --example interceptor_env \ No newline at end of file diff --git a/sqlness/Cargo.toml b/sqlness/Cargo.toml index 5f9066f..ca0345e 100644 --- a/sqlness/Cargo.toml +++ b/sqlness/Cargo.toml @@ -12,7 +12,6 @@ readme = { workspace = true } [dependencies] async-trait = "0.1" derive_builder = "0.11" -handlebars = "4" mysql = { version = "23.0.1", optional = true } postgres = { version = "0.19.7", optional = true } prettydiff = { version = "0.6.2", default_features = false } diff --git a/sqlness/examples/interceptor-env/simple/env.result b/sqlness/examples/interceptor-env/simple/env.result new file mode 100644 index 00000000..6a72536 --- /dev/null +++ b/sqlness/examples/interceptor-env/simple/env.result @@ -0,0 +1,22 @@ +-- multiple env in one line +-- SQLNESS ENV ENV1 ENV2 NONEXISTENT1 NONEXISTENT2 NONEXISTENT3 +SELECT $ENV1, $ENV2, $NONEXISTENT1 FROM t; + +SELECT value1, value2, $NONEXISTENT1 FROM t; + +-- multiple env in multiple lines +-- SQLNESS ENV ENV1 +-- SQLNESS ENV ENV2 +-- SQLNESS ENV NONEXISTENT1 +-- SQLNESS ENV NONEXISTENT2 +-- SQLNESS ENV NONEXISTENT3 +SELECT $ENV1, $ENV2, $NONEXISTENT1, FROM t; + +SELECT value1, value2, $NONEXISTENT1, FROM t; + +-- Undeclared env won't be rendered +-- SQLNESS ENV ENV2 +SELECT $ENV1, $ENV2, $NONEXISTENT1 FROM t; + +SELECT $ENV1, value2, $NONEXISTENT1 FROM t; + diff --git a/sqlness/examples/interceptor-env/simple/env.sql b/sqlness/examples/interceptor-env/simple/env.sql new file mode 100644 index 00000000..e237480 --- /dev/null +++ b/sqlness/examples/interceptor-env/simple/env.sql @@ -0,0 +1,15 @@ +-- multiple env in one line +-- SQLNESS ENV ENV1 ENV2 NONEXISTENT1 NONEXISTENT2 NONEXISTENT3 +SELECT $ENV1, $ENV2, $NONEXISTENT1 FROM t; + +-- multiple env in multiple lines +-- SQLNESS ENV ENV1 +-- SQLNESS ENV ENV2 +-- SQLNESS ENV NONEXISTENT1 +-- SQLNESS ENV NONEXISTENT2 +-- SQLNESS ENV NONEXISTENT3 +SELECT $ENV1, $ENV2, $NONEXISTENT1, FROM t; + +-- Undeclared env won't be rendered +-- SQLNESS ENV ENV2 +SELECT $ENV1, $ENV2, $NONEXISTENT1 FROM t; diff --git a/sqlness/examples/interceptor-replace/simple/replace.result b/sqlness/examples/interceptor-replace/simple/replace.result new file mode 100644 index 00000000..60d17d6 --- /dev/null +++ b/sqlness/examples/interceptor-replace/simple/replace.result @@ -0,0 +1,21 @@ +-- SQLNESS REPLACE 00 +SELECT 0; + +SELECT 0; + +-- SQLNESS REPLACE 00 +SELECT 00; + +SELECT ; + +-- SQLNESS REPLACE 0 1 +SELECT 0; + +SELECT 1; + +-- example of capture group replacement +-- SQLNESS REPLACE (?P\d{4})-(?P\d{2})-(?P\d{2}) $m/$d/$y +2012-03-14, 2013-01-01 and 2014-07-05; + +03/14/2012, 01/01/2013 and 07/05/2014; + diff --git a/sqlness/examples/interceptor-replace/simple/replace.sql b/sqlness/examples/interceptor-replace/simple/replace.sql new file mode 100644 index 00000000..f47f540 --- /dev/null +++ b/sqlness/examples/interceptor-replace/simple/replace.sql @@ -0,0 +1,12 @@ +-- SQLNESS REPLACE 00 +SELECT 0; + +-- SQLNESS REPLACE 00 +SELECT 00; + +-- SQLNESS REPLACE 0 1 +SELECT 0; + +-- example of capture group replacement +-- SQLNESS REPLACE (?P\d{4})-(?P\d{2})-(?P\d{2}) $m/$d/$y +2012-03-14, 2013-01-01 and 2014-07-05; diff --git a/sqlness/examples/interceptor_env.rs b/sqlness/examples/interceptor_env.rs new file mode 100644 index 00000000..1ae0ab5 --- /dev/null +++ b/sqlness/examples/interceptor_env.rs @@ -0,0 +1,55 @@ +// Copyright 2023 CeresDB Project Authors. Licensed under Apache-2.0. + +//! Shows how an SORT_RESULT interceptor works. + +use std::{fmt::Display, path::Path}; + +use async_trait::async_trait; +use sqlness::{ConfigBuilder, Database, EnvController, QueryContext, Runner}; + +struct MyController; +struct MyDB; + +#[async_trait] +impl Database for MyDB { + async fn query(&self, _: QueryContext, query: String) -> Box { + return Box::new(query); + } +} + +impl MyDB { + fn new(_env: &str, _config: Option<&Path>) -> Self { + MyDB + } + + fn stop(self) {} +} + +#[async_trait] +impl EnvController for MyController { + type DB = MyDB; + + async fn start(&self, env: &str, config: Option<&Path>) -> Self::DB { + MyDB::new(env, config) + } + + async fn stop(&self, _env: &str, database: Self::DB) { + database.stop(); + } +} + +#[tokio::main] +async fn main() { + std::env::set_var("ENV1", "value1"); + std::env::set_var("ENV2", "value2"); + let env = MyController; + let config = ConfigBuilder::default() + .case_dir("examples/interceptor-env".to_string()) + .build() + .unwrap(); + let runner = Runner::new(config, env); + + println!("Run testcase..."); + + runner.run().await.unwrap(); +} diff --git a/sqlness/examples/interceptor_replace.rs b/sqlness/examples/interceptor_replace.rs new file mode 100644 index 00000000..23f3dda --- /dev/null +++ b/sqlness/examples/interceptor_replace.rs @@ -0,0 +1,53 @@ +// Copyright 2022 CeresDB Project Authors. Licensed under Apache-2.0. + +//! Shows how an REPLACE interceptor works. + +use std::{fmt::Display, path::Path}; + +use async_trait::async_trait; +use sqlness::{ConfigBuilder, Database, EnvController, QueryContext, Runner}; + +struct MyController; +struct MyDB; + +#[async_trait] +impl Database for MyDB { + async fn query(&self, _: QueryContext, query: String) -> Box { + return Box::new(query); + } +} + +impl MyDB { + fn new(_env: &str, _config: Option<&Path>) -> Self { + MyDB + } + + fn stop(self) {} +} + +#[async_trait] +impl EnvController for MyController { + type DB = MyDB; + + async fn start(&self, env: &str, config: Option<&Path>) -> Self::DB { + MyDB::new(env, config) + } + + async fn stop(&self, _env: &str, database: Self::DB) { + database.stop(); + } +} + +#[tokio::main] +async fn main() { + let env = MyController; + let config = ConfigBuilder::default() + .case_dir("examples/interceptor-replace".to_string()) + .build() + .unwrap(); + let runner = Runner::new(config, env); + + println!("Run testcase..."); + + runner.run().await.unwrap(); +} diff --git a/sqlness/src/case.rs b/sqlness/src/case.rs index 36b484a..511d8ce 100644 --- a/sqlness/src/case.rs +++ b/sqlness/src/case.rs @@ -96,7 +96,10 @@ pub struct QueryContext { #[derive(Default)] struct Query { comment_lines: Vec, - query_lines: Vec, + /// Query to be displayed in the result file + display_query: Vec, + /// Query to be executed + execute_query: Vec, interceptor_factories: Vec, interceptors: Vec, } @@ -125,7 +128,8 @@ impl Query { } fn append_query_line(&mut self, line: &str) { - self.query_lines.push(line.to_string()); + self.display_query.push(line.to_string()); + self.execute_query.push(line.to_string()); } async fn execute(&mut self, db: &dyn Database, writer: &mut W) -> Result<()> @@ -145,11 +149,19 @@ impl Query { Ok(()) } + /// Run pre-execution interceptors. + /// + /// Interceptors may change either the query to be displayed or the query to be executed, + /// so we need to return the query to caller. fn before_execute_intercept(&mut self) -> QueryContext { let mut context = QueryContext::default(); for interceptor in &self.interceptors { - interceptor.before_execute(&mut self.query_lines, &mut context); + interceptor.before_execute( + &mut self.display_query, + &mut self.execute_query, + &mut context, + ); } context @@ -161,8 +173,9 @@ impl Query { } } + /// Concat the query to be executed to a single string. fn concat_query_lines(&self) -> String { - self.query_lines + self.execute_query .iter() .fold(String::new(), |query, str| query + str) .trim_start() @@ -178,7 +191,7 @@ impl Query { writer.write_all(comment.as_bytes())?; writer.write("\n".as_bytes())?; } - for line in &self.query_lines { + for line in &self.display_query { writer.write_all(line.as_bytes())?; } writer.write("\n\n".as_bytes())?; diff --git a/sqlness/src/interceptor.rs b/sqlness/src/interceptor.rs index f16736d..1ccf172 100644 --- a/sqlness/src/interceptor.rs +++ b/sqlness/src/interceptor.rs @@ -21,7 +21,13 @@ pub type InterceptorRef = Box; pub trait Interceptor { #[allow(unused_variables)] - fn before_execute(&self, query: &mut Vec, context: &mut QueryContext) {} + fn before_execute( + &self, + display_query: &mut Vec, + execute_query: &mut Vec, + context: &mut QueryContext, + ) { + } #[allow(unused_variables)] fn after_execute(&self, result: &mut String) {} diff --git a/sqlness/src/interceptor/arg.rs b/sqlness/src/interceptor/arg.rs index 6f313c7..2e0b56f 100644 --- a/sqlness/src/interceptor/arg.rs +++ b/sqlness/src/interceptor/arg.rs @@ -25,7 +25,7 @@ pub struct ArgInterceptor { } impl Interceptor for ArgInterceptor { - fn before_execute(&self, _: &mut Vec, context: &mut QueryContext) { + fn before_execute(&self, _: &mut Vec, _: &mut Vec, context: &mut QueryContext) { for (key, value) in &self.args { context.context.insert(key.to_string(), value.to_string()); } diff --git a/sqlness/src/interceptor/env.rs b/sqlness/src/interceptor/env.rs index 4d35025..9b43e8b 100644 --- a/sqlness/src/interceptor/env.rs +++ b/sqlness/src/interceptor/env.rs @@ -2,8 +2,6 @@ use std::collections::HashMap; -use handlebars::Handlebars; - use crate::case::QueryContext; use crate::interceptor::{Interceptor, InterceptorFactory, InterceptorRef}; @@ -16,14 +14,17 @@ pub struct EnvInterceptor { } impl Interceptor for EnvInterceptor { - fn before_execute(&self, query_lines: &mut Vec, _: &mut QueryContext) { - let mut handlebars = Handlebars::new(); - handlebars.set_strict_mode(true); - for line in query_lines { - let rendered = handlebars - .render_template(line.as_str(), &self.data) - .unwrap(); - *line = rendered; + fn before_execute( + &self, + _: &mut Vec, + execute_query: &mut Vec, + _: &mut QueryContext, + ) { + for line in execute_query { + for (key, value) in &self.data { + let rendered = line.replace(key, value); + *line = rendered; + } } } } @@ -47,8 +48,9 @@ impl EnvInterceptorFactory { let mut env_data = HashMap::new(); for env in envs { - let value = std::env::var(env).unwrap_or_default(); - env_data.insert(env.to_string(), value); + if let Ok(value) = std::env::var(env) { + env_data.insert(format!("${env}"), value); + } } Some(EnvInterceptor { data: env_data }) @@ -67,12 +69,9 @@ mod test { let input = "ENV SECRET NONEXISTENT"; std::env::set_var("SECRET", "2333"); - let expected = [ - ("SECRET".to_string(), "2333".to_string()), - ("NONEXISTENT".to_string(), "".to_string()), - ] - .into_iter() - .collect(); + let expected = [("$SECRET".to_string(), "2333".to_string())] + .into_iter() + .collect(); let interceptor = EnvInterceptorFactory::create(input).unwrap(); assert_eq!(interceptor.data, expected); From 7e53f83d60d8586f49e7d1b6808ca45bee89b035 Mon Sep 17 00:00:00 2001 From: Ruihang Xia Date: Sat, 7 Oct 2023 22:16:43 +0800 Subject: [PATCH 4/7] add documents Signed-off-by: Ruihang Xia --- sqlness/src/interceptor/env.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/sqlness/src/interceptor/env.rs b/sqlness/src/interceptor/env.rs index 9b43e8b..fb456e5 100644 --- a/sqlness/src/interceptor/env.rs +++ b/sqlness/src/interceptor/env.rs @@ -8,6 +8,30 @@ use crate::interceptor::{Interceptor, InterceptorFactory, InterceptorRef}; const PREFIX: &str = "ENV"; /// Read environment variables and fill them in query. +/// +/// # Example +/// ``` sql +/// -- SQLNESS ENV SECRET +/// SELECT $SECRET; +/// ``` +/// +/// Environment variables declared in `ENV` interceptor will be replaced in the +/// going to be executed. It won't be rendered in the result file so you can +/// safely put secret things in your query. +/// +/// Note that only decalred and present environment variables will be replaced. +/// +/// You can either declare multiple env in one intercetor or separate them into +/// different interceptors. The following two examples are equivalent: +/// +/// ``` sql +/// -- SQLNESS ENV SECRET1 SECRET2 +/// SELECT $SECRET1, $SECRET2; +/// +/// -- SQLNESS ENV SECRET1 +/// -- SQLNESS ENV SECRET2 +/// SELECT $SECRET1, $SECRET2; +/// ```` #[derive(Debug)] pub struct EnvInterceptor { data: HashMap, From a4d3a723a1925f0d8db239288c70271b8cd5e927 Mon Sep 17 00:00:00 2001 From: Ruihang Xia Date: Sat, 7 Oct 2023 22:22:44 +0800 Subject: [PATCH 5/7] tweak style Signed-off-by: Ruihang Xia --- Makefile | 2 +- sqlness/examples/bad-case/simple/select.result | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index cc26a95..5e45779 100644 --- a/Makefile +++ b/Makefile @@ -45,4 +45,4 @@ interceptor-sort-result-example: cd $(DIR)/sqlness; cargo run --example interceptor_sort_result interceptor-env-example: - cd $(DIR)/sqlness; cargo run --example interceptor_env \ No newline at end of file + cd $(DIR)/sqlness; cargo run --example interceptor_env diff --git a/sqlness/examples/bad-case/simple/select.result b/sqlness/examples/bad-case/simple/select.result index 776d77e..a6c3ac4 100644 --- a/sqlness/examples/bad-case/simple/select.result +++ b/sqlness/examples/bad-case/simple/select.result @@ -3,5 +3,5 @@ SELECT FROM `table`; -Unexpected +ok From b6ded50ecce6522e89ea9ef700e3b12b26f64433 Mon Sep 17 00:00:00 2001 From: Ruihang Xia Date: Wed, 8 Nov 2023 15:25:22 +0800 Subject: [PATCH 6/7] add comment Signed-off-by: Ruihang Xia --- sqlness/src/interceptor/env.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/sqlness/src/interceptor/env.rs b/sqlness/src/interceptor/env.rs index fb456e5..69b9d39 100644 --- a/sqlness/src/interceptor/env.rs +++ b/sqlness/src/interceptor/env.rs @@ -34,6 +34,7 @@ const PREFIX: &str = "ENV"; /// ```` #[derive(Debug)] pub struct EnvInterceptor { + /// Environment variables to be replaced. data: HashMap, } From 92ffd79c36f28a90ee525f91871fdc2e4e5ea597 Mon Sep 17 00:00:00 2001 From: Ruihang Xia Date: Wed, 8 Nov 2023 16:33:45 +0800 Subject: [PATCH 7/7] remove unused params Signed-off-by: Ruihang Xia --- sqlness/src/case.rs | 6 +----- sqlness/src/interceptor.rs | 8 +------- sqlness/src/interceptor/arg.rs | 2 +- sqlness/src/interceptor/env.rs | 7 +------ 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/sqlness/src/case.rs b/sqlness/src/case.rs index 511d8ce..ed581eb 100644 --- a/sqlness/src/case.rs +++ b/sqlness/src/case.rs @@ -157,11 +157,7 @@ impl Query { let mut context = QueryContext::default(); for interceptor in &self.interceptors { - interceptor.before_execute( - &mut self.display_query, - &mut self.execute_query, - &mut context, - ); + interceptor.before_execute(&mut self.execute_query, &mut context); } context diff --git a/sqlness/src/interceptor.rs b/sqlness/src/interceptor.rs index 1ccf172..094e998 100644 --- a/sqlness/src/interceptor.rs +++ b/sqlness/src/interceptor.rs @@ -21,13 +21,7 @@ pub type InterceptorRef = Box; pub trait Interceptor { #[allow(unused_variables)] - fn before_execute( - &self, - display_query: &mut Vec, - execute_query: &mut Vec, - context: &mut QueryContext, - ) { - } + fn before_execute(&self, execute_query: &mut Vec, context: &mut QueryContext) {} #[allow(unused_variables)] fn after_execute(&self, result: &mut String) {} diff --git a/sqlness/src/interceptor/arg.rs b/sqlness/src/interceptor/arg.rs index 2e0b56f..6f313c7 100644 --- a/sqlness/src/interceptor/arg.rs +++ b/sqlness/src/interceptor/arg.rs @@ -25,7 +25,7 @@ pub struct ArgInterceptor { } impl Interceptor for ArgInterceptor { - fn before_execute(&self, _: &mut Vec, _: &mut Vec, context: &mut QueryContext) { + fn before_execute(&self, _: &mut Vec, context: &mut QueryContext) { for (key, value) in &self.args { context.context.insert(key.to_string(), value.to_string()); } diff --git a/sqlness/src/interceptor/env.rs b/sqlness/src/interceptor/env.rs index 69b9d39..e6c7259 100644 --- a/sqlness/src/interceptor/env.rs +++ b/sqlness/src/interceptor/env.rs @@ -39,12 +39,7 @@ pub struct EnvInterceptor { } impl Interceptor for EnvInterceptor { - fn before_execute( - &self, - _: &mut Vec, - execute_query: &mut Vec, - _: &mut QueryContext, - ) { + fn before_execute(&self, execute_query: &mut Vec, _: &mut QueryContext) { for line in execute_query { for (key, value) in &self.data { let rendered = line.replace(key, value);