diff --git a/src/components/sidebar/TreeItem.vue b/src/components/sidebar/TreeItem.vue
index e2bd2736bc..6606d83483 100644
--- a/src/components/sidebar/TreeItem.vue
+++ b/src/components/sidebar/TreeItem.vue
@@ -73,6 +73,7 @@ import {
FIELD_LINEAGE_SUPPORTED_TYPES,
TREE_SCHEMA_TYPES,
PG_LIKE_STRUCTURE_TYPES,
+ CREATE_DATABASE_SUPPORTED_TYPES,
isSchemaAware,
usesFetchFirst,
} from "@/lib/databaseCapabilities";
@@ -378,6 +379,13 @@ const showTruncateTableConfirm = ref(false);
const showDuplicateDialog = ref(false);
const duplicateTableName = ref("");
+const showCreateDatabaseDialog = ref(false);
+const createDatabaseName = ref("");
+const showDropDatabaseConfirm = ref(false);
+const showCreateSchemaDialog = ref(false);
+const createSchemaName = ref("");
+const showDropSchemaConfirm = ref(false);
+
const isTableNotView = computed(() => props.node.type === "table");
const supportsTruncate = computed(() => {
@@ -395,6 +403,26 @@ const canCreateTable = computed(() => {
);
});
+const canCreateDatabase = computed(() => {
+ const config = props.node.connectionId ? connectionStore.getConfig(props.node.connectionId) : undefined;
+ return props.node.type === "connection" && !!config && CREATE_DATABASE_SUPPORTED_TYPES.has(config.db_type);
+});
+
+const canDropDatabase = computed(() => {
+ const config = props.node.connectionId ? connectionStore.getConfig(props.node.connectionId) : undefined;
+ return props.node.type === "database" && !!config && CREATE_DATABASE_SUPPORTED_TYPES.has(config.db_type);
+});
+
+const canCreateSchema = computed(() => {
+ const config = props.node.connectionId ? connectionStore.getConfig(props.node.connectionId) : undefined;
+ return props.node.type === "database" && !!config && TREE_SCHEMA_TYPES.has(config.db_type);
+});
+
+const canDropSchema = computed(() => {
+ const config = props.node.connectionId ? connectionStore.getConfig(props.node.connectionId) : undefined;
+ return props.node.type === "schema" && !!config && TREE_SCHEMA_TYPES.has(config.db_type);
+});
+
function buildDropTableSql(): string {
return `DROP TABLE ${qualifiedTableName(props.node.label, props.node.schema)};`;
}
@@ -463,6 +491,93 @@ async function confirmTruncateTable() {
}
}
+function buildDropDatabaseSql(): string {
+ return `DROP DATABASE ${quoteIdent(props.node.label)};`;
+}
+
+function buildDropSchemaSql(): string {
+ const dbType = currentDatabaseType();
+ const name = quoteIdent(props.node.label);
+ if (dbType === "postgres" || dbType === "gaussdb") return `DROP SCHEMA ${name} CASCADE;`;
+ return `DROP SCHEMA ${name};`;
+}
+
+function openCreateDatabaseDialog() {
+ createDatabaseName.value = "";
+ showCreateDatabaseDialog.value = true;
+}
+
+async function confirmCreateDatabase() {
+ const node = props.node;
+ const name = createDatabaseName.value.trim();
+ if (!name || !node.connectionId) return;
+ showCreateDatabaseDialog.value = false;
+ try {
+ await connectionStore.ensureConnected(node.connectionId);
+ const sql = `CREATE DATABASE ${quoteIdent(name)};`;
+ await api.executeQuery(node.connectionId, "", sql);
+ toast(t("contextMenu.createDatabaseSuccess", { name }), 3000);
+ await connectionStore.loadDatabases(node.connectionId);
+ } catch (e: any) {
+ toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
+ }
+}
+
+function dropDatabase() {
+ showDropDatabaseConfirm.value = true;
+}
+
+async function confirmDropDatabase() {
+ const node = props.node;
+ if (!node.connectionId) return;
+ try {
+ await connectionStore.ensureConnected(node.connectionId);
+ await api.executeQuery(node.connectionId, "", buildDropDatabaseSql());
+ toast(t("contextMenu.dropDatabaseSuccess", { name: node.label }), 3000);
+ await connectionStore.loadDatabases(node.connectionId);
+ } catch (e: any) {
+ toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
+ }
+}
+
+function openCreateSchemaDialog() {
+ createSchemaName.value = "";
+ showCreateSchemaDialog.value = true;
+}
+
+async function confirmCreateSchema() {
+ const node = props.node;
+ const name = createSchemaName.value.trim();
+ if (!name || !node.connectionId || !node.database) return;
+ showCreateSchemaDialog.value = false;
+ try {
+ await connectionStore.ensureConnected(node.connectionId);
+ const sql = `CREATE SCHEMA ${quoteIdent(name)};`;
+ await api.executeQuery(node.connectionId, node.database, sql);
+ toast(t("contextMenu.createSchemaSuccess", { name }), 3000);
+ await connectionStore.loadSchemas(node.connectionId, node.database);
+ } catch (e: any) {
+ toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
+ }
+}
+
+function dropSchema() {
+ showDropSchemaConfirm.value = true;
+}
+
+async function confirmDropSchema() {
+ const node = props.node;
+ if (!node.connectionId || !node.database) return;
+ try {
+ await connectionStore.ensureConnected(node.connectionId);
+ await api.executeQuery(node.connectionId, node.database, buildDropSchemaSql());
+ toast(t("contextMenu.dropSchemaSuccess", { name: node.label }), 3000);
+ await connectionStore.loadSchemas(node.connectionId, node.database);
+ } catch (e: any) {
+ toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
+ }
+}
+
function duplicateStructure() {
duplicateTableName.value = `${props.node.label}_copy`;
showDuplicateDialog.value = true;
@@ -1163,6 +1278,9 @@ const isDragging = computed(() => dragState.active && dragState.draggedId === pr
{{ t("sqlFile.title") }}
+
+ {{ t("contextMenu.createDatabase") }}
+
@@ -1228,6 +1346,9 @@ const isDragging = computed(() => dragState.active && dragState.draggedId === pr
{{ t("contextMenu.createTable") }}
+
+ {{ t("contextMenu.createSchema") }}
+
{{ t("sqlFile.title") }}
@@ -1252,6 +1373,15 @@ const isDragging = computed(() => dragState.active && dragState.draggedId === pr
{{ t("contextMenu.exportDatabase") }}
+
+
+
+ {{ t("contextMenu.dropDatabase") }}
+
+
+ {{ t("contextMenu.dropSchema") }}
+
+
@@ -1438,4 +1568,60 @@ const isDragging = computed(() => dragState.active && dragState.draggedId === pr
+
+
+
+
+
+
+
+
diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts
index 49cde113ba..a3d5e2cb18 100644
--- a/src/i18n/locales/en.ts
+++ b/src/i18n/locales/en.ts
@@ -451,6 +451,22 @@ export default {
tableOperationFailed: "Operation failed: {message}",
duplicateNameTitle: "Duplicate Structure",
duplicateNamePlaceholder: "New table name",
+ createDatabase: "Create Database",
+ dropDatabase: "Drop Database",
+ confirmDropDatabaseTitle: "Drop Database",
+ confirmDropDatabaseMessage:
+ 'Are you sure you want to drop database "{name}"? This will permanently delete the database and all its data.',
+ createDatabaseSuccess: 'Database "{name}" created',
+ dropDatabaseSuccess: 'Database "{name}" dropped',
+ createDatabaseNamePlaceholder: "Database name",
+ createSchema: "Create Schema",
+ dropSchema: "Drop Schema",
+ confirmDropSchemaTitle: "Drop Schema",
+ confirmDropSchemaMessage:
+ 'Are you sure you want to drop schema "{name}"? This will permanently delete the schema and all its objects.',
+ createSchemaSuccess: 'Schema "{name}" created',
+ dropSchemaSuccess: 'Schema "{name}" dropped',
+ createSchemaNamePlaceholder: "Schema name",
},
tree: {
columns: "Columns",
diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts
index d872778797..f66a07a477 100644
--- a/src/i18n/locales/zh-CN.ts
+++ b/src/i18n/locales/zh-CN.ts
@@ -442,6 +442,20 @@ export default {
tableOperationFailed: "操作失败:{message}",
duplicateNameTitle: "复制表结构",
duplicateNamePlaceholder: "新表名",
+ createDatabase: "新建数据库",
+ dropDatabase: "删除数据库",
+ confirmDropDatabaseTitle: "删除数据库",
+ confirmDropDatabaseMessage: "确定要删除数据库「{name}」吗?这将永久删除该数据库及其所有数据。",
+ createDatabaseSuccess: "数据库「{name}」已创建",
+ dropDatabaseSuccess: "数据库「{name}」已删除",
+ createDatabaseNamePlaceholder: "数据库名称",
+ createSchema: "新建 Schema",
+ dropSchema: "删除 Schema",
+ confirmDropSchemaTitle: "删除 Schema",
+ confirmDropSchemaMessage: "确定要删除 Schema「{name}」吗?这将永久删除该 Schema 及其所有对象。",
+ createSchemaSuccess: "Schema「{name}」已创建",
+ dropSchemaSuccess: "Schema「{name}」已删除",
+ createSchemaNamePlaceholder: "Schema 名称",
},
tree: {
columns: "字段",
diff --git a/src/lib/databaseCapabilities.ts b/src/lib/databaseCapabilities.ts
index 8aa555a483..62080b4a30 100644
--- a/src/lib/databaseCapabilities.ts
+++ b/src/lib/databaseCapabilities.ts
@@ -52,6 +52,19 @@ export const TABLE_IMPORT_SUPPORTED_TYPES = new Set([
export const TABLE_STRUCTURE_SUPPORTED_TYPES = new Set(["mysql", "postgres", "sqlite", "sqlserver"]);
+export const CREATE_DATABASE_SUPPORTED_TYPES = new Set([
+ "mysql",
+ "postgres",
+ "sqlserver",
+ "clickhouse",
+ "oracle",
+ "dameng",
+ "gaussdb",
+ "doris",
+ "starrocks",
+ "redshift",
+]);
+
export const FIELD_LINEAGE_SUPPORTED_TYPES = new Set([
"mysql",
"postgres",