fix(mongodb): resolve per-database pool for dump restore and export

This commit is contained in:
Loc Nguyen authored and GitHub committed 2026-09-23 16:01:52 +08:00
1 parent 571eaf960b
commit 18f144f11c
3 files changed
+113 -11

No files matched your search

+6 -4
View File
@@ -406,10 +406,12 @@ fn command_cursor_id(cursor: &Document) -> Result<i64, String> {
async fn dump_client(state: &AppState, id: &str, database: &str) -> Result<DumpClient, String> {
metadata::validate_database(database)?;
state.get_or_create_pool(id, Some(database)).await?;
match state.pool_handle(id).await {
Some(PoolKind::MongoDb(client)) => Ok(DumpClient::Native(client.clone())),
Some(PoolKind::Agent(client)) => {
// Propagate pool resolution errors (e.g. connection establishment failures) instead of
// swallowing them into the generic message below, so users see the real cause.
let pool = crate::mongodb_import_export::mongo_pool_for_database(state, id, database).await?;
match pool {
PoolKind::MongoDb(client) => Ok(DumpClient::Native(client.clone())),
PoolKind::Agent(client) => {
// Check what every dump, restore, or preview shares up front, so an outdated
// agent is refused before any work starts rather than mid-operation. The find
// cursor only the dump's BSON export relies on is gated on that path instead.
@@ -1669,6 +1669,22 @@ fn progress(
}
}
/// Resolve the pool that serves `database` on this connection.
///
/// MongoDB pools are keyed `<connection id>:<database>`, so looking one up by the bare
/// connection id misses the pool `get_or_create_pool` just returned. Depending on what else the
/// app has opened, the bare key is either absent — "Not a MongoDB connection" on a perfectly good
/// connection — or holds a *different*, possibly already closed, pool, which surfaces later as
/// "Agent stdin not available". Always resolve through the key the pool was created under.
pub(crate) async fn mongo_pool_for_database(
state: &AppState,
connection_id: &str,
database: &str,
) -> Result<PoolKind, String> {
let pool_key = state.get_or_create_pool(connection_id, Some(database)).await?;
state.pool_handle(&pool_key).await.ok_or_else(|| "Not found".to_string())
}
async fn insert_documents_batch(
state: &AppState,
connection_id: &str,
@@ -1676,8 +1692,9 @@ async fn insert_documents_batch(
collection: &str,
documents: Vec<Document>,
) -> Result<MongoInsertOutcome, MongoImportIssue> {
let pool =
state.pool_handle(connection_id).await.ok_or_else(|| MongoImportIssue::new("CONNECTION", "Not found"))?;
let pool = mongo_pool_for_database(state, connection_id, database)
.await
.map_err(|error| MongoImportIssue::new("CONNECTION", error))?;
match &pool {
PoolKind::MongoDb(client) => {
insert_bson_documents(client, database, collection, documents).await.map_err(bulk_write_issue)
@@ -2339,8 +2356,7 @@ where
return Err("Export cancelled".to_string());
}
state.get_or_create_pool(&request.connection_id, Some(&request.database)).await?;
let pool = state.pool_handle(&request.connection_id).await.ok_or_else(|| "Not found".to_string())?;
let pool = mongo_pool_for_database(state, &request.connection_id, &request.database).await?;
match &pool {
PoolKind::MongoDb(_) | PoolKind::Agent(_) => {}
_ => return Err("Not a MongoDB connection".to_string()),
@@ -2420,7 +2436,7 @@ async fn count_export_documents(state: &AppState, request: &MongoExportRequest)
if request.filter.as_deref().is_some_and(|filter| !filter.trim().is_empty() && filter.trim() != "{}") {
return None;
}
let pool = state.pool_handle(&request.connection_id).await?;
let pool = mongo_pool_for_database(state, &request.connection_id, &request.database).await.ok()?;
match pool {
PoolKind::MongoDb(client) => mongo_driver::count_documents(
&client,
@@ -2457,7 +2473,7 @@ where
C: FnMut(&str) -> std::pin::Pin<Box<dyn std::future::Future<Output = bool> + Send>>,
F: FnMut(serde_json::Value) -> Result<(), String>,
{
let pool = state.pool_handle(&request.connection_id).await.ok_or_else(|| "Not found".to_string())?;
let pool = mongo_pool_for_database(state, &request.connection_id, &request.database).await?;
match pool {
PoolKind::MongoDb(client) => {
for_each_find_document(
@@ -2849,7 +2865,7 @@ where
if is_cancelled(&request.export_id).await {
return Err("Export cancelled".to_string());
}
let pool = state.pool_handle(&request.connection_id).await.ok_or_else(|| "Not found".to_string())?;
let pool = mongo_pool_for_database(state, &request.connection_id, &request.database).await?;
let file = File::create(temp).map_err(|error| error.to_string())?;
let buffered = BufWriter::new(file);
let mut writer = if request.gzip {