From 159e813c9c7f55bdf9b406e42bb44ee7c26b7e60 Mon Sep 17 00:00:00 2001 From: Elias <45232878+mapan0424@users.noreply.github.com> Date: Sat, 8 Aug 2026 10:37:59 +0800 Subject: [PATCH] feat(xugu): expose routine parameter metadata --- .../components/objects/ObjectSourceDialog.vue | 40 ++- .../objects/ProcedureExecutionDialog.vue | 28 +- .../objects/RoutineMetadataPanel.vue | 41 +++ .../__tests__/RoutineMetadataPanel.spec.ts | 53 ++++ .../table/routineExecutionSql.spec.ts | 127 +++++++- .../table/routineParameters.xugu.spec.ts | 50 +++ .../src/lib/table/routineExecutionSql.ts | 27 ++ .../src/lib/table/routineParameters.ts | 290 +++++++++++++++++- 8 files changed, 633 insertions(+), 23 deletions(-) create mode 100644 apps/desktop/src/components/objects/RoutineMetadataPanel.vue create mode 100644 apps/desktop/src/components/objects/__tests__/RoutineMetadataPanel.spec.ts create mode 100644 apps/desktop/src/lib/__tests__/table/routineParameters.xugu.spec.ts diff --git a/apps/desktop/src/components/objects/ObjectSourceDialog.vue b/apps/desktop/src/components/objects/ObjectSourceDialog.vue index 9d79d23f5..c871deb6d 100644 --- a/apps/desktop/src/components/objects/ObjectSourceDialog.vue +++ b/apps/desktop/src/components/objects/ObjectSourceDialog.vue @@ -9,9 +9,11 @@ import { copyToClipboard } from "@/lib/common/clipboard"; import { formatSqlForDisplay, type SqlFormatDialect } from "@/lib/sql/sqlFormatter"; import { buildEditableObjectSource, buildExecutableObjectSourceStatements, executeObjectSourceSave, formatObjectSourceSaveError } from "@/lib/table/objectSourceEditor"; import { loadObjectSourceWithRoutineFallback } from "@/lib/table/objectSourceLoad"; +import { xuguRoutineMetadataFromDefinition, type XuguRoutineMetadata } from "@/lib/table/routineParameters"; import { executeWithProductionSqlGuard } from "@/lib/database/productionExecutionGuard"; import * as api from "@/lib/backend/api"; import QueryEditor from "@/components/editor/QueryEditor.vue"; +import RoutineMetadataPanel from "@/components/objects/RoutineMetadataPanel.vue"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import type { DatabaseType, ObjectSourceKind } from "@/types/database"; @@ -55,12 +57,14 @@ const editing = ref(false); const sourceEditable = ref(true); const error = ref(""); const saveError = ref(""); +const routineMetadata = ref(null); /** May differ from props.objectType after PROCEDURE/FUNCTION/PACKAGE fallback resolution. */ const resolvedObjectType = ref(props.objectType); let loadSerial = 0; const canEdit = computed(() => sourceEditable.value && props.objectType !== "SEQUENCE"); const title = computed(() => `${editing.value ? t("contextMenu.editView") : t("contextMenu.viewSource")} - ${props.name}`); +const hasRoutineMetadata = computed(() => !!routineMetadata.value && (routineMetadata.value.parameters.length > 0 || !!routineMetadata.value.returnType)); watch( () => [props.open, props.connectionId, props.database, props.schema, props.name, props.relationName, props.signature, props.objectType, props.initialEditing] as const, @@ -77,6 +81,7 @@ async function loadSource(nextEditing = props.initialEditing && canEdit.value) { draft.value = ""; error.value = ""; saveError.value = ""; + routineMetadata.value = null; sourceEditable.value = true; editing.value = false; loading.value = true; @@ -94,6 +99,7 @@ async function loadSource(nextEditing = props.initialEditing && canEdit.value) { }); if (serial !== loadSerial) return; resolvedObjectType.value = resolvedType; + routineMetadata.value = props.databaseType === "xugu" && (resolvedType === "PROCEDURE" || resolvedType === "FUNCTION") ? xuguRoutineMetadataFromDefinition(result.source) : null; sourceEditable.value = editableAllowed; const formatted = await formatSqlForDisplay(editable, props.formatDialect ?? props.dialect, settingsStore.editorSettings.sqlFormatter); editableText.value = editable; @@ -221,22 +227,24 @@ function closeDialog() { {{ saveError }} - +
+ + +
diff --git a/apps/desktop/src/components/objects/ProcedureExecutionDialog.vue b/apps/desktop/src/components/objects/ProcedureExecutionDialog.vue index fae74751e..d2c5ab0ef 100644 --- a/apps/desktop/src/components/objects/ProcedureExecutionDialog.vue +++ b/apps/desktop/src/components/objects/ProcedureExecutionDialog.vue @@ -52,7 +52,8 @@ const generatedSql = computed(() => { }); const inputParameterCount = computed(() => parameters.value.filter(acceptsRoutineInput).length); -const outputParameterCount = computed(() => parameters.value.filter((parameter) => parameter.mode === "OUT").length); +const outputParameterCount = computed(() => parameters.value.filter((parameter) => parameter.mode === "OUT" || (props.databaseType === "xugu" && parameter.mode === "INOUT")).length); +const isXugu = computed(() => props.databaseType === "xugu"); watch( () => [open.value, props.connectionId, props.database, props.databaseType, props.schema, props.routineName] as const, @@ -134,6 +135,11 @@ function execute() { function canEditParameter(parameter: RoutineParameterValue): boolean { return acceptsRoutineInput(parameter); } + +function displayParameterDefault(parameter: RoutineParameterValue): string { + if (!parameter.hasDefault) return "-"; + return parameter.defaultValue?.trim() || "DEFAULT"; +}