fix(query): preserve structured backend errors

This commit is contained in:
miracle authored and GitHub committed 2026-08-02 16:37:46 +08:00
1 parent 2e9dcdc26b
commit bcafc4a474
58 files changed
+4182 -554

No files matched your search

@@ -1502,7 +1502,7 @@ function finishAgentDriverInstall() {
function failAgentDriverInstall(error: unknown) {
agentInstallOperationId.value = null;
agentInstallRunning.value = false;
agentInstallError.value = translateBackendError(t, errorMessage(error));
agentInstallError.value = translateBackendError(t, error);
showAgentInstallDialog.value = true;
}
@@ -1559,7 +1559,7 @@ async function ensureRequiredAgentDriverInstalled(config: ConnectionConfig): Pro
await refreshLocalAgentDrivers();
finishAgentDriverInstall();
} catch (error) {
testResult.value = { ok: false, message: errorMessage(error) };
testResult.value = { ok: false, message: translateBackendError(t, error) };
failAgentDriverInstall(error);
throw error;
}
@@ -1601,7 +1601,7 @@ async function installSqlServerLegacyCompatibilityComponentIfNeeded(): Promise<b
await refreshLocalAgentDrivers();
finishAgentDriverInstall();
} catch (error) {
testResult.value = { ok: false, message: errorMessage(error) };
testResult.value = { ok: false, message: translateBackendError(t, error) };
failAgentDriverInstall(error);
throw error;
}
@@ -79,6 +79,7 @@ import type { ConnectionConfig, QueryTab, SavedSqlFile, TableInfo } from "@/type
import { fetchNamespaceOptionsForConnection, useDatabaseOptions } from "@/composables/useDatabaseOptions";
import { decodeSelectableDatabaseValue, encodeSelectableDatabaseValue, formatDatabaseLabel, resolveDefaultDatabase } from "@/lib/database/defaultDatabase";
import { normalizeSqliteNamespace } from "@/lib/database/sqliteNamespace";
import { isQueryExecutionErrorResult } from "@/lib/query/queryResultError";
import { isSchemaAware } from "@/lib/database/databaseCapabilities";
import ExplainPlanViewer from "@/components/explain/ExplainPlanViewer.vue";
import { parseExplainResult, parseOracleExplainText, type ParsedExplainPlan } from "@/lib/diagram/explainPlan";
@@ -662,8 +663,7 @@ watch(
function selectAction(action: AiAction) {
activeAction.value = action;
if (action === "fix" && props.tab?.result) {
const cols = props.tab.result.columns;
if (cols.includes("Error")) {
if (isQueryExecutionErrorResult(props.tab.result)) {
const errVal = props.tab.result.rows[0]?.[0];
if (errVal != null) prompt.value = String(errVal);
}
@@ -67,6 +67,7 @@ import DataGridQueryControls from "@/components/grid/DataGridQueryControls.vue";
import TemporalCellEditor from "@/components/grid/TemporalCellEditor.vue";
import EnumCellEditor from "@/components/grid/EnumCellEditor.vue";
import type { QueryResult, ColumnInfo, DatabaseType, ForeignKeyInfo, IndexInfo, TriggerInfo, TableInfoTab } from "@/types/database";
import { isQueryExecutionErrorResult } from "@/lib/query/queryResultError";
import { tableObjectSourceKind } from "@/lib/table/tableObjectSourceKind";
import { tableColumnDefaultDisplayValue } from "@/lib/table/tableColumnDefaultPresentation";
import { shouldNavigateFromTableInfoColumnClick } from "@/lib/table/tableInfoColumnNavigation";
@@ -3577,7 +3578,7 @@ watch(
},
{ immediate: true },
);
const isErrorResult = computed(() => props.result.columns.length === 1 && props.result.columns[0] === "Error" && props.result.rows.length > 0);
const isErrorResult = computed(() => isQueryExecutionErrorResult(props.result) && props.result.rows.length > 0);
const errorMessage = computed(() => (isErrorResult.value ? String(props.result.rows[0]?.[0] ?? "") : ""));
// --- Selection composable ---
const selection = useDataGridSelection({
@@ -3,6 +3,7 @@ import { computed, ref, defineAsyncComponent, watch, nextTick, onMounted, onUnmo
import { safeLocalStorageGet, safeLocalStorageSet } from "@/lib/backend/safeStorage";
import { appendDebugLog, isDebugLoggingEnabled } from "@/lib/backend/debugLog";
import { canReloadUnavailableDataTab } from "@/lib/table/tableDataRefresh";
import { isQueryExecutionErrorResult } from "@/lib/query/queryResultError";
import type { CSSProperties } from "vue";
import { useI18n } from "vue-i18n";
import { Check, Columns3Cog, EyeOff, Loader2, Search, TableProperties, ChevronDown, ChevronUp, Inbox, RefreshCcw, Wrench, Toolbox, Database, Download, Upload, X, Pin, Rows3, SquareDashed, Minus, Plus, ShieldAlert, AlignLeft, AlignRight, PanelsTopLeft } from "@lucide/vue";
@@ -340,7 +341,7 @@ const hasNumericData = computed(() => {
const activeQueryError = computed(() => {
const result = props.activeTab.result;
if (!result?.columns.includes("Error")) return "";
if (!result || !isQueryExecutionErrorResult(result)) return "";
return String(result.rows[0]?.[0] ?? "");
});
const hasQueryOutput = computed(
@@ -1480,7 +1481,7 @@ defineExpose({ focusSearch, refreshData, refreshQueryEditorCompletionCache, hand
@export-archive="exportResultArchive"
/>
</template>
<template v-if="activeTab.result?.columns.includes('Error')" #error-actions="{ errorMessage }">
<template v-if="activeTab.result && isQueryExecutionErrorResult(activeTab.result)" #error-actions="{ errorMessage }">
<QueryErrorActions :error-message="String(errorMessage)" :connection-id="activeTab.connectionId" @change-query-timeout="activeTab.connectionId && emit('openConnectionSettings', activeTab.connectionId, 'advanced')" @fix-with-ai="(message) => emit('fixWithAi', message)" />
</template>
</DataGrid>
@@ -1777,7 +1778,7 @@ defineExpose({ focusSearch, refreshData, refreshQueryEditorCompletionCache, hand
@paginate="(offset: number, limit: number, whereInput?: string, orderBy?: string) => emit('paginate', offset, limit, whereInput, orderBy)"
@sort="(column: string, columnIndex: number, direction: 'asc' | 'desc' | null, whereInput?: string, mode?: DataGridSortMode) => emit('sort', column, columnIndex, direction, whereInput, mode)"
>
<template v-if="activeTab.result?.columns.includes('Error')" #error-actions="{ errorMessage }">
<template v-if="activeTab.result && isQueryExecutionErrorResult(activeTab.result)" #error-actions="{ errorMessage }">
<QueryErrorActions :error-message="String(errorMessage)" :connection-id="activeTab.connectionId" @change-query-timeout="activeTab.connectionId && emit('openConnectionSettings', activeTab.connectionId, 'advanced')" @fix-with-ai="(message) => emit('fixWithAi', message)" />
</template>
</DataGrid>