use std::future::Future; use std::sync::Arc; use tauri::State; use crate::commands::connection::{ensure_connection_writable, AppState}; use dbx_core::db::mongo_driver::MongoDocumentResult; #[tauri::command] pub fn mongo_parse_shell_command(source: String) -> Result { dbx_core::mongo_shell::parse(&source) } async fn run_cancellable(state: &Arc, execution_id: Option, future: F) -> Result where F: Future>, { let registered_query = execution_id.as_ref().filter(|id| !id.trim().is_empty()).map(|id| state.running_queries.register(id.clone())); if let Some(query) = registered_query.as_ref() { let token = query.token(); tokio::select! { biased; _ = token.cancelled() => Err(dbx_core::query::canceled_error()), result = future => result, } } else { future.await } } #[tauri::command] pub async fn mongo_list_databases( state: State<'_, Arc>, connection_id: String, ) -> Result, String> { dbx_core::mongo_ops::mongo_list_databases_core(&state, &connection_id).await } #[tauri::command] pub async fn mongo_list_collections( state: State<'_, Arc>, connection_id: String, database: String, ) -> Result, String> { dbx_core::mongo_ops::mongo_list_collections_core(&state, &connection_id, &database).await } #[tauri::command] pub async fn vector_collection_detail( state: State<'_, Arc>, connection_id: String, database: String, collection: String, ) -> Result { dbx_core::schema::get_vector_collection_detail_core(&state, &connection_id, &database, &collection).await } #[tauri::command] pub async fn mongo_create_database( state: State<'_, Arc>, connection_id: String, database: String, ) -> Result<(), String> { ensure_connection_writable(&state, &connection_id, "Create database").await?; dbx_core::mongo_ops::mongo_create_database_core(&state, &connection_id, &database).await } #[tauri::command] pub async fn mongo_drop_database( state: State<'_, Arc>, connection_id: String, database: String, ) -> Result<(), String> { ensure_connection_writable(&state, &connection_id, "Drop database").await?; dbx_core::mongo_ops::mongo_drop_database_core(&state, &connection_id, &database).await } #[tauri::command] pub async fn mongo_drop_collection( state: State<'_, Arc>, connection_id: String, database: String, collection: String, ) -> Result<(), String> { ensure_connection_writable(&state, &connection_id, "Drop collection").await?; dbx_core::mongo_ops::mongo_drop_collection_core(&state, &connection_id, &database, &collection).await } #[tauri::command] pub async fn mongo_rename_collection( state: State<'_, Arc>, connection_id: String, database: String, collection: String, new_name: String, ) -> Result<(), String> { ensure_connection_writable(&state, &connection_id, "Rename collection").await?; dbx_core::mongo_ops::mongo_rename_collection_core(&state, &connection_id, &database, &collection, &new_name).await } #[tauri::command] #[allow(clippy::too_many_arguments)] pub async fn mongo_find_documents( state: State<'_, Arc>, connection_id: String, database: String, collection: String, skip: u64, limit: i64, filter: Option, projection: Option, sort: Option, execution_id: Option, mcp_request: Option, ) -> Result { if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_read_allowed_by_id(state.inner(), &connection_id, &database).await?; } crate::commands::document_cmd::document_find_documents( state, connection_id, database, collection, skip, limit, filter, projection, sort, execution_id, ) .await } #[tauri::command] #[allow(clippy::too_many_arguments)] pub async fn mongo_find_one( state: State<'_, Arc>, connection_id: String, database: String, collection: String, filter: Option, projection: Option, options: Option, execution_id: Option, mcp_request: Option, ) -> Result { let app = state.inner().clone(); if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_read_allowed_by_id(&app, &connection_id, &database).await?; } run_cancellable( &app, execution_id, dbx_core::mongo_ops::mongo_find_one_core( &app, &connection_id, &database, &collection, filter.as_deref(), projection.as_deref(), options.as_deref(), ), ) .await } #[tauri::command] pub async fn mongo_count_documents( state: State<'_, Arc>, connection_id: String, database: String, collection: String, filter: Option, mode: Option, execution_id: Option, mcp_request: Option, ) -> Result { let app = state.inner().clone(); if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_read_allowed_by_id(&app, &connection_id, &database).await?; } crate::commands::document_cmd::run_cancellable( &app, execution_id, dbx_core::mongo_ops::mongo_count_documents_core( &app, &connection_id, &database, &collection, filter.as_deref(), mode.as_deref(), ), ) .await } #[tauri::command] pub async fn mongo_server_version( state: State<'_, Arc>, connection_id: String, database: String, execution_id: Option, mcp_request: Option, ) -> Result { let app = state.inner().clone(); if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_read_allowed_by_id(&app, &connection_id, &database).await?; } run_cancellable(&app, execution_id, dbx_core::mongo_ops::mongo_server_version_core(&app, &connection_id, &database)) .await } #[tauri::command] pub async fn mongo_collection_stats( state: State<'_, Arc>, connection_id: String, database: String, collection: String, scale: Option, execution_id: Option, mcp_request: Option, ) -> Result { let app = state.inner().clone(); if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_read_allowed_by_id(&app, &connection_id, &database).await?; } run_cancellable( &app, execution_id, dbx_core::mongo_ops::mongo_collection_stats_core(&app, &connection_id, &database, &collection, scale), ) .await } #[tauri::command] pub async fn mongo_aggregate_documents( state: State<'_, Arc>, connection_id: String, database: String, collection: String, pipeline_json: String, max_rows: Option, options_json: Option, execution_id: Option, mcp_request: Option, ) -> Result { let app = state.inner().clone(); if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_mongo_aggregate_allowed_by_id( &app, &connection_id, &database, &pipeline_json, ) .await?; } run_cancellable( &app, execution_id, dbx_core::mongo_ops::mongo_aggregate_documents_core( &app, &connection_id, &database, &collection, &pipeline_json, max_rows, options_json.as_deref(), ), ) .await } #[tauri::command] pub async fn mongo_distinct( state: State<'_, Arc>, connection_id: String, database: String, collection: String, field: String, filter: Option, execution_id: Option, mcp_request: Option, ) -> Result { let app = state.inner().clone(); if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_read_allowed_by_id(&app, &connection_id, &database).await?; } run_cancellable( &app, execution_id, dbx_core::mongo_ops::mongo_distinct_core( &app, &connection_id, &database, &collection, &field, filter.as_deref(), ), ) .await } #[tauri::command] pub async fn mongo_create_index( state: State<'_, Arc>, connection_id: String, database: String, collection: String, keys_json: String, options_json: Option, mcp_request: Option, ) -> Result { if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_dangerous_write_allowed_by_id( state.inner(), &connection_id, &database, "Create index", ) .await?; } ensure_connection_writable(&state, &connection_id, "Create index").await?; let name = dbx_core::mongo_ops::mongo_create_index_core( &state, &connection_id, &database, &collection, &keys_json, options_json.as_deref(), ) .await?; Ok(serde_json::json!({ "name": name })) } #[tauri::command] pub async fn mongo_drop_indexes( state: State<'_, Arc>, connection_id: String, database: String, collection: String, indexes_json: Option, single: bool, mcp_request: Option, ) -> Result { if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_dangerous_write_allowed_by_id( state.inner(), &connection_id, &database, "Drop indexes", ) .await?; } ensure_connection_writable(&state, &connection_id, "Drop indexes").await?; dbx_core::mongo_ops::mongo_drop_indexes_core( &state, &connection_id, &database, &collection, indexes_json.as_deref(), single, ) .await } #[tauri::command] pub async fn mongo_insert_document( state: State<'_, Arc>, connection_id: String, database: String, collection: String, doc_json: String, routing: Option, ) -> Result { crate::commands::document_cmd::document_insert_document( state, connection_id, database, collection, doc_json, routing, ) .await } #[tauri::command] pub async fn mongo_insert_documents( state: State<'_, Arc>, connection_id: String, database: String, collection: String, docs_json: String, mcp_request: Option, ) -> Result { if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_write_allowed_by_id(state.inner(), &connection_id, &database, "Insert") .await?; } ensure_connection_writable(&state, &connection_id, "Insert").await?; dbx_core::mongo_ops::mongo_insert_documents_core(&state, &connection_id, &database, &collection, &docs_json).await } #[tauri::command] pub async fn mongo_update_document( state: State<'_, Arc>, connection_id: String, database: String, collection: String, id: String, doc_json: String, routing: Option, ) -> Result { crate::commands::document_cmd::document_update_document( state, connection_id, database, collection, id, doc_json, routing, ) .await } #[tauri::command] pub async fn mongo_update_documents( state: State<'_, Arc>, connection_id: String, database: String, collection: String, filter_json: String, update_json: String, many: bool, options_json: Option, mcp_request: Option, ) -> Result { if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_mongo_filtered_write_allowed_by_id( state.inner(), &connection_id, &database, "Update", &filter_json, ) .await?; } ensure_connection_writable(&state, &connection_id, "Update").await?; dbx_core::mongo_ops::mongo_update_documents_core( &state, &connection_id, &database, &collection, &filter_json, &update_json, many, options_json.as_deref(), ) .await } #[tauri::command] pub async fn mongo_delete_document( state: State<'_, Arc>, connection_id: String, database: String, collection: String, id: String, routing: Option, ) -> Result { crate::commands::document_cmd::document_delete_document( state, connection_id, database, collection, id, routing, None, ) .await } #[tauri::command] pub async fn mongo_delete_documents( state: State<'_, Arc>, connection_id: String, database: String, collection: String, filter_json: String, many: bool, mcp_request: Option, ) -> Result { if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_mongo_filtered_write_allowed_by_id( state.inner(), &connection_id, &database, "Delete", &filter_json, ) .await?; } ensure_connection_writable(&state, &connection_id, "Delete").await?; dbx_core::mongo_ops::mongo_delete_documents_core(&state, &connection_id, &database, &collection, &filter_json, many) .await } #[tauri::command] pub async fn mongo_find_one_and_update( state: State<'_, Arc>, connection_id: String, database: String, collection: String, filter_json: String, update_json: String, options_json: Option, mcp_request: Option, ) -> Result { if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_mongo_filtered_write_allowed_by_id( state.inner(), &connection_id, &database, "Update", &filter_json, ) .await?; } ensure_connection_writable(&state, &connection_id, "Update").await?; dbx_core::mongo_ops::mongo_find_one_and_update_core( &state, &connection_id, &database, &collection, &filter_json, &update_json, options_json.as_deref(), ) .await } #[tauri::command] pub async fn mongo_find_one_and_replace( state: State<'_, Arc>, connection_id: String, database: String, collection: String, filter_json: String, replacement_json: String, options_json: Option, mcp_request: Option, ) -> Result { if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_mongo_filtered_write_allowed_by_id( state.inner(), &connection_id, &database, "Update", &filter_json, ) .await?; } ensure_connection_writable(&state, &connection_id, "Update").await?; dbx_core::mongo_ops::mongo_find_one_and_replace_core( &state, &connection_id, &database, &collection, &filter_json, &replacement_json, options_json.as_deref(), ) .await } #[tauri::command] pub async fn mongo_find_one_and_delete( state: State<'_, Arc>, connection_id: String, database: String, collection: String, filter_json: String, options_json: Option, mcp_request: Option, ) -> Result { if mcp_request == Some(true) { crate::commands::mcp_bridge::ensure_mcp_mongo_filtered_write_allowed_by_id( state.inner(), &connection_id, &database, "Delete", &filter_json, ) .await?; } ensure_connection_writable(&state, &connection_id, "Delete").await?; dbx_core::mongo_ops::mongo_find_one_and_delete_core( &state, &connection_id, &database, &collection, &filter_json, options_json.as_deref(), ) .await }