fix(mongo): complete agent fallback for all connection paths

- Fix connect_db and test_connection to also fallback to agent when
  native driver fails with wire version error
- Route MongoDB agent through mongo_ops in schema.rs list_databases
- Update MongoDB legacy hint text to mention Driver Manager
This commit is contained in:
t8y2 2026-05-14 16:16:33 +08:00
parent 1e8ce6673f
commit 7faa9ec818
5 changed files with 58 additions and 12 deletions

View File

@ -3,6 +3,7 @@ use std::sync::Arc;
use crate::connection::{AppState, MysqlMode, PoolKind};
use crate::db;
use crate::models::connection::DatabaseType;
pub fn duckdb_query_tables(con: &duckdb::Connection) -> Result<Vec<db::TableInfo>, String> {
let mut stmt = con.prepare(
@ -136,6 +137,13 @@ pub async fn list_databases_core(state: &AppState, connection_id: &str) -> Resul
return db::sqlserver::list_databases(&mut client).await;
}
if let Some(client) = extract_agent(&connections, connection_id) {
let is_mongo =
state.configs.read().await.get(connection_id).is_some_and(|c| c.db_type == DatabaseType::MongoDb);
if is_mongo {
drop(connections);
let dbs = crate::mongo_ops::mongo_list_databases_core(state, connection_id).await?;
return Ok(dbs.into_iter().map(|name| db::DatabaseInfo { name }).collect());
}
drop(connections);
let mut client = client.lock().await;
return client.call("list_databases", serde_json::json!({})).await;

View File

@ -81,12 +81,29 @@ pub async fn test_connection(state: State<'_, Arc<AppState>>, config: Connection
DatabaseType::DuckDb => duckdb::Connection::open(&expand_tilde(&config.host))
.map(|_| "Connection successful".to_string())
.map_err(|e| e.to_string()),
DatabaseType::MongoDb => match db::mongo_driver::connect(&url).await {
Ok(client) => {
db::mongo_driver::test_connection(&client).await.map(|_| "Connection successful".to_string())
DatabaseType::MongoDb => {
let native_err = match db::mongo_driver::connect(&url).await {
Ok(client) => match db::mongo_driver::test_connection(&client).await {
Ok(()) => return Ok("Connection successful".to_string()),
Err(e) => e,
},
Err(e) => e,
};
if native_err.contains("wire version") {
let am = &state.agent_manager;
let mut client = am.spawn(&config.db_type, config.driver_profile.as_deref()).await?;
let params = serde_json::json!({ "connection": {
"host": host, "port": port,
"database": config.effective_database().unwrap_or(""),
"username": config.username, "password": config.password,
}});
client.call::<serde_json::Value>("connect", params).await?;
client.call::<serde_json::Value>("disconnect", serde_json::json!({})).await.ok();
Ok("Connection successful (via legacy driver)".to_string())
} else {
Err(native_err)
}
Err(e) => Err(e.to_string()),
},
}
DatabaseType::ClickHouse => {
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()) };
@ -170,9 +187,31 @@ pub async fn connect_db(state: State<'_, Arc<AppState>>, config: ConnectionConfi
PoolKind::DuckDb(std::sync::Arc::new(std::sync::Mutex::new(con)))
}
DatabaseType::MongoDb => {
let client = db::mongo_driver::connect(&url).await?;
db::mongo_driver::test_connection(&client).await?;
PoolKind::MongoDb(client)
let native_err = match db::mongo_driver::connect(&url).await {
Ok(client) => match db::mongo_driver::test_connection(&client).await {
Ok(()) => {
state.configs.write().await.insert(id.clone(), config);
state.connections.write().await.insert(id.clone(), PoolKind::MongoDb(client));
return Ok(id);
}
Err(e) => e,
},
Err(e) => e,
};
if native_err.contains("wire version") {
log::info!("Native MongoDB driver failed ({native_err}), falling back to agent driver");
let mut client =
state.agent_manager.spawn(&db_config.db_type, db_config.driver_profile.as_deref()).await?;
let params = serde_json::json!({ "connection": {
"host": host, "port": port,
"database": db_config.effective_database().unwrap_or(""),
"username": db_config.username, "password": db_config.password,
}});
client.call::<serde_json::Value>("connect", params).await?;
PoolKind::Agent(std::sync::Arc::new(tokio::sync::Mutex::new(client)))
} else {
return Err(native_err);
}
}
DatabaseType::ClickHouse => {
let username = if db_config.username.is_empty() { None } else { Some(db_config.username.clone()) };

View File

@ -179,7 +179,7 @@ export default {
dmCompatHint: "Requires DM8 ODBC driver installed on your system.",
dmDownload: "Download from Dameng",
mongoLegacyHint:
"For older MongoDB servers, enter authSource=admin&authMechanism=SCRAM-SHA-1 here; add directConnection=true only when needed for direct standalone connections.",
"MongoDB below 4.2 requires the MongoDB (Legacy) driver from Driver Manager; connections will switch automatically.",
compatible: "Compatible",
mainstream: "Popular",
color: "Color",

View File

@ -180,7 +180,7 @@ export default {
dmCompatHint: "Requiere el driver ODBC DM8 instalado en el sistema.",
dmDownload: "Descargar desde Dameng",
mongoLegacyHint:
"Para servidores MongoDB más antiguos, ingresa authSource=admin&authMechanism=SCRAM-SHA-1 aquí; agrega directConnection=true solo cuando sea necesario para conexiones directas a instancias independientes.",
"MongoDB inferior a 4.2 requiere el controlador MongoDB (Legacy) del Gestor de controladores; la conexión cambiará automáticamente.",
compatible: "Compatible",
mainstream: "Popular",
color: "Color",

View File

@ -176,8 +176,7 @@ export default {
jdbcPluginHint: "先安装 DBX JDBC 插件,再导入数据库厂商提供的 JDBC 驱动 JAR。",
dmCompatHint: "需要在系统上安装达梦 DM8 ODBC 驱动程序。",
dmDownload: "前往达梦官网下载",
mongoLegacyHint:
"连接旧版 MongoDB 时,可在此填写 authSource=admin&authMechanism=SCRAM-SHA-1直连单节点时可按需追加 directConnection=true。",
mongoLegacyHint: "MongoDB 4.2 以下版本需在驱动管理中安装 MongoDB (Legacy) 驱动,连接时将自动切换。",
compatible: "兼容",
mainstream: "主流",
color: "颜色",