fix: support for ClickHouse database username and password configuration

This commit is contained in:
t8y2 2026-05-02 17:25:16 +08:00
parent 1fe40b7a09
commit c6f9bb89ec
4 changed files with 33 additions and 11 deletions

View File

@ -106,7 +106,9 @@ impl AppState {
PoolKind::MongoDb(client)
}
DatabaseType::ClickHouse => {
let client = db::clickhouse_driver::ChClient::new(&url);
let username = if db_config.username.is_empty() { None } else { Some(db_config.username.clone()) };
let password = if db_config.password.is_empty() { None } else { Some(db_config.password.clone()) };
let client = db::clickhouse_driver::ChClient::new(&url, username, password);
db::clickhouse_driver::test_connection(&client).await?;
PoolKind::ClickHouse(client)
}
@ -311,7 +313,9 @@ pub async fn test_connection(
Err(e) => Err(e.to_string()),
},
DatabaseType::ClickHouse => {
let client = db::clickhouse_driver::ChClient::new(&url);
let username = if config.username.is_empty() { None } else { Some(config.username.clone()) };
let password = if config.password.is_empty() { None } else { Some(config.password.clone()) };
let client = db::clickhouse_driver::ChClient::new(&url, username, password);
db::clickhouse_driver::test_connection(&client)
.await
.map(|_| "Connection successful".to_string())
@ -381,7 +385,9 @@ pub async fn connect_db(
PoolKind::MongoDb(client)
}
DatabaseType::ClickHouse => {
let client = db::clickhouse_driver::ChClient::new(&url);
let username = if config.username.is_empty() { None } else { Some(config.username.clone()) };
let password = if config.password.is_empty() { None } else { Some(config.password.clone()) };
let client = db::clickhouse_driver::ChClient::new(&url, username, password);
db::clickhouse_driver::test_connection(&client).await?;
PoolKind::ClickHouse(client)
}

View File

@ -67,6 +67,7 @@ pub struct SqlFileProgress {
pub error: Option<String>,
}
#[cfg(test)]
#[derive(Debug, Clone, PartialEq, Eq)]
struct SqlFileSummary {
status: SqlFileStatus,

View File

@ -7,13 +7,17 @@ use super::{ColumnInfo, DatabaseInfo, QueryResult, TableInfo};
pub struct ChClient {
http: HttpClient,
base_url: String,
username: Option<String>,
password: Option<String>,
}
impl ChClient {
pub fn new(url: &str) -> Self {
pub fn new(url: &str, username: Option<String>, password: Option<String>) -> Self {
Self {
http: HttpClient::new(),
base_url: url.trim_end_matches('/').to_string(),
username,
password,
}
}
}
@ -23,6 +27,8 @@ impl Clone for ChClient {
Self {
http: self.http.clone(),
base_url: self.base_url.clone(),
username: self.username.clone(),
password: self.password.clone(),
}
}
}
@ -43,13 +49,21 @@ struct ChColumn {
_type: String,
}
fn build_request(client: &ChClient, req: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
match (&client.username, &client.password) {
(Some(u), Some(p)) if !u.is_empty() => req.basic_auth(u, Some(p)),
(Some(u), None) if !u.is_empty() => req.basic_auth(u, None::<&str>),
_ => req,
}
}
async fn ch_query(client: &ChClient, sql: &str, database: Option<&str>) -> Result<ChJsonResult, String> {
let mut url = format!("{}/?default_format=JSONCompact", client.base_url);
if let Some(db) = database {
url.push_str(&format!("&database={}", db));
}
let resp = client.http.post(&url)
.body(sql.to_string())
let req = build_request(client, client.http.post(&url).body(sql.to_string()));
let resp = req
.send()
.await
.map_err(|e| format!("ClickHouse request failed: {e}"))?;
@ -62,7 +76,8 @@ async fn ch_query(client: &ChClient, sql: &str, database: Option<&str>) -> Resul
pub async fn test_connection(client: &ChClient) -> Result<(), String> {
let url = format!("{}/ping", client.base_url);
client.http.get(&url).send().await
let req = build_request(client, client.http.get(&url));
req.send().await
.map_err(|e| format!("ClickHouse connection failed: {e}"))?;
Ok(())
}
@ -139,8 +154,8 @@ pub async fn execute_query(client: &ChClient, database: &str, sql: &str) -> Resu
})
} else {
let url = format!("{}/?default_format=JSONCompact&database={}", client.base_url, database);
let resp = client.http.post(&url)
.body(sql.to_string())
let req = build_request(client, client.http.post(&url).body(sql.to_string()));
let resp = req
.send()
.await
.map_err(|e| format!("ClickHouse request failed: {e}"))?;

View File

@ -104,7 +104,7 @@ impl ConnectionConfig {
};
format!("postgres://{host}:{port}{db_part}{suffix}")
}
DatabaseType::ClickHouse => format!("http://{host}:{port}{db_part}"),
DatabaseType::ClickHouse => format!("http://{host}:{port}"),
DatabaseType::SqlServer => format!(
"server=tcp:{host},{port};database={}",
self.database.as_deref().unwrap_or("master")
@ -161,7 +161,7 @@ impl ConnectionConfig {
username, password
)
}
DatabaseType::ClickHouse => format!("http://{host}:{port}{db_part}"),
DatabaseType::ClickHouse => format!("http://{host}:{port}"),
DatabaseType::SqlServer => format!(
"server=tcp:{host},{port};user={};password={};database={}",
self.username,