From 793c244d401697e09e821c8ad6c0e4b032f10c30 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Fri, 15 May 2026 14:47:20 +0800 Subject: [PATCH] feat(connection): auto-generate name when left empty Allow saving connections without a name by generating one in the format `{DbType}_{random4chars}` (e.g. Neo4j_a3f2). Update placeholder text to inform users about auto-generation. --- crates/dbx-core/src/schema.rs | 71 +++++++++++++++++++ .../connection/ConnectionDialog.vue | 10 ++- src/i18n/locales/en.ts | 2 +- src/i18n/locales/es.ts | 2 +- src/i18n/locales/zh-CN.ts | 2 +- 5 files changed, 83 insertions(+), 4 deletions(-) diff --git a/crates/dbx-core/src/schema.rs b/crates/dbx-core/src/schema.rs index d95ada8869..490804f953 100644 --- a/crates/dbx-core/src/schema.rs +++ b/crates/dbx-core/src/schema.rs @@ -813,6 +813,77 @@ mod object_source_tests { } } +#[cfg(test)] +mod ddl_tests { + use super::*; + + #[test] + fn detects_unknown_agent_get_table_ddl_method_errors() { + assert!(is_unknown_agent_method_error( + "Agent RPC error (-1): Unknown method: get_table_ddl. recent stderr: ..." + )); + assert!(!is_unknown_agent_method_error("Agent RPC error (-1): permission denied")); + } + + #[test] + fn builds_postgres_like_table_ddl_from_agent_metadata() { + let columns = vec![ + db::ColumnInfo { + name: "id".to_string(), + data_type: "integer".to_string(), + is_nullable: false, + column_default: Some("nextval('departments_id_seq'::regclass)".to_string()), + is_primary_key: true, + extra: None, + comment: None, + numeric_precision: None, + numeric_scale: None, + character_maximum_length: None, + }, + db::ColumnInfo { + name: "name".to_string(), + data_type: "varchar(128)".to_string(), + is_nullable: false, + column_default: None, + is_primary_key: false, + extra: None, + comment: None, + numeric_precision: None, + numeric_scale: None, + character_maximum_length: None, + }, + ]; + let indexes = vec![db::IndexInfo { + name: "idx_departments_name".to_string(), + columns: vec!["name".to_string()], + is_unique: true, + is_primary: false, + filter: None, + index_type: Some("btree".to_string()), + included_columns: None, + comment: None, + }]; + let fkeys = vec![db::ForeignKeyInfo { + name: "fk_departments_parent".to_string(), + column: "parent_id".to_string(), + ref_table: "departments".to_string(), + ref_column: "id".to_string(), + }]; + + let ddl = build_postgres_like_table_ddl("public", "departments", &columns, &indexes, &fkeys); + + assert!(ddl.contains("CREATE TABLE \"public\".\"departments\"")); + assert!(ddl.contains("\"id\" integer NOT NULL DEFAULT nextval('departments_id_seq'::regclass)")); + assert!(ddl.contains("PRIMARY KEY (\"id\")")); + assert!(ddl.contains( + "CONSTRAINT \"fk_departments_parent\" FOREIGN KEY (\"parent_id\") REFERENCES \"departments\"(\"id\")" + )); + assert!(ddl.contains( + "CREATE UNIQUE INDEX \"idx_departments_name\" ON \"public\".\"departments\" USING btree (\"name\");" + )); + } +} + pub async fn mysql_ddl(pool: &sqlx::mysql::MySqlPool, table: &str) -> Result { use sqlx::Row; let sql = format!("SHOW CREATE TABLE `{}`", table.replace('`', "``")); diff --git a/src/components/connection/ConnectionDialog.vue b/src/components/connection/ConnectionDialog.vue index 9a519bc71b..85b6a27360 100644 --- a/src/components/connection/ConnectionDialog.vue +++ b/src/components/connection/ConnectionDialog.vue @@ -515,8 +515,17 @@ async function testConnection() { } } +function generateConnectionName(): string { + const label = selectedProfile().label; + const rand = Math.random().toString(36).slice(2, 6); + return `${label}_${rand}`; +} + function connectionConfigForSubmit(id: string): ConnectionConfig { const config: ConnectionConfig = { ...form.value, id }; + if (!config.name?.trim()) { + config.name = generateConnectionName(); + } const sshTimeout = Number(config.ssh_connect_timeout_secs); config.ssh_connect_timeout_secs = Number.isFinite(sshTimeout) && sshTimeout > 0 ? sshTimeout : 5; const proxyPort = Number(config.proxy_port); @@ -1431,7 +1440,6 @@ function openExternalUrl(url: string) { @click="save" :disabled=" isSaving || - !form.name || (!form.host && !(mongoUseUrl && form.connection_string) && !(form.db_type === 'jdbc' && form.connection_string)) diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index 1cf1f69afa..a2c12b2c26 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -93,7 +93,7 @@ export default { connection: { title: "New Connection", name: "Name", - namePlaceholder: "My Database", + namePlaceholder: "Connection name, auto-generated if empty", type: "Type", host: "Host", filePath: "File Path", diff --git a/src/i18n/locales/es.ts b/src/i18n/locales/es.ts index d3b54d5068..c25c01978f 100644 --- a/src/i18n/locales/es.ts +++ b/src/i18n/locales/es.ts @@ -93,7 +93,7 @@ export default { connection: { title: "Nueva conexión", name: "Nombre", - namePlaceholder: "Mi base de datos", + namePlaceholder: "Nombre de conexión, se genera automáticamente si está vacío", type: "Tipo", host: "Host", filePath: "Ruta del archivo", diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index 8f16713bf1..bb8e3986a0 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -92,7 +92,7 @@ export default { connection: { title: "新建连接", name: "名称", - namePlaceholder: "我的数据库", + namePlaceholder: "连接名称,留空则自动生成", type: "类型", host: "主机", filePath: "文件路径",