From 41edb3da91ab9f461622b24ea1e492d1dc17b741 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9E=97=E5=89=91=E5=87=9B?= <2993354@qq.com>
Date: Sat, 20 Jun 2026 22:22:04 +0800
Subject: [PATCH] feat(mongo): add database and collection deletion
---
.../src/components/sidebar/TreeItem.vue | 87 ++++++++++++++++++-
apps/desktop/src/i18n/locales/en.ts | 4 +
apps/desktop/src/i18n/locales/es.ts | 4 +
apps/desktop/src/i18n/locales/it.ts | 4 +
apps/desktop/src/i18n/locales/ja.ts | 4 +
apps/desktop/src/i18n/locales/pt-BR.ts | 4 +
apps/desktop/src/i18n/locales/zh-CN.ts | 4 +
apps/desktop/src/i18n/locales/zh-TW.ts | 4 +
apps/desktop/src/lib/api.ts | 3 +
apps/desktop/src/lib/http.ts | 12 +++
apps/desktop/src/lib/tauri.ts | 12 +++
crates/dbx-core/src/db/mongo_driver.rs | 28 ++++++
crates/dbx-core/src/mongo_ops.rs | 35 ++++++++
crates/dbx-web/src/main.rs | 3 +
crates/dbx-web/src/routes/mongo.rs | 41 +++++++++
src-tauri/src/commands/mongo_cmd.rs | 31 +++++++
src-tauri/src/lib.rs | 3 +
17 files changed, 282 insertions(+), 1 deletion(-)
diff --git a/apps/desktop/src/components/sidebar/TreeItem.vue b/apps/desktop/src/components/sidebar/TreeItem.vue
index 14c10c5871..9becd85522 100644
--- a/apps/desktop/src/components/sidebar/TreeItem.vue
+++ b/apps/desktop/src/components/sidebar/TreeItem.vue
@@ -747,6 +747,14 @@ function requestDeleteSelectedNode(): boolean {
dropDatabase();
return true;
}
+ if (canDropMongoDatabase.value) {
+ dropDatabase();
+ return true;
+ }
+ if (canDropMongoCollection.value) {
+ dropMongoCollection();
+ return true;
+ }
if (canDropSchema.value) {
dropSchema();
return true;
@@ -1276,6 +1284,8 @@ const createDatabaseCharset = ref("utf8mb4");
const createDatabaseCollation = ref("utf8mb4_unicode_ci");
const showDropDatabaseConfirm = ref(false);
const dropDatabaseLoading = ref(false);
+const showDropMongoCollectionConfirm = ref(false);
+const dropMongoCollectionLoading = ref(false);
const showFlushRedisDbConfirm = ref(false);
const showCreateSchemaDialog = ref(false);
const createSchemaName = ref("");
@@ -1745,7 +1755,7 @@ const canCreateTable = computed(() => {
const canCreateDatabase = computed(() => {
const config = props.node.connectionId ? connectionStore.getConfig(props.node.connectionId) : undefined;
- return props.node.type === "connection" && (supportsDatabaseCreation(config?.db_type) || config?.db_type === "duckdb");
+ return props.node.type === "connection" && (supportsDatabaseCreation(config?.db_type) || config?.db_type === "duckdb" || (config?.db_type === "mongodb" && config.driver_profile !== "mongodb-legacy"));
});
const isDuckDbConnection = computed(() => {
@@ -1763,6 +1773,16 @@ const canDropDatabase = computed(() => {
return props.node.type === "database" && !isSqlServerLinkedNode(props.node) && supportsDatabaseCreation(config?.db_type);
});
+const canDropMongoDatabase = computed(() => {
+ const config = props.node.connectionId ? connectionStore.getConfig(props.node.connectionId) : undefined;
+ return props.node.type === "mongo-db" && !!props.node.database && config?.driver_profile !== "mongodb-legacy";
+});
+
+const canDropMongoCollection = computed(() => {
+ const config = props.node.connectionId ? connectionStore.getConfig(props.node.connectionId) : undefined;
+ return props.node.type === "mongo-collection" && !!props.node.database && config?.driver_profile !== "mongodb-legacy";
+});
+
const canCreateSchema = computed(() => {
const config = props.node.connectionId ? connectionStore.getConfig(props.node.connectionId) : undefined;
return props.node.type === "database" && usesTreeSchemaMode(effectiveDatabaseTypeForConnection(config)) && !connectionUsesDatabaseObjectTreeMode(config);
@@ -1857,6 +1877,10 @@ async function confirmTruncateTable() {
}
async function refreshDropDatabasePreviewSql() {
+ if (props.node.type === "mongo-db") {
+ dropDatabasePreviewSql.value = `db.getSiblingDB(${JSON.stringify(props.node.label)}).dropDatabase();`;
+ return;
+ }
dropDatabasePreviewSql.value = "";
dropDatabasePreviewSql.value = await buildDropDatabaseSql({
databaseType: currentDatabaseType(),
@@ -1939,6 +1963,12 @@ async function confirmCreateDatabase() {
try {
await connectionStore.ensureConnected(node.connectionId);
const config = connectionStore.getConfig(node.connectionId);
+ if (config?.db_type === "mongodb") {
+ await api.mongoCreateDatabase(node.connectionId, name);
+ toast(t("contextMenu.createDatabaseSuccess", { name }), 3000);
+ await connectionStore.loadMongoDatabases(node.connectionId);
+ return;
+ }
const sql = await buildCreateDatabaseSql({
databaseType: config?.db_type,
driverProfile: config?.driver_profile,
@@ -1960,6 +1990,11 @@ function dropDatabase() {
showDropDatabaseConfirm.value = true;
}
+function dropMongoCollection() {
+ dropMongoCollectionLoading.value = false;
+ showDropMongoCollectionConfirm.value = true;
+}
+
function flushRedisDb() {
showFlushRedisDbConfirm.value = true;
}
@@ -1988,6 +2023,13 @@ async function confirmDropDatabase() {
dropDatabaseLoading.value = true;
try {
await connectionStore.ensureConnected(node.connectionId);
+ if (node.type === "mongo-db" && node.database) {
+ await api.mongoDropDatabase(node.connectionId, node.database);
+ toast(t("contextMenu.dropDatabaseSuccess", { name: node.label }), 3000);
+ await connectionStore.loadMongoDatabases(node.connectionId);
+ showDropDatabaseConfirm.value = false;
+ return;
+ }
const sql =
dropDatabasePreviewSql.value ||
(await buildDropDatabaseSql({
@@ -2005,6 +2047,23 @@ async function confirmDropDatabase() {
}
}
+async function confirmDropMongoCollection() {
+ const node = props.node;
+ if (node.type !== "mongo-collection" || !node.connectionId || !node.database || dropMongoCollectionLoading.value) return;
+ dropMongoCollectionLoading.value = true;
+ try {
+ await connectionStore.ensureConnected(node.connectionId);
+ await api.mongoDropCollection(node.connectionId, node.database, node.label);
+ toast(t("contextMenu.dropCollectionSuccess", { name: node.label }), 3000);
+ await connectionStore.loadMongoCollections(node.connectionId, node.database);
+ showDropMongoCollectionConfirm.value = false;
+ } catch (e: any) {
+ toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
+ } finally {
+ dropMongoCollectionLoading.value = false;
+ }
+}
+
function openCreateSchemaDialog() {
createSchemaName.value = "";
showCreateSchemaDialog.value = true;
@@ -3263,6 +3322,22 @@ function treeItemMenuItems(): ContextMenuItem[] {
items.push({ label: "", separator: true });
items.push({ label: t("redis.flushDb"), action: flushRedisDb, icon: Eraser, variant: "destructive" as const });
}
+ if (canDropMongoDatabase.value) {
+ items.push({ label: "", separator: true });
+ items.push({ label: t("contextMenu.dropDatabase"), action: dropDatabase, icon: Trash2, shortcut: shortcutDelete, variant: "destructive" as const });
+ }
+ return items;
+ }
+
+ if (node.type === "mongo-collection") {
+ items.push({ label: t("contextMenu.copyName"), action: copyName, icon: Copy, shortcut: shortcutCopyName.value });
+ items.push({ label: "", separator: true });
+ items.push({ label: t("contextMenu.viewData"), action: toggle, icon: TableProperties });
+ items.push({ label: t("contextMenu.newQuery"), action: newQuery, icon: TerminalSquare });
+ if (canDropMongoCollection.value) {
+ items.push({ label: "", separator: true });
+ items.push({ label: t("contextMenu.dropCollection"), action: dropMongoCollection, icon: Trash2, shortcut: shortcutDelete, variant: "destructive" as const });
+ }
return items;
}
@@ -3779,6 +3854,16 @@ function treeItemMenuItems(): ContextMenuItem[] {
@confirm="confirmDropDatabase"
/>
+
+