feat(mysql): add routine and trigger creation templates
This commit is contained in:
10 files changed
+200
-1
No files matched your search
@@ -66,6 +66,7 @@ import { resolveDefaultDatabase } from "@/lib/database/defaultDatabase";
|
||||
import { canTreeNodePin, canTreeNodeShowExpander } from "@/lib/sidebar/sidebarTreeItemLayout";
|
||||
import { objectTypesForGroupNode } from "@/lib/table/tableTree";
|
||||
import { loadSidebarObjectGroup } from "@/lib/sidebar/sidebarObjectGroupRouting";
|
||||
import { mysqlObjectTemplateForGroup } from "@/lib/sidebar/mysqlObjectTemplates";
|
||||
import { buildTableDeleteTemplate, buildTableInsertTemplate, buildTableSelectTemplate, buildTableUpdateTemplate } from "@/lib/table/tableSqlTemplates";
|
||||
import { driverStoreFocusForInstallError } from "@/lib/connection/agentDriverInstallHint";
|
||||
import {
|
||||
@@ -2865,6 +2866,16 @@ function createView() {
|
||||
});
|
||||
}
|
||||
|
||||
function createMysqlObjectTemplate() {
|
||||
const node = activeNode.value;
|
||||
if (!node.connectionId || !node.database) return;
|
||||
const template = mysqlObjectTemplateForGroup(connectionStore.getConfig(node.connectionId), node);
|
||||
if (!template) return;
|
||||
connectionStore.activeConnectionId = node.connectionId;
|
||||
const tabId = queryStore.createTab(node.connectionId, node.database, t(template.titleKey), "query", node.schema);
|
||||
queryStore.updateSql(tabId, template.sql);
|
||||
}
|
||||
|
||||
const canExpand = computed(() =>
|
||||
canTreeNodeShowExpander({
|
||||
type: activeNode.value.type,
|
||||
@@ -4024,7 +4035,8 @@ function buildObjectGroupSidebarMenu(context: SidebarMenuFactoryContext): boolea
|
||||
const { node, items } = context;
|
||||
// 9. Group Labels (group-columns, group-tables, etc.)
|
||||
if (isGroupLabel(node)) {
|
||||
const hasGroupCreateAction = (node.type === "group-tables" && canCreateTable.value) || (node.type === "group-views" && !!node.connectionId && !!node.database);
|
||||
const mysqlObjectTemplate = node.connectionId ? mysqlObjectTemplateForGroup(connectionStore.getConfig(node.connectionId), node) : null;
|
||||
const hasGroupCreateAction = (node.type === "group-tables" && canCreateTable.value) || (node.type === "group-views" && !!node.connectionId && !!node.database) || !!mysqlObjectTemplate;
|
||||
const canLoadAllObjectGroup = node.type === "group-tables" || node.type === "group-views" || node.type === "group-materialized-views";
|
||||
if (node.type === "group-tables" && canCreateTable.value) {
|
||||
items.push({ label: t("contextMenu.createTable"), action: createTable, icon: Plus });
|
||||
@@ -4038,6 +4050,9 @@ function buildObjectGroupSidebarMenu(context: SidebarMenuFactoryContext): boolea
|
||||
if (node.type === "group-views" && node.connectionId && node.database) {
|
||||
items.push({ label: t("contextMenu.createView"), action: createView, icon: Plus });
|
||||
}
|
||||
if (mysqlObjectTemplate) {
|
||||
items.push({ label: t(mysqlObjectTemplate.titleKey), action: createMysqlObjectTemplate, icon: Plus });
|
||||
}
|
||||
if (hasGroupCreateAction) {
|
||||
items.push({ label: "", separator: true });
|
||||
}
|
||||
|
||||
@@ -1644,6 +1644,9 @@ export default {
|
||||
exportStructureCopied: "Structure copied",
|
||||
createTable: "Create Table",
|
||||
createView: "Create View",
|
||||
createProcedure: "Create Procedure",
|
||||
createFunction: "Create Function",
|
||||
createTrigger: "Create Trigger",
|
||||
dropTable: "Drop Table",
|
||||
emptyTable: "Empty Table",
|
||||
truncateTable: "Truncate Table",
|
||||
|
||||
@@ -1761,6 +1761,9 @@ export default withEnglishFallback({
|
||||
dropExtension: "Eliminar extensión",
|
||||
processList: "Lista de procesos",
|
||||
serverDashboard: "Panel de control del servidor",
|
||||
createProcedure: "Nuevo procedimiento almacenado",
|
||||
createFunction: "Nueva función",
|
||||
createTrigger: "Nuevo disparador",
|
||||
},
|
||||
visibleDatabases: {
|
||||
title: "Bases de datos visibles",
|
||||
|
||||
@@ -1759,6 +1759,9 @@ export default withEnglishFallback({
|
||||
dropExtension: "Elimina estensione",
|
||||
processList: "Elenco processi",
|
||||
serverDashboard: "Dashboard del server",
|
||||
createProcedure: "Nuovo stored procedure",
|
||||
createFunction: "Nuova funzione",
|
||||
createTrigger: "Nuovo trigger",
|
||||
},
|
||||
visibleDatabases: {
|
||||
title: "Database Visibili",
|
||||
|
||||
@@ -1760,6 +1760,9 @@ export default withEnglishFallback({
|
||||
dropExtension: "拡張機能を削除",
|
||||
processList: "プロセス一覧",
|
||||
serverDashboard: "サーバーダッシュボード",
|
||||
createProcedure: "新規ストアドプロシージャ",
|
||||
createFunction: "新規関数",
|
||||
createTrigger: "新規トリガー",
|
||||
},
|
||||
visibleDatabases: {
|
||||
title: "表示するデータベース",
|
||||
|
||||
@@ -1761,6 +1761,9 @@ export default withEnglishFallback({
|
||||
dropExtension: "Remover extensão",
|
||||
processList: "Lista de Processos",
|
||||
serverDashboard: "Painel do Servidor",
|
||||
createProcedure: "Novo procedimento armazenado",
|
||||
createFunction: "Nova função",
|
||||
createTrigger: "Novo gatilho",
|
||||
},
|
||||
visibleDatabases: {
|
||||
title: "Bancos de dados visíveis",
|
||||
|
||||
@@ -1644,6 +1644,9 @@ export default withEnglishFallback({
|
||||
exportStructureCopied: "表结构已复制",
|
||||
createTable: "新建表",
|
||||
createView: "新建视图",
|
||||
createProcedure: "新建存储过程",
|
||||
createFunction: "新建函数",
|
||||
createTrigger: "新建触发器",
|
||||
dropTable: "删除表",
|
||||
emptyTable: "清空数据",
|
||||
truncateTable: "截断表",
|
||||
|
||||
@@ -1761,6 +1761,9 @@ export default withEnglishFallback({
|
||||
dropExtension: "刪除擴展",
|
||||
processList: "處理程序清單",
|
||||
serverDashboard: "伺服器儀表板",
|
||||
createProcedure: "新增儲存程序",
|
||||
createFunction: "新增函數",
|
||||
createTrigger: "新增觸發器",
|
||||
},
|
||||
visibleDatabases: {
|
||||
title: "顯示資料庫",
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import type { ConnectionConfig, TreeNode, TreeNodeType } from "@/types/database";
|
||||
|
||||
export type MysqlObjectTemplateKind = "procedure" | "function" | "trigger";
|
||||
|
||||
export interface MysqlObjectTemplate {
|
||||
kind: MysqlObjectTemplateKind;
|
||||
titleKey: "contextMenu.createProcedure" | "contextMenu.createFunction" | "contextMenu.createTrigger";
|
||||
sql: string;
|
||||
}
|
||||
|
||||
type MysqlTemplateConnection = Pick<ConnectionConfig, "db_type" | "driver_profile">;
|
||||
type MysqlTemplateNode = Pick<TreeNode, "type" | "database" | "tableName">;
|
||||
|
||||
const templateKindByGroup: Partial<Record<TreeNodeType, MysqlObjectTemplateKind>> = {
|
||||
"group-procedures": "procedure",
|
||||
"group-functions": "function",
|
||||
"group-triggers": "trigger",
|
||||
};
|
||||
|
||||
export function supportsMysqlObjectTemplates(connection?: MysqlTemplateConnection): boolean {
|
||||
if (connection?.db_type !== "mysql") return false;
|
||||
const profile = connection.driver_profile?.trim().toLowerCase();
|
||||
return !profile || profile === "mysql" || profile === "custom_mysql";
|
||||
}
|
||||
|
||||
export function mysqlObjectTemplateForGroup(connection: MysqlTemplateConnection | undefined, node: MysqlTemplateNode): MysqlObjectTemplate | null {
|
||||
if (!supportsMysqlObjectTemplates(connection) || !node.database) return null;
|
||||
const kind = templateKindByGroup[node.type];
|
||||
if (!kind) return null;
|
||||
return buildMysqlObjectTemplate(kind, node.database, node.tableName);
|
||||
}
|
||||
|
||||
export function buildMysqlObjectTemplate(kind: MysqlObjectTemplateKind, database: string, tableName?: string): MysqlObjectTemplate {
|
||||
const qualifiedDatabase = quoteMysqlIdentifier(database);
|
||||
|
||||
if (kind === "procedure") {
|
||||
const name = "new_procedure";
|
||||
return {
|
||||
kind,
|
||||
titleKey: "contextMenu.createProcedure",
|
||||
sql: `DELIMITER $$
|
||||
|
||||
CREATE PROCEDURE ${qualifiedDatabase}.${quoteMysqlIdentifier(name)}()
|
||||
BEGIN
|
||||
SELECT 1;
|
||||
END$$
|
||||
|
||||
DELIMITER ;`,
|
||||
};
|
||||
}
|
||||
|
||||
if (kind === "function") {
|
||||
const name = "new_function";
|
||||
return {
|
||||
kind,
|
||||
titleKey: "contextMenu.createFunction",
|
||||
sql: `DELIMITER $$
|
||||
|
||||
CREATE FUNCTION ${qualifiedDatabase}.${quoteMysqlIdentifier(name)}()
|
||||
RETURNS INT
|
||||
DETERMINISTIC
|
||||
BEGIN
|
||||
RETURN 0;
|
||||
END$$
|
||||
|
||||
DELIMITER ;`,
|
||||
};
|
||||
}
|
||||
|
||||
const name = "new_trigger";
|
||||
return {
|
||||
kind,
|
||||
titleKey: "contextMenu.createTrigger",
|
||||
sql: `DELIMITER $$
|
||||
|
||||
CREATE TRIGGER ${qualifiedDatabase}.${quoteMysqlIdentifier(name)}
|
||||
BEFORE INSERT ON ${qualifiedDatabase}.${quoteMysqlIdentifier(tableName || "table_name")}
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
SET @dbx_trigger_placeholder = 1;
|
||||
END$$
|
||||
|
||||
DELIMITER ;`,
|
||||
};
|
||||
}
|
||||
|
||||
function quoteMysqlIdentifier(identifier: string): string {
|
||||
return `\`${identifier.replaceAll("`", "``")}\``;
|
||||
}
|
||||
Reference in new issue
Block a user