diff --git a/apps/desktop/src/components/sidebar/TreeItem.vue b/apps/desktop/src/components/sidebar/TreeItem.vue
index db9d9bc729..305ed8a680 100644
--- a/apps/desktop/src/components/sidebar/TreeItem.vue
+++ b/apps/desktop/src/components/sidebar/TreeItem.vue
@@ -102,15 +102,19 @@ import {
buildDropObjectSql,
buildDropSchemaSql,
buildDropTableSql,
+ buildDropTableChildObjectSql,
buildDuplicateTableStructureSql,
buildEmptyTableSql,
buildTruncateTableSql,
+ type DropTableChildObjectSqlOptions,
type DropObjectSqlOptions,
+ type TableChildObjectType,
type TableAdminSqlOptions,
} from "@/lib/dbAdminSql";
import { buildRenameObjectSql, supportsObjectRename, type RenameableObjectType } from "@/lib/objectRenameSql";
import { buildRoutineRenameObjectSourceStatements, supportsSourceBackedRoutineRename } from "@/lib/objectSourceEditor";
import { buildViewDdl } from "@/lib/viewDdl";
+import { getTableStructureCapabilities } from "@/lib/tableStructureCapabilities";
import { hexToRgba } from "@/lib/color";
import { focusSidebarRenameInput } from "@/lib/sidebarRenameFocus";
import { hasTreeNodeDatabaseContext } from "@/lib/treeNodeContext";
@@ -450,6 +454,12 @@ function isEditableShortcutTarget(target: EventTarget | null): boolean {
function onKeydown(event: KeyboardEvent) {
if (!isSelected.value || isEditableShortcutTarget(event.target)) return;
+ if (!event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey && isDeleteTreeNodeShortcut(event)) {
+ if (!requestDropSelectedNode()) return;
+ event.preventDefault();
+ event.stopPropagation();
+ return;
+ }
const action = sidebarSelectionCopyAction(event);
if (action !== "copy-name") return;
event.preventDefault();
@@ -457,6 +467,10 @@ function onKeydown(event: KeyboardEvent) {
copyName();
}
+function isDeleteTreeNodeShortcut(event: KeyboardEvent): boolean {
+ return event.key === "Delete" || event.key === "Backspace";
+}
+
function onDoubleClick() {
const action = treeNodeRowDoubleClickAction(
props.node.type,
@@ -704,6 +718,7 @@ async function duplicateConnection() {
// --- Table Management Operations ---
const showDropTableConfirm = ref(false);
+const showDropTableChildObjectConfirm = ref(false);
const showEmptyTableConfirm = ref(false);
const showTruncateTableConfirm = ref(false);
const showRenameObjectDialog = ref(false);
@@ -714,6 +729,7 @@ const dropTablePreviewSql = ref("");
const emptyTablePreviewSql = ref("");
const truncateTablePreviewSql = ref("");
const dropObjectPreviewSql = ref("");
+const dropTableChildObjectPreviewSql = ref("");
const dropDatabasePreviewSql = ref("");
const dropSchemaPreviewSql = ref("");
const showDuplicateDialog = ref(false);
@@ -735,21 +751,114 @@ const showProcedureExecutionConfirm = ref(false);
function dropObjectSqlOptions(): DropObjectSqlOptions | null {
const node = props.node;
- if (node.type !== "procedure" && node.type !== "function") return null;
+ if (node.type !== "view" && node.type !== "procedure" && node.type !== "function") return null;
return {
databaseType: currentDatabaseType(),
- objectType: node.type === "procedure" ? "PROCEDURE" : "FUNCTION",
+ objectType: node.type === "view" ? "VIEW" : node.type === "procedure" ? "PROCEDURE" : "FUNCTION",
schema: node.schema,
name: node.label,
};
}
+function tableChildDropObjectType(type: TreeNodeType): TableChildObjectType | null {
+ if (type === "column") return "COLUMN";
+ if (type === "index") return "INDEX";
+ if (type === "fkey") return "FOREIGN_KEY";
+ if (type === "trigger") return "TRIGGER";
+ return null;
+}
+
+function tableChildDropObjectName(node: TreeNode): string {
+ if (node.type === "column")
+ return node.meta && "name" in node.meta ? node.meta.name : node.label.replace(/\s+\(.+\)$/, "");
+ if (node.type === "index")
+ return node.meta && "name" in node.meta ? node.meta.name : node.label.replace(/\s+\(.+\)$/, "");
+ if (node.type === "fkey") return node.meta && "name" in node.meta ? node.meta.name : node.label;
+ if (node.type === "trigger")
+ return node.meta && "name" in node.meta ? node.meta.name : node.label.replace(/\s+\(.+\)$/, "");
+ return node.label;
+}
+
+function dropTableChildObjectSqlOptions(): DropTableChildObjectSqlOptions | null {
+ const node = props.node;
+ const objectType = tableChildDropObjectType(node.type);
+ if (!objectType || !node.tableName) return null;
+ const name = tableChildDropObjectName(node).trim();
+ if (!name) return null;
+ return {
+ databaseType: currentDatabaseType(),
+ objectType,
+ schema: node.schema,
+ tableName: node.tableName,
+ name,
+ };
+}
+
+const canDropTableChildObject = computed(() => {
+ const options = dropTableChildObjectSqlOptions();
+ if (!options) return false;
+ const capabilities = getTableStructureCapabilities(currentDatabaseType());
+ if (options.objectType === "COLUMN") return capabilities.dropColumn;
+ if (options.objectType === "INDEX") return capabilities.dropIndex;
+ return true;
+});
+
+function dropObjectMenuLabel(): string {
+ if (props.node.type === "view") return t("contextMenu.dropView");
+ if (props.node.type === "procedure") return t("contextMenu.dropProcedure");
+ if (props.node.type === "function") return t("contextMenu.dropFunction");
+ return t("contextMenu.dropObject");
+}
+
+function dropObjectConfirmTitle(): string {
+ if (props.node.type === "view") return t("contextMenu.confirmDropViewTitle");
+ if (props.node.type === "procedure") return t("contextMenu.confirmDropProcedureTitle");
+ if (props.node.type === "function") return t("contextMenu.confirmDropFunctionTitle");
+ return t("contextMenu.confirmDropObjectTitle");
+}
+
+function dropObjectConfirmMessage(): string {
+ if (props.node.type === "view") return t("contextMenu.confirmDropViewMessage", { name: props.node.label });
+ if (props.node.type === "procedure") return t("contextMenu.confirmDropProcedureMessage", { name: props.node.label });
+ if (props.node.type === "function") return t("contextMenu.confirmDropFunctionMessage", { name: props.node.label });
+ return t("contextMenu.confirmDropObjectMessage", { name: props.node.label });
+}
+
+function dropTableChildObjectMenuLabel(): string {
+ if (props.node.type === "column") return t("contextMenu.dropColumn");
+ if (props.node.type === "index") return t("contextMenu.dropIndex");
+ if (props.node.type === "fkey") return t("contextMenu.dropForeignKey");
+ if (props.node.type === "trigger") return t("contextMenu.dropTrigger");
+ return t("contextMenu.dropObject");
+}
+
+function dropTableChildObjectConfirmTitle(): string {
+ if (props.node.type === "column") return t("contextMenu.confirmDropColumnTitle");
+ if (props.node.type === "index") return t("contextMenu.confirmDropIndexTitle");
+ if (props.node.type === "fkey") return t("contextMenu.confirmDropForeignKeyTitle");
+ if (props.node.type === "trigger") return t("contextMenu.confirmDropTriggerTitle");
+ return t("contextMenu.confirmDropObjectTitle");
+}
+
+function dropTableChildObjectConfirmMessage(): string {
+ return t("contextMenu.confirmDropTableChildObjectMessage", {
+ name: tableChildDropObjectName(props.node),
+ table: props.node.tableName || "",
+ });
+}
+
async function refreshDropObjectPreviewSql() {
const options = dropObjectSqlOptions();
dropObjectPreviewSql.value = "";
dropObjectPreviewSql.value = options ? await buildDropObjectSql(options).catch(() => "") : "";
}
+async function refreshDropTableChildObjectPreviewSql() {
+ const options = dropTableChildObjectSqlOptions();
+ dropTableChildObjectPreviewSql.value = "";
+ dropTableChildObjectPreviewSql.value = options ? await buildDropTableChildObjectSql(options).catch(() => "") : "";
+}
+
function viewObjectSource() {
const node = props.node;
if (!node.connectionId || !node.database) return;
@@ -828,6 +937,28 @@ function requestDropObject() {
showDropObjectConfirm.value = true;
}
+function requestDropTableChildObject() {
+ if (!canDropTableChildObject.value) return;
+ void refreshDropTableChildObjectPreviewSql();
+ showDropTableChildObjectConfirm.value = true;
+}
+
+function requestDropSelectedNode(): boolean {
+ if (props.node.type === "table") {
+ dropTable();
+ return true;
+ }
+ if (props.node.type === "view" || props.node.type === "procedure" || props.node.type === "function") {
+ requestDropObject();
+ return true;
+ }
+ if (canDropTableChildObject.value) {
+ requestDropTableChildObject();
+ return true;
+ }
+ return false;
+}
+
function nodeRenameObjectType(): RenameableObjectType | null {
if (props.node.type === "table") return "TABLE";
if (props.node.type === "view") return "VIEW";
@@ -944,9 +1075,34 @@ async function confirmDropObject() {
await connectionStore.ensureConnected(node.connectionId);
const sql = dropObjectPreviewSql.value || (await buildDropObjectSql(options));
await api.executeQuery(node.connectionId, node.database, sql, node.schema);
- const msgKey = node.type === "procedure" ? "contextMenu.dropProcedureSuccess" : "contextMenu.dropFunctionSuccess";
+ const msgKey =
+ node.type === "view"
+ ? "contextMenu.dropViewSuccess"
+ : node.type === "procedure"
+ ? "contextMenu.dropProcedureSuccess"
+ : "contextMenu.dropFunctionSuccess";
toast(t(msgKey, { name: node.label }), 3000);
- await refreshTableList(node);
+ if (node.type === "view") {
+ connectionStore.removeTreeNode(node.id);
+ } else {
+ await refreshTableList(node);
+ }
+ } catch (e: any) {
+ toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
+ }
+}
+
+async function confirmDropTableChildObject() {
+ const node = props.node;
+ if (!node.connectionId || !node.database) return;
+ const options = dropTableChildObjectSqlOptions();
+ if (!options) return;
+ try {
+ await connectionStore.ensureConnected(node.connectionId);
+ const sql = dropTableChildObjectPreviewSql.value || (await buildDropTableChildObjectSql(options));
+ await api.executeQuery(node.connectionId, node.database, sql, node.schema);
+ toast(t("contextMenu.dropTableChildObjectSuccess", { name: options.name }), 3000);
+ connectionStore.removeTreeNode(node.id);
} catch (e: any) {
toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
}
@@ -2190,6 +2346,14 @@ function treeItemMenuItems(): ContextMenuItem[] {
if (canRenameObject.value) {
items.push({ label: t("contextMenu.renameObject"), action: openRenameObjectDialog, icon: Pencil });
}
+ if (node.type === "view") {
+ items.push({
+ label: t("contextMenu.dropView"),
+ action: requestDropObject,
+ icon: Trash2,
+ variant: "destructive" as const,
+ });
+ }
items.push({ label: t("contextMenu.newQuery"), action: newQuery, icon: TerminalSquare });
if (canOpenDiagram.value) {
items.push({ label: t("diagram.open"), action: openDiagram, icon: Network });
@@ -2236,9 +2400,34 @@ function treeItemMenuItems(): ContextMenuItem[] {
// 7. Column
if (node.type === "column") {
+ items.push({ label: t("contextMenu.copyName"), action: copyName, icon: Copy });
if (canOpenFieldLineage.value) {
+ items.push({ label: "", separator: true });
items.push({ label: t("lineage.open"), action: openFieldLineage, icon: Network });
}
+ if (canDropTableChildObject.value) {
+ items.push({ label: "", separator: true });
+ items.push({
+ label: dropTableChildObjectMenuLabel(),
+ action: requestDropTableChildObject,
+ icon: Trash2,
+ variant: "destructive" as const,
+ });
+ }
+ return items;
+ }
+
+ if (node.type === "index" || node.type === "fkey" || node.type === "trigger") {
+ items.push({ label: t("contextMenu.copyName"), action: copyName, icon: Copy });
+ if (canDropTableChildObject.value) {
+ items.push({ label: "", separator: true });
+ items.push({
+ label: dropTableChildObjectMenuLabel(),
+ action: requestDropTableChildObject,
+ icon: Trash2,
+ variant: "destructive" as const,
+ });
+ }
return items;
}
@@ -2611,19 +2800,22 @@ function treeItemMenuItems(): ContextMenuItem[] {
+
+
{
+ return api.buildDropTableChildObjectSql(options);
+}
+
export function buildEmptyTableSql(options: TableAdminSqlOptions): Promise {
return api.buildEmptyTableSql(options);
}
diff --git a/apps/desktop/src/lib/http.ts b/apps/desktop/src/lib/http.ts
index 22922e0384..2dfe623abf 100644
--- a/apps/desktop/src/lib/http.ts
+++ b/apps/desktop/src/lib/http.ts
@@ -81,6 +81,7 @@ import type { BuildRenameObjectSqlOptions } from "@/lib/objectRenameSql";
import type { CreateDatabaseSqlOptions } from "@/lib/createDatabaseSql";
import type {
DatabaseNameSqlOptions,
+ DropTableChildObjectSqlOptions,
DropObjectSqlOptions,
DuplicateTableStructureSqlOptions,
SchemaNameSqlOptions,
@@ -588,6 +589,10 @@ export async function buildDropTableSql(options: TableAdminSqlOptions): Promise<
return post("/api/query/build-drop-table-sql", { options });
}
+export async function buildDropTableChildObjectSql(options: DropTableChildObjectSqlOptions): Promise {
+ return post("/api/query/build-drop-table-child-object-sql", { options });
+}
+
export async function buildEmptyTableSql(options: TableAdminSqlOptions): Promise {
return post("/api/query/build-empty-table-sql", { options });
}
diff --git a/apps/desktop/src/lib/tauri.ts b/apps/desktop/src/lib/tauri.ts
index 27acaf8a85..4a0d5daaeb 100644
--- a/apps/desktop/src/lib/tauri.ts
+++ b/apps/desktop/src/lib/tauri.ts
@@ -54,6 +54,7 @@ import type { BuildRenameObjectSqlOptions } from "@/lib/objectRenameSql";
import type { CreateDatabaseSqlOptions } from "@/lib/createDatabaseSql";
import type {
DatabaseNameSqlOptions,
+ DropTableChildObjectSqlOptions,
DropObjectSqlOptions,
DuplicateTableStructureSqlOptions,
SchemaNameSqlOptions,
@@ -580,6 +581,10 @@ export async function buildDropTableSql(options: TableAdminSqlOptions): Promise<
return invoke("build_drop_table_sql", { options });
}
+export async function buildDropTableChildObjectSql(options: DropTableChildObjectSqlOptions): Promise {
+ return invoke("build_drop_table_child_object_sql", { options });
+}
+
export async function buildEmptyTableSql(options: TableAdminSqlOptions): Promise {
return invoke("build_empty_table_sql", { options });
}
diff --git a/apps/desktop/src/stores/connectionStore.ts b/apps/desktop/src/stores/connectionStore.ts
index 8e37ac6f70..26ec0e0b57 100644
--- a/apps/desktop/src/stores/connectionStore.ts
+++ b/apps/desktop/src/stores/connectionStore.ts
@@ -1170,6 +1170,7 @@ export const useConnectionStore = defineStore("connection", () => {
connectionId,
database,
schema,
+ tableName: table,
meta: idx,
})),
);
@@ -1210,6 +1211,7 @@ export const useConnectionStore = defineStore("connection", () => {
connectionId,
database,
schema,
+ tableName: table,
meta: fk,
})),
);
@@ -1244,6 +1246,7 @@ export const useConnectionStore = defineStore("connection", () => {
connectionId,
database,
schema,
+ tableName: table,
meta: tr,
})),
);
diff --git a/crates/dbx-core/src/db_admin_sql.rs b/crates/dbx-core/src/db_admin_sql.rs
index 515639eea0..c96c98d64d 100644
--- a/crates/dbx-core/src/db_admin_sql.rs
+++ b/crates/dbx-core/src/db_admin_sql.rs
@@ -12,6 +12,15 @@ pub enum DatabaseObjectType {
Function,
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+pub enum TableChildObjectType {
+ Column,
+ Index,
+ ForeignKey,
+ Trigger,
+}
+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RenameObjectSqlOptions {
@@ -66,6 +75,18 @@ pub struct TableAdminSqlOptions {
pub table_name: String,
}
+#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct DropTableChildObjectSqlOptions {
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub database_type: Option,
+ pub object_type: TableChildObjectType,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub schema: Option,
+ pub table_name: String,
+ pub name: String,
+}
+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DatabaseNameSqlOptions {
@@ -135,6 +156,75 @@ pub fn build_drop_table_sql(options: TableAdminSqlOptions) -> String {
format!("DROP TABLE {};", qualified_name(options.database_type, options.schema.as_deref(), &options.table_name))
}
+pub fn build_drop_table_child_object_sql(options: DropTableChildObjectSqlOptions) -> Result {
+ let database_type = options.database_type;
+ let table = qualified_name(database_type, options.schema.as_deref(), &options.table_name);
+ let name = quote_rename_identifier(database_type, &options.name);
+ match options.object_type {
+ TableChildObjectType::Column => Ok(format!("ALTER TABLE {table} DROP COLUMN {name};")),
+ TableChildObjectType::Index => {
+ if matches!(database_type, Some(DatabaseType::ClickHouse | DatabaseType::Redshift)) {
+ return Err(format!("Dropping indexes is not supported for {}.", database_label(database_type)));
+ }
+ if matches!(database_type, Some(DatabaseType::Mysql | DatabaseType::Goldendb | DatabaseType::SqlServer)) {
+ return Ok(format!("DROP INDEX {name} ON {table};"));
+ }
+ if matches!(
+ database_type,
+ Some(
+ DatabaseType::Postgres
+ | DatabaseType::Gaussdb
+ | DatabaseType::OpenGauss
+ | DatabaseType::Highgo
+ | DatabaseType::Vastbase
+ | DatabaseType::Kingbase
+ | DatabaseType::Oracle
+ | DatabaseType::Dameng
+ | DatabaseType::OceanbaseOracle
+ | DatabaseType::Iris
+ )
+ ) && options.schema.as_deref().is_some_and(|schema| !schema.is_empty())
+ {
+ let schema = quote_rename_identifier(database_type, options.schema.as_deref().unwrap());
+ return Ok(format!("DROP INDEX {schema}.{name};"));
+ }
+ Ok(format!("DROP INDEX {name};"))
+ }
+ TableChildObjectType::ForeignKey => {
+ if matches!(database_type, Some(DatabaseType::Mysql | DatabaseType::Goldendb)) {
+ Ok(format!("ALTER TABLE {table} DROP FOREIGN KEY {name};"))
+ } else {
+ Ok(format!("ALTER TABLE {table} DROP CONSTRAINT {name};"))
+ }
+ }
+ TableChildObjectType::Trigger => {
+ if matches!(
+ database_type,
+ Some(
+ DatabaseType::Postgres
+ | DatabaseType::Gaussdb
+ | DatabaseType::OpenGauss
+ | DatabaseType::Highgo
+ | DatabaseType::Vastbase
+ | DatabaseType::Kingbase
+ )
+ ) {
+ Ok(format!("DROP TRIGGER {name} ON {table};"))
+ } else if matches!(database_type, Some(DatabaseType::SqlServer)) {
+ Ok(format!("DROP TRIGGER {name};"))
+ } else if database_type.is_some_and(is_schema_aware)
+ && options.schema.as_deref().is_some_and(|schema| !schema.is_empty())
+ && !matches!(database_type, Some(DatabaseType::Mysql | DatabaseType::Goldendb))
+ {
+ let schema = quote_rename_identifier(database_type, options.schema.as_deref().unwrap());
+ Ok(format!("DROP TRIGGER {schema}.{name};"))
+ } else {
+ Ok(format!("DROP TRIGGER {name};"))
+ }
+ }
+ }
+}
+
pub fn build_empty_table_sql(options: TableAdminSqlOptions) -> String {
let table = qualified_name(options.database_type, options.schema.as_deref(), &options.table_name);
match options.database_type {
@@ -481,6 +571,76 @@ mod tests {
);
}
+ #[test]
+ fn builds_drop_table_child_object_sql() {
+ assert_eq!(
+ build_drop_table_child_object_sql(DropTableChildObjectSqlOptions {
+ database_type: Some(DatabaseType::Postgres),
+ object_type: TableChildObjectType::Column,
+ schema: Some("public".to_string()),
+ table_name: "orders".to_string(),
+ name: "status".to_string(),
+ })
+ .unwrap(),
+ "ALTER TABLE \"public\".\"orders\" DROP COLUMN \"status\";"
+ );
+ assert_eq!(
+ build_drop_table_child_object_sql(DropTableChildObjectSqlOptions {
+ database_type: Some(DatabaseType::Mysql),
+ object_type: TableChildObjectType::Index,
+ schema: None,
+ table_name: "orders".to_string(),
+ name: "idx_orders_status".to_string(),
+ })
+ .unwrap(),
+ "DROP INDEX `idx_orders_status` ON `orders`;"
+ );
+ assert_eq!(
+ build_drop_table_child_object_sql(DropTableChildObjectSqlOptions {
+ database_type: Some(DatabaseType::Postgres),
+ object_type: TableChildObjectType::Index,
+ schema: Some("public".to_string()),
+ table_name: "orders".to_string(),
+ name: "idx_orders_status".to_string(),
+ })
+ .unwrap(),
+ "DROP INDEX \"public\".\"idx_orders_status\";"
+ );
+ assert_eq!(
+ build_drop_table_child_object_sql(DropTableChildObjectSqlOptions {
+ database_type: Some(DatabaseType::Mysql),
+ object_type: TableChildObjectType::ForeignKey,
+ schema: None,
+ table_name: "orders".to_string(),
+ name: "fk_orders_user".to_string(),
+ })
+ .unwrap(),
+ "ALTER TABLE `orders` DROP FOREIGN KEY `fk_orders_user`;"
+ );
+ assert_eq!(
+ build_drop_table_child_object_sql(DropTableChildObjectSqlOptions {
+ database_type: Some(DatabaseType::SqlServer),
+ object_type: TableChildObjectType::ForeignKey,
+ schema: Some("dbo".to_string()),
+ table_name: "orders".to_string(),
+ name: "fk_orders_user".to_string(),
+ })
+ .unwrap(),
+ "ALTER TABLE [dbo].[orders] DROP CONSTRAINT [fk_orders_user];"
+ );
+ assert_eq!(
+ build_drop_table_child_object_sql(DropTableChildObjectSqlOptions {
+ database_type: Some(DatabaseType::Postgres),
+ object_type: TableChildObjectType::Trigger,
+ schema: Some("public".to_string()),
+ table_name: "orders".to_string(),
+ name: "orders_audit".to_string(),
+ })
+ .unwrap(),
+ "DROP TRIGGER \"orders_audit\" ON \"public\".\"orders\";"
+ );
+ }
+
#[test]
fn builds_duplicate_table_structure_sql() {
assert_eq!(
diff --git a/crates/dbx-web/src/main.rs b/crates/dbx-web/src/main.rs
index 7635b39654..60ce7091ff 100644
--- a/crates/dbx-web/src/main.rs
+++ b/crates/dbx-web/src/main.rs
@@ -152,6 +152,7 @@ async fn main() {
.route("/query/build-duckdb-attach-database-sql", post(routes::query::build_duckdb_attach_database_sql))
.route("/query/build-drop-object-sql", post(routes::query::build_drop_object_sql))
.route("/query/build-drop-table-sql", post(routes::query::build_drop_table_sql))
+ .route("/query/build-drop-table-child-object-sql", post(routes::query::build_drop_table_child_object_sql))
.route("/query/build-empty-table-sql", post(routes::query::build_empty_table_sql))
.route("/query/build-truncate-table-sql", post(routes::query::build_truncate_table_sql))
.route("/query/build-drop-database-sql", post(routes::query::build_drop_database_sql))
diff --git a/crates/dbx-web/src/routes/query.rs b/crates/dbx-web/src/routes/query.rs
index 2602214540..8a94e73386 100644
--- a/crates/dbx-web/src/routes/query.rs
+++ b/crates/dbx-web/src/routes/query.rs
@@ -148,6 +148,12 @@ pub struct BuildTableAdminSqlRequest {
pub options: dbx_core::db_admin_sql::TableAdminSqlOptions,
}
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct BuildDropTableChildObjectSqlRequest {
+ pub options: dbx_core::db_admin_sql::DropTableChildObjectSqlOptions,
+}
+
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BuildDatabaseNameSqlRequest {
@@ -489,6 +495,12 @@ pub async fn build_drop_table_sql(Json(req): Json) ->
Json(dbx_core::db_admin_sql::build_drop_table_sql(req.options))
}
+pub async fn build_drop_table_child_object_sql(
+ Json(req): Json,
+) -> Result, AppError> {
+ dbx_core::db_admin_sql::build_drop_table_child_object_sql(req.options).map(Json).map_err(AppError)
+}
+
pub async fn build_empty_table_sql(Json(req): Json) -> Json {
Json(dbx_core::db_admin_sql::build_empty_table_sql(req.options))
}
diff --git a/src-tauri/src/commands/query.rs b/src-tauri/src/commands/query.rs
index 7e82d227d5..be87a33c02 100644
--- a/src-tauri/src/commands/query.rs
+++ b/src-tauri/src/commands/query.rs
@@ -286,6 +286,13 @@ pub fn build_drop_table_sql(options: dbx_core::db_admin_sql::TableAdminSqlOption
Ok(dbx_core::db_admin_sql::build_drop_table_sql(options))
}
+#[tauri::command]
+pub fn build_drop_table_child_object_sql(
+ options: dbx_core::db_admin_sql::DropTableChildObjectSqlOptions,
+) -> Result {
+ dbx_core::db_admin_sql::build_drop_table_child_object_sql(options)
+}
+
#[tauri::command]
pub fn build_empty_table_sql(options: dbx_core::db_admin_sql::TableAdminSqlOptions) -> Result {
Ok(dbx_core::db_admin_sql::build_empty_table_sql(options))
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index 32cef0f3a1..7a3a733364 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -413,6 +413,7 @@ pub fn run() {
commands::query::build_duckdb_attach_database_sql,
commands::query::build_drop_object_sql,
commands::query::build_drop_table_sql,
+ commands::query::build_drop_table_child_object_sql,
commands::query::build_empty_table_sql,
commands::query::build_truncate_table_sql,
commands::query::build_drop_database_sql,