feat(xugu): expose routine parameter metadata

This commit is contained in:
Elias authored and GitHub committed 2026-08-08 10:37:59 +08:00
1 parent bdf87ac255
commit 159e813c9c
8 files changed
+633 -23

No files matched your search

@@ -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<XuguRoutineMetadata | null>(null);
/** May differ from props.objectType after PROCEDURE/FUNCTION/PACKAGE fallback resolution. */
const resolvedObjectType = ref<ObjectSourceKind>(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 }}
</div>
</div>
<QueryEditor
v-else
:key="`${props.connectionId}:${props.database}:${props.schema || ''}:${props.name}:${props.objectType}`"
:model-value="content"
class="object-source-dialog-editor min-h-0 overflow-hidden rounded border"
:connection-id="props.connectionId"
:database="props.database"
:schema="props.schema || props.database"
:database-type="props.databaseType"
:dialect="props.dialect"
:format-dialect="props.formatDialect"
force-word-wrap
read-only
hide-execution-controls
data-object-source-preview
/>
<div v-else class="flex min-h-0 flex-col gap-3 overflow-hidden">
<RoutineMetadataPanel v-if="hasRoutineMetadata && routineMetadata" :parameters="routineMetadata.parameters" :return-type="routineMetadata.returnType" />
<QueryEditor
:key="`${props.connectionId}:${props.database}:${props.schema || ''}:${props.name}:${props.objectType}`"
:model-value="content"
class="object-source-dialog-editor min-h-0 flex-1 overflow-hidden rounded border"
:connection-id="props.connectionId"
:database="props.database"
:schema="props.schema || props.database"
:database-type="props.databaseType"
:dialect="props.dialect"
:format-dialect="props.formatDialect"
force-word-wrap
read-only
hide-execution-controls
data-object-source-preview
/>
</div>
<DialogFooter>
<Button variant="outline" @click="closeDialog">{{ t("common.close") }}</Button>