From b43e67b4fca8cbb8f89e12b95c6de363045f20f3 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Fri, 1 May 2026 01:26:35 +0800 Subject: [PATCH] feat: add support for Doris, StarRocks, and Redshift databases in connection handling and UI --- src-tauri/src/commands/connection.rs | 12 +- src-tauri/src/commands/transfer.rs | 4 +- src-tauri/src/models/connection.rs | 16 ++- .../connection/ConnectionDialog.vue | 111 +++++++++++------- src/i18n/locales/en.ts | 1 + src/i18n/locales/zh-CN.ts | 1 + src/stores/connectionStore.ts | 3 + src/types/database.ts | 2 +- 8 files changed, 95 insertions(+), 55 deletions(-) diff --git a/src-tauri/src/commands/connection.rs b/src-tauri/src/commands/connection.rs index f942909ce..c396e9199 100644 --- a/src-tauri/src/commands/connection.rs +++ b/src-tauri/src/commands/connection.rs @@ -86,8 +86,8 @@ impl AppState { let (host, port) = self.connection_host_port(connection_id, &db_config).await?; let url = connection_url_for_endpoint(&db_config, &host, port); let pool = match db_config.db_type { - DatabaseType::Mysql => PoolKind::Mysql(db::mysql::connect(&url).await?), - DatabaseType::Postgres => PoolKind::Postgres(db::postgres::connect(&url).await?), + DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks => PoolKind::Mysql(db::mysql::connect(&url).await?), + DatabaseType::Postgres | DatabaseType::Redshift => PoolKind::Postgres(db::postgres::connect(&url).await?), DatabaseType::Sqlite => PoolKind::Sqlite(db::sqlite::connect(&url).await?), DatabaseType::Redis => { let con = db::redis_driver::connect(&url).await?; @@ -265,14 +265,14 @@ pub async fn test_connection( target ); let result = match config.db_type { - DatabaseType::Mysql => match db::mysql::connect(&url).await { + DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks => match db::mysql::connect(&url).await { Ok(pool) => { pool.close().await; Ok("Connection successful".to_string()) } Err(e) => Err(e), }, - DatabaseType::Postgres => match db::postgres::connect(&url).await { + DatabaseType::Postgres | DatabaseType::Redshift => match db::postgres::connect(&url).await { Ok(pool) => { pool.close().await; Ok("Connection successful".to_string()) @@ -358,8 +358,8 @@ pub async fn connect_db( let url = connection_url_for_endpoint(&config, &host, port); let pool = match config.db_type { - DatabaseType::Mysql => PoolKind::Mysql(db::mysql::connect(&url).await?), - DatabaseType::Postgres => PoolKind::Postgres(db::postgres::connect(&url).await?), + DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks => PoolKind::Mysql(db::mysql::connect(&url).await?), + DatabaseType::Postgres | DatabaseType::Redshift => PoolKind::Postgres(db::postgres::connect(&url).await?), DatabaseType::Sqlite => PoolKind::Sqlite(db::sqlite::connect(&url).await?), DatabaseType::Redis => { let con = db::redis_driver::connect(&url).await?; diff --git a/src-tauri/src/commands/transfer.rs b/src-tauri/src/commands/transfer.rs index e2f94e0df..6f0babeca 100644 --- a/src-tauri/src/commands/transfer.rs +++ b/src-tauri/src/commands/transfer.rs @@ -52,7 +52,7 @@ pub enum TransferStatus { fn quote_identifier(name: &str, db_type: &DatabaseType) -> String { match db_type { - DatabaseType::Mysql | DatabaseType::ClickHouse => format!("`{}`", name.replace('`', "``")), + DatabaseType::Mysql | DatabaseType::ClickHouse | DatabaseType::Doris | DatabaseType::StarRocks => format!("`{}`", name.replace('`', "``")), DatabaseType::SqlServer => format!("[{}]", name.replace(']', "]]")), _ => format!("\"{}\"", name.replace('"', "\"\"")), } @@ -71,7 +71,7 @@ fn escape_value(val: &serde_json::Value, db_type: &DatabaseType) -> String { match val { serde_json::Value::Null => "NULL".to_string(), serde_json::Value::Bool(b) => match db_type { - DatabaseType::Mysql | DatabaseType::Sqlite | DatabaseType::DuckDb => { + DatabaseType::Mysql | DatabaseType::Sqlite | DatabaseType::DuckDb | DatabaseType::Doris | DatabaseType::StarRocks => { if *b { "1".to_string() } else { "0".to_string() } } _ => if *b { "TRUE".to_string() } else { "FALSE".to_string() }, diff --git a/src-tauri/src/models/connection.rs b/src-tauri/src/models/connection.rs index 4e7457318..9b778585f 100644 --- a/src-tauri/src/models/connection.rs +++ b/src-tauri/src/models/connection.rs @@ -60,6 +60,10 @@ pub enum DatabaseType { Oracle, #[serde(rename = "elasticsearch")] Elasticsearch, + Doris, + #[serde(rename = "starrocks")] + StarRocks, + Redshift, } impl ConnectionConfig { @@ -88,8 +92,8 @@ impl ConnectionConfig { let scheme = if self.ssl { "rediss" } else { "redis" }; format!("{scheme}://{host}:{port}/") } - DatabaseType::Mysql => format!("mysql://{host}:{port}{db_part}?{params}"), - DatabaseType::Postgres => { + DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks => format!("mysql://{host}:{port}{db_part}?{params}"), + DatabaseType::Postgres | DatabaseType::Redshift => { let suffix = if params.is_empty() { String::new() } else { @@ -138,11 +142,11 @@ impl ConnectionConfig { format!("{scheme}://{username}:{password}@{host}:{port}/") } } - DatabaseType::Mysql => format!( + DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks => format!( "mysql://{}:{}@{host}:{port}{db_part}?{params}", username, password ), - DatabaseType::Postgres => { + DatabaseType::Postgres | DatabaseType::Redshift => { let suffix = if params.is_empty() { String::new() } else { @@ -180,7 +184,7 @@ impl ConnectionConfig { fn normalized_url_params(&self) -> String { let value = self.url_params.as_deref().unwrap_or("").trim(); match self.db_type { - DatabaseType::Mysql => { + DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks => { let base = "ssl-mode=preferred&charset=utf8mb4"; if value.is_empty() { base.to_string() @@ -192,7 +196,7 @@ impl ConnectionConfig { if v.contains("charset=") { format!("ssl-mode=preferred&{v}") } else { format!("{base}&{v}") } } } - DatabaseType::Postgres => value.trim_start_matches('?').to_string(), + DatabaseType::Postgres | DatabaseType::Redshift => value.trim_start_matches('?').to_string(), _ => value.trim_start_matches('?').to_string(), } } diff --git a/src/components/connection/ConnectionDialog.vue b/src/components/connection/ConnectionDialog.vue index 5d94b03c8..00110e2e4 100644 --- a/src/components/connection/ConnectionDialog.vue +++ b/src/components/connection/ConnectionDialog.vue @@ -9,8 +9,9 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { - Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue, -} from "@/components/ui/select"; + DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, + DropdownMenuLabel, +} from "@/components/ui/dropdown-menu"; import type { ConnectionConfig, DatabaseType } from "@/types/database"; import { useConnectionStore } from "@/stores/connectionStore"; import DatabaseIcon from "@/components/icons/DatabaseIcon.vue"; @@ -91,8 +92,13 @@ const driverProfiles: Record props.editConfig, (config) => { const isEditing = ref(false); watch(() => editingId.value, (v) => { isEditing.value = !!v; }); +const dbTypeMenuOpen = ref(false); + function onDbTypeChange(val: string) { customDriverName.value = ""; applyProfile(val, !!editingId.value); + dbTypeMenuOpen.value = false; } const iconTypeMap: Record = { @@ -178,6 +187,8 @@ const iconTypeMap: Record = { elasticsearch: "elasticsearch", mariadb: "mariadb", tidb: "tidb", oceanbase: "oceanbase", goldendb: "goldendb", opengauss: "opengauss", gaussdb: "gaussdb", kingbase: "kingbase", vastbase: "vastbase", + doris: "doris", starrocks: "starrocks", redshift: "redshift", + cockroachdb: "cockroachdb", tdengine: "tdengine", custom_mysql: "mysql", custom_postgres: "postgres", }; @@ -199,7 +210,10 @@ const mysqlCompat = [ { value: "tidb", label: "TiDB" }, { value: "oceanbase", label: "OceanBase" }, { value: "goldendb", label: "GoldenDB" }, - { value: "custom_mysql", label: "Custom MySQL-compatible" }, + { value: "doris", label: "Doris" }, + { value: "starrocks", label: "StarRocks" }, + { value: "tdengine", label: "TDengine" }, + { value: "custom_mysql", label: "Custom" }, ]; const pgCompat = [ @@ -207,7 +221,9 @@ const pgCompat = [ { value: "gaussdb", label: "GaussDB" }, { value: "kingbase", label: "KingBase" }, { value: "vastbase", label: "Vastbase" }, - { value: "custom_postgres", label: "Custom PostgreSQL-compatible" }, + { value: "redshift", label: "Redshift" }, + { value: "cockroachdb", label: "CockroachDB" }, + { value: "custom_postgres", label: "Custom" }, ]; watch(customDriverName, (value) => { @@ -295,42 +311,57 @@ watch([() => editingId.value, () => open.value], () => {
- + +
diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index 7ef23be1d..bd9c9847d 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -59,6 +59,7 @@ export default { sshPasswordPlaceholder: "Leave empty to use key", sshKeyPath: "Key Path", compatible: "Compatible", + mainstream: "Popular", color: "Color", colorNone: "No color", colorGreen: "Green", diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index c525ca203..c8c764385 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -61,6 +61,7 @@ export default { sshPasswordPlaceholder: "留空则使用密钥", sshKeyPath: "密钥路径", compatible: "兼容", + mainstream: "主流", color: "颜色", colorNone: "无颜色", colorGreen: "绿色", diff --git a/src/stores/connectionStore.ts b/src/stores/connectionStore.ts index b54758b96..ddbb172f3 100644 --- a/src/stores/connectionStore.ts +++ b/src/stores/connectionStore.ts @@ -42,6 +42,9 @@ export const useConnectionStore = defineStore("connection", () => { mongodb: "MongoDB", oracle: "Oracle", elasticsearch: "Elasticsearch", + doris: "Doris", + starrocks: "StarRocks", + redshift: "Redshift", }; return { ...config, diff --git a/src/types/database.ts b/src/types/database.ts index ceac231df..ad022b0d2 100644 --- a/src/types/database.ts +++ b/src/types/database.ts @@ -1,4 +1,4 @@ -export type DatabaseType = "mysql" | "postgres" | "sqlite" | "redis" | "duckdb" | "clickhouse" | "sqlserver" | "mongodb" | "oracle" | "elasticsearch"; +export type DatabaseType = "mysql" | "postgres" | "sqlite" | "redis" | "duckdb" | "clickhouse" | "sqlserver" | "mongodb" | "oracle" | "elasticsearch" | "doris" | "starrocks" | "redshift"; export interface ConnectionConfig { id: string;