feat(ui): refresh latest ddl on demand

This commit is contained in:
zipg authored and GitHub committed 2026-09-01 01:46:39 +08:00
1 parent f9ff9245ce
commit cd008b2d56
17 files changed
+186 -11

No files matched your search

+91 -5
View File
@@ -86,6 +86,7 @@ import { tableObjectSourceKind } from "@/lib/table/tableObjectSourceKind";
import { tableColumnDefaultDisplayValue } from "@/lib/table/tableColumnDefaultPresentation";
import { shouldNavigateFromTableInfoColumnClick } from "@/lib/table/tableInfoColumnNavigation";
import { tableInfoTabForDrawerToggle } from "@/lib/table/tableInfoTabPreference";
import { loadObjectDdl } from "@/lib/metadata/objectDdlCache";
import { loadObjectMetadataFacet } from "@/lib/metadata/objectMetadataCache";
import * as api from "@/lib/backend/api";
import { formatElapsedSeconds } from "@/lib/common/elapsedTime";
@@ -10785,6 +10786,9 @@ function clampCellDetailPanelSize(value: number, layout = cellDetailPanelLayout.
const showTableInfo = ref(false);
const activeTableInfoTab = ref<TableInfoTab>(settingsStore.editorSettings.tableInfoActiveTab);
const ddlContent = ref("");
const tableInfoColumns = ref<ColumnInfo[]>(props.tableMeta?.columns ?? []);
const tableInfoColumnsLoading = ref(false);
let tableInfoColumnsRequestGeneration = 0;
const ddlPreRef = ref<HTMLPreElement | null>(null);
const ddlSearchMatchCount = ref(0);
const ddlSearchMatchIndex = ref(0);
@@ -10943,6 +10947,14 @@ let constraintsRequestGeneration = 0;
// also shown (each constraint appears once; FK navigation stays in that tab).
const constraintsForTab = computed(() => constraintsForConstraintsTab(constraints.value, tableMetadataCapabilities.value.foreignKeys));
const searchQuery = ref("");
const activeTableInfoLoading = computed(() => {
if (activeTableInfoTab.value === "ddl") return ddlLoading.value;
if (activeTableInfoTab.value === "columns") return tableInfoColumnsLoading.value;
if (activeTableInfoTab.value === "indexes") return indexesLoading.value;
if (activeTableInfoTab.value === "foreignKeys") return foreignKeysLoading.value;
if (activeTableInfoTab.value === "constraints") return constraintsLoading.value;
return activeTableInfoTab.value === "triggers" && triggersLoading.value;
});
const cellDetailPanelLayout = computed(() => settingsStore.editorSettings.cellDetailPanelLayout);
const cellDetailPanelIsBottom = computed(() => cellDetailPanelLayout.value === "bottom");
@@ -11042,7 +11054,7 @@ const tableInfoTabs = computed(() => {
id: "columns",
label: t("grid.tableInfoColumns"),
icon: ListTree,
count: props.tableMeta?.columns.length,
count: tableInfoColumns.value.length,
});
}
if (canShowTableIndexes.value) {
@@ -11116,13 +11128,24 @@ watch(
{ immediate: true },
);
async function fetchDdl() {
async function fetchDdl(force = settingsStore.editorSettings.refreshDdlOnOpen) {
if (!props.connectionId || !props.tableMeta) return;
showTableInfo.value = true;
ddlLoading.value = true;
try {
// Preserve view identity so the backend loads the stored view source instead of synthesizing table DDL.
ddlContent.value = await api.getTableDisplayDdl(props.connectionId, props.database || "", props.tableMeta.schema || props.database || "", props.tableMeta.tableName, tableObjectSourceKind(props.tableMeta.tableType), props.tableMeta.catalog);
const { ddl } = await loadObjectDdl(
{
connectionId: props.connectionId,
database: props.database || "",
schema: props.tableMeta.schema || props.database || "",
tableName: props.tableMeta.tableName,
objectType: tableObjectSourceKind(props.tableMeta.tableType),
catalog: props.tableMeta.catalog,
},
{ force },
);
ddlContent.value = ddl;
} catch (e: any) {
ddlContent.value = `-- Error: ${e}`;
} finally {
@@ -11130,6 +11153,53 @@ async function fetchDdl() {
}
}
async function fetchTableInfoColumns(force = false) {
if (!props.connectionId || !props.tableMeta) return;
const requestGeneration = ++tableInfoColumnsRequestGeneration;
tableInfoColumnsLoading.value = true;
try {
// Route through the shared metadata facet cache so a grid-side refresh
// invalidates/populates the same cache the sidebar and hover views read.
const request = {
connectionId: props.connectionId,
database: props.database || "",
schema: props.tableMeta.schema || props.database || "",
tableName: props.tableMeta.tableName,
objectType: tableObjectSourceKind(props.tableMeta.tableType),
catalog: props.tableMeta.catalog,
};
const { value: columns } = await loadObjectMetadataFacet(request, "columns", () => api.getColumns(request.connectionId, request.database, request.schema, request.tableName, request.catalog), { force });
if (requestGeneration !== tableInfoColumnsRequestGeneration) return;
tableInfoColumns.value = columns;
} catch (error) {
if (requestGeneration !== tableInfoColumnsRequestGeneration) return;
toast(translateBackendError(t, error), 5000);
} finally {
if (requestGeneration === tableInfoColumnsRequestGeneration) tableInfoColumnsLoading.value = false;
}
}
async function refreshActiveTableInfo() {
if (!showTableInfo.value || !props.tableMeta) return;
if (canShowTableOwner.value) void fetchTableOwner(true);
if (activeTableInfoTab.value === "ddl") await fetchDdl(true);
else if (activeTableInfoTab.value === "columns") await fetchTableInfoColumns(true);
else if (activeTableInfoTab.value === "indexes") {
indexesLoaded.value = false;
await fetchIndexes();
} else if (activeTableInfoTab.value === "foreignKeys") {
foreignKeysLoaded.value = false;
await fetchForeignKeys();
} else if (activeTableInfoTab.value === "constraints") {
constraintsLoaded.value = false;
await fetchConstraints();
} else if (activeTableInfoTab.value === "triggers") {
triggersLoaded.value = false;
await fetchTriggers();
}
}
async function fetchIndexes() {
const requestIdentity = currentIndexTableIdentity.value;
if (!props.connectionId || !props.tableMeta || !canShowTableIndexes.value || !requestIdentity || indexesLoaded.value || indexesLoading.value) return;
@@ -11318,6 +11388,9 @@ async function fetchConstraints() {
watch(
() => [props.connectionId, props.database, props.tableMeta?.catalog, props.tableMeta?.schema, props.tableMeta?.tableName],
() => {
tableInfoColumns.value = props.tableMeta?.columns ?? [];
tableInfoColumnsLoading.value = false;
tableInfoColumnsRequestGeneration += 1;
tableOwner.value = null;
tableOwnerLoading.value = false;
tableOwnerError.value = "";
@@ -11350,6 +11423,13 @@ watch(
},
);
watch(
() => props.tableMeta?.columns,
(columns) => {
if (!tableInfoColumnsLoading.value) tableInfoColumns.value = columns ?? [];
},
);
watch([showTableInfo, canShowTableOwner], ([shown, supported]) => {
if (shown && supported && !tableOwnerLoading.value && tableOwner.value === null && !tableOwnerError.value) void fetchTableOwner();
});
@@ -11793,7 +11873,7 @@ onUnmounted(() => {
stopLoadingElapsedTimer();
});
const filteredColumns = computed(() => filterObjectBrowserTableColumns(props.tableMeta?.columns ?? [], searchQuery.value));
const filteredColumns = computed(() => filterObjectBrowserTableColumns(tableInfoColumns.value, searchQuery.value));
const filteredIndexes = computed(() => {
if (!searchQuery.value) return indexes.value;
@@ -14002,6 +14082,9 @@ function openGridSnapshot() {
<X class="w-3 h-3" />
</button>
</div>
<Button variant="ghost" size="icon" class="h-7 w-7 shrink-0" :disabled="activeTableInfoLoading" :title="t('structureEditor.refresh')" :aria-label="t('structureEditor.refresh')" @click="refreshActiveTableInfo">
<RefreshCw class="h-3.5 w-3.5" :class="{ 'animate-spin': activeTableInfoLoading }" />
</Button>
<template v-if="activeTableInfoTab === 'ddl'">
<span class="w-9 shrink-0 text-center text-[11px] tabular-nums text-muted-foreground">
{{ searchQuery ? (ddlSearchMatchCount > 0 ? `${ddlSearchMatchIndex + 1}/${ddlSearchMatchCount}` : "0") : "" }}
@@ -14017,7 +14100,10 @@ function openGridSnapshot() {
</div>
<div v-if="activeTableInfoTab === 'columns'" class="flex-1 min-h-0 overflow-auto">
<div v-if="searchQuery && filteredColumns.length === 0" class="p-6 text-center text-xs text-muted-foreground">
<div v-if="tableInfoColumnsLoading" class="h-full flex items-center justify-center">
<Loader2 class="w-4 h-4 animate-spin text-muted-foreground" />
</div>
<div v-else-if="searchQuery && filteredColumns.length === 0" class="p-6 text-center text-xs text-muted-foreground">
{{ t("grid.tableInfoNoResults") }}
</div>
<table v-else class="w-full text-xs">
@@ -7,4 +7,15 @@ describe("DataGrid DDL search navigation", () => {
it("resets navigation when the raw search query changes", () => {
expect(dataGridSource).toMatch(/watch\(\s*\[filteredDdlContent, searchQuery\],/);
});
it("uses the shared DDL cache policy and exposes refresh controls", () => {
expect(dataGridSource).toContain('from "@/lib/metadata/objectDdlCache"');
expect(dataGridSource).toContain("async function fetchDdl(force = settingsStore.editorSettings.refreshDdlOnOpen)");
expect(dataGridSource).toMatch(/loadObjectDdl\([\s\S]*?objectType: tableObjectSourceKind\(props\.tableMeta\.tableType\),[\s\S]*?\{ force \},/);
expect(dataGridSource).toMatch(/async function refreshActiveTableInfo\(\)[\s\S]*?fetchDdl\(true\)[\s\S]*?fetchTableInfoColumns\(true\)[\s\S]*?fetchIndexes\(\)[\s\S]*?fetchForeignKeys\(\)[\s\S]*?fetchConstraints\(\)[\s\S]*?fetchTriggers\(\)/);
expect(dataGridSource).toContain('@click="refreshActiveTableInfo"');
expect(dataGridSource).toMatch(/loadObjectMetadataFacet\(request, "columns"/);
expect(dataGridSource).toMatch(/activeTableInfoTab\.value === "constraints"\) return constraintsLoading\.value/);
expect(dataGridSource).not.toContain("setTableInfoRefreshDdlOnOpen");
});
});
@@ -12,6 +12,8 @@ import { formatSqlForDisplay, type SqlFormatDialect } from "@/lib/sql/sqlFormatt
import { loadObjectDdl } from "@/lib/metadata/objectDdlCache";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Switch } from "@/components/ui/switch";
import { HelpTooltip } from "@/components/ui/tooltip";
import EditorSearchPanel from "@/components/editor/EditorSearchPanel.vue";
import type { EditorView } from "@codemirror/view";
import type { DatabaseType, ObjectSourceKind } from "@/types/database";
@@ -131,7 +133,7 @@ async function loadDdl(force = false) {
}
}
/** Loads the persisted table DDL when the dialog opens. */
/** Loads from the persisted snapshot by default; users can opt into a fresh database query on every open. */
watch(
() => props.open,
async (open) => {
@@ -140,7 +142,7 @@ watch(
const active = document.activeElement;
editorRootToRestoreFocus = active instanceof HTMLElement ? active.closest(".cm-editor") : null;
ddlContent.value = "";
await loadDdl();
await loadDdl(settingsStore.editorSettings.refreshDdlOnOpen);
},
{ immediate: true },
);
@@ -269,6 +271,11 @@ function retry() {
void loadDdl(true);
}
function setRefreshDdlOnOpen(value: boolean) {
settingsStore.updateEditorSettings({ refreshDdlOnOpen: value });
if (value) void loadDdl(true);
}
function onClose() {
emit("update:open", false);
}
@@ -298,6 +305,15 @@ function onClose() {
</div>
</div>
<DialogFooter>
<div class="mr-auto flex items-center gap-2 text-sm text-muted-foreground">
<Switch id="ddl-refresh-on-open" size="sm" :model-value="settingsStore.editorSettings.refreshDdlOnOpen" @update:model-value="setRefreshDdlOnOpen" />
<div class="flex items-center gap-1">
<label for="ddl-refresh-on-open" class="cursor-pointer">{{ t("contextMenu.refreshDdlOnOpen") }}</label>
<HelpTooltip :label="t('contextMenu.refreshDdlOnOpenHint')" trigger-class="[&_svg]:h-3 [&_svg]:w-3">
{{ t("contextMenu.refreshDdlOnOpenHint") }}
</HelpTooltip>
</div>
</div>
<Button variant="outline" @click="onClose">{{ t("common.close") }}</Button>
<Button variant="outline" :disabled="ddlLoading" :title="t('structureEditor.refresh')" @click="loadDdl(true)">
<RefreshCw class="h-4 w-4" />
@@ -246,6 +246,13 @@ const tableConstraintsLoaded = ref(false);
const tableConstraintsForTab = computed(() => constraintsForConstraintsTab(tableConstraints.value, tableMetadataCapabilities.value.foreignKeys));
const tableInfoSearchQuery = ref("");
const tableInfoDdlPreRef = ref<HTMLPreElement | null>(null);
const activeTableInfoLoading = computed(() => {
if (tableInfoTab.value === "ddl") return tableDdlLoading.value;
if (tableInfoTab.value === "columns") return tableColumnsLoading.value;
if (tableInfoTab.value === "indexes") return tableIndexesLoading.value;
if (tableInfoTab.value === "foreignKeys") return tableForeignKeysLoading.value;
return tableInfoTab.value === "triggers" && tableTriggersLoading.value;
});
const SIDE_PANEL_MIN_WIDTH = 280;
const SIDE_PANEL_MAX_WIDTH = 900;
const sidePanelWidth = ref(settingsStore.editorSettings.tableInfoDrawerWidth || 420);
@@ -1098,7 +1105,7 @@ function tableMetadataRequest(row: ObjectBrowserRow): ObjectDdlRequest {
};
}
async function fetchTableDdl(force = false) {
async function fetchTableDdl(force = settingsStore.editorSettings.refreshDdlOnOpen) {
const row = sidePanelRow.value;
if (!row || (tableDdlLoaded.value && !force)) return;
const epoch = sidePanelGuard.capture();
@@ -3536,14 +3543,17 @@ function getObjectBrowserMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
<span class="block truncate">{{ tab.label }}</span>
</button>
</div>
<div class="px-2 py-1.5 border-b shrink-0 bg-background">
<div class="relative">
<div class="flex items-center gap-1 px-2 py-1.5 border-b shrink-0 bg-background">
<div class="relative min-w-0 flex-1">
<Search class="absolute left-2 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-muted-foreground" />
<input v-model="tableInfoSearchQuery" :placeholder="t('grid.tableInfoSearch')" class="w-full h-7 pl-7 pr-6 text-xs bg-muted/50 rounded border border-border focus:outline-none focus:border-primary/50" @keydown.escape="tableInfoSearchQuery = ''" />
<button v-if="tableInfoSearchQuery" class="absolute right-1.5 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground" @click="tableInfoSearchQuery = ''">
<X class="w-3 h-3" />
</button>
</div>
<Button variant="ghost" size="icon" class="h-7 w-7 shrink-0" :disabled="activeTableInfoLoading" :title="t('structureEditor.refresh')" :aria-label="t('structureEditor.refresh')" @click="refreshActiveTableInfo">
<RefreshCw class="h-3.5 w-3.5" :class="{ 'animate-spin': activeTableInfoLoading }" />
</Button>
</div>
<div v-if="tableInfoTab === 'columns'" class="flex-1 min-h-0 overflow-auto">
<div v-if="tableColumnsLoading" class="h-full flex items-center justify-center">
@@ -0,0 +1,19 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const source = readFileSync(new URL("../DdlViewDialog.vue", import.meta.url), "utf8");
describe("DdlViewDialog freshness", () => {
it("uses the persisted refresh preference when the dialog opens", () => {
expect(source).toMatch(/watch\(\s*\(\) => props\.open,[\s\S]*?await loadDdl\(settingsStore\.editorSettings\.refreshDdlOnOpen\);/);
});
it("refreshes the current DDL immediately when the preference is enabled", () => {
expect(source).toMatch(/function setRefreshDdlOnOpen\(value: boolean\)[\s\S]*?if \(value\) void loadDdl\(true\);/);
});
it("explains how the refresh preference affects cached DDL", () => {
expect(source).toContain('import { HelpTooltip } from "@/components/ui/tooltip";');
expect(source).toMatch(/<HelpTooltip :label="t\('contextMenu\.refreshDdlOnOpenHint'\)"[\s\S]*?t\("contextMenu\.refreshDdlOnOpenHint"\)[\s\S]*?<\/HelpTooltip>/);
});
});
@@ -47,6 +47,12 @@ describe("ObjectBrowser table metadata refresh", () => {
}
});
it("shares the DDL refresh preference and exposes an explicit refresh action", () => {
expect(source).toContain("async function fetchTableDdl(force = settingsStore.editorSettings.refreshDdlOnOpen)");
expect(source).toContain('@click="refreshActiveTableInfo"');
expect(source).not.toContain("setTableInfoRefreshDdlOnOpen");
});
it("keeps automatic object reloads free of extra metadata requests", () => {
expect(functionBody("reload")).not.toContain("refreshActiveTableInfo");
});
+2
View File
@@ -3094,6 +3094,8 @@ export default {
viewDdl: "View DDL",
viewDdlLoading: "Loading DDL...",
ddlCopied: "DDL copied",
refreshDdlOnOpen: "Refresh each time it opens",
refreshDdlOnOpenHint: "When enabled, DDL is reloaded from the database each time it opens; when disabled, cached data is preferred",
dropObject: "Drop Object",
dropEventSuccess: 'Event "{name}" dropped',
editObject: "Edit Object",
+2
View File
@@ -2994,6 +2994,8 @@ export default withEnglishFallback({
viewDdl: "Ver DDL",
viewDdlLoading: "Cargando DDL...",
ddlCopied: "DDL copiado",
refreshDdlOnOpen: "Actualizar cada vez que se abra",
refreshDdlOnOpenHint: "Si se activa, el DDL se vuelve a cargar de la base de datos cada vez que se abre; si se desactiva, se usan primero los datos en caché",
dropObject: "Eliminar objeto",
dropView: "Eliminar vista",
dropColumn: "Eliminar columna",
+2
View File
@@ -2992,6 +2992,8 @@ export default withEnglishFallback({
viewDdl: "Visualizza DDL",
viewDdlLoading: "Caricamento DDL...",
ddlCopied: "DDL copiato",
refreshDdlOnOpen: "Aggiorna a ogni apertura",
refreshDdlOnOpenHint: "Se attivo, il DDL viene ricaricato dal database a ogni apertura; se disattivo, vengono usati prima i dati memorizzati nella cache",
dropObject: "Elimina Oggetto",
dropView: "Elimina Vista",
dropColumn: "Elimina Colonna",
+2
View File
@@ -3225,6 +3225,8 @@ export default withEnglishFallback({
instanceInfo: "インスタンス情報",
viewDdlLoading: "DDLを読み込み中...",
ddlCopied: "DDLをコピーしました",
refreshDdlOnOpen: "開くたびに更新",
refreshDdlOnOpenHint: "有効にすると開くたびにデータベースから DDL を再取得し、無効にするとキャッシュを優先して使用します",
manageExtension: "拡張機能を管理...",
dropExtension: "拡張機能を削除",
processList: "プロセス一覧",
+2
View File
@@ -3113,6 +3113,8 @@ export default withEnglishFallback({
eventLoading: "Loading...",
eventCancel: "Cancel",
eventSave: "Save",
refreshDdlOnOpen: "열 때마다 새로 고침",
refreshDdlOnOpenHint: "켜면 열 때마다 데이터베이스에서 DDL을 다시 불러오고, 끄면 캐시된 데이터를 우선 사용합니다",
},
visibleDatabases: {
title: "표시할 데이터베이스",
+2
View File
@@ -2990,6 +2990,8 @@ export default withEnglishFallback({
viewDdl: "Ver DDL",
viewDdlLoading: "Carregando DDL...",
ddlCopied: "DDL copiado",
refreshDdlOnOpen: "Atualizar sempre que abrir",
refreshDdlOnOpenHint: "Quando ativado, o DDL é recarregado do banco de dados sempre que é aberto; quando desativado, os dados em cache têm prioridade",
dropObject: "Remover Objeto",
dropView: "Remover Visão",
dropColumn: "Remover Coluna",
+2
View File
@@ -3017,6 +3017,8 @@ export default withEnglishFallback({
viewDdl: "查看 DDL",
viewDdlLoading: "正在读取 DDL...",
ddlCopied: "DDL 已复制",
refreshDdlOnOpen: "每次打开时刷新",
refreshDdlOnOpenHint: "开启后每次打开都会从数据库重新读取;关闭时优先使用缓存",
dropObject: "删除对象",
dropView: "删除视图",
dropColumn: "删除字段",
+2
View File
@@ -2991,6 +2991,8 @@ export default withEnglishFallback({
viewDdl: "檢視 DDL",
viewDdlLoading: "正在讀取 DDL...",
ddlCopied: "DDL 已複製",
refreshDdlOnOpen: "每次開啟時重新整理",
refreshDdlOnOpenHint: "開啟後每次開啟都會從資料庫重新讀取;關閉時優先使用快取",
dropObject: "刪除物件",
dropView: "刪除檢視",
dropColumn: "刪除欄位",
@@ -5,6 +5,13 @@ import { DEFAULT_EDITOR_SETTINGS, EXECUTE_MODE_CURRENT_DEFAULT_VERSION, enforceR
import type { AiConfigItem } from "@/types/ai";
describe("normalizeEditorSettings", () => {
it("keeps automatic DDL refresh disabled unless explicitly enabled", () => {
expect(normalizeEditorSettings({}).refreshDdlOnOpen).toBe(false);
expect(normalizeEditorSettings({ refreshDdlOnOpen: true }).refreshDdlOnOpen).toBe(true);
expect(normalizeEditorSettings({ refreshDdlOnOpen: false }).refreshDdlOnOpen).toBe(false);
expect(normalizeEditorSettings({ refreshDdlOnOpen: "true" } as any).refreshDdlOnOpen).toBe(false);
});
it("enables SQL variable substitution by default and only preserves booleans", () => {
expect(normalizeEditorSettings({}).sqlVariableSubstitutionEnabled).toBe(true);
expect(normalizeEditorSettings({ sqlVariableSubstitutionEnabled: true }).sqlVariableSubstitutionEnabled).toBe(true);
+4
View File
@@ -596,6 +596,7 @@ export interface EditorSettings {
selectFirstCompletionOnOpen: boolean;
wordWrap: boolean;
tableDdlWordWrap: boolean;
refreshDdlOnOpen: boolean;
vimModeEnabled: boolean;
autoCloseBrackets: boolean;
sqlSemanticDiagnosticsMode: SqlSemanticDiagnosticsMode;
@@ -817,6 +818,7 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
selectFirstCompletionOnOpen: true,
wordWrap: false,
tableDdlWordWrap: true,
refreshDdlOnOpen: false,
vimModeEnabled: false,
autoCloseBrackets: true,
sqlSemanticDiagnosticsMode: "auto",
@@ -1227,6 +1229,7 @@ export function normalizeEditorSettings(settings: Partial<EditorSettings>, exist
selectFirstCompletionOnOpen: typeof settings.selectFirstCompletionOnOpen === "boolean" ? settings.selectFirstCompletionOnOpen : DEFAULT_EDITOR_SETTINGS.selectFirstCompletionOnOpen,
wordWrap: settings.wordWrap ?? DEFAULT_EDITOR_SETTINGS.wordWrap,
tableDdlWordWrap: typeof settings.tableDdlWordWrap === "boolean" ? settings.tableDdlWordWrap : DEFAULT_EDITOR_SETTINGS.tableDdlWordWrap,
refreshDdlOnOpen: typeof settings.refreshDdlOnOpen === "boolean" ? settings.refreshDdlOnOpen : DEFAULT_EDITOR_SETTINGS.refreshDdlOnOpen,
vimModeEnabled: typeof settings.vimModeEnabled === "boolean" ? settings.vimModeEnabled : DEFAULT_EDITOR_SETTINGS.vimModeEnabled,
autoCloseBrackets: typeof settings.autoCloseBrackets === "boolean" ? settings.autoCloseBrackets : DEFAULT_EDITOR_SETTINGS.autoCloseBrackets,
sqlSemanticDiagnosticsMode,
@@ -1847,6 +1850,7 @@ export const useSettingsStore = defineStore("settings", () => {
if (partial.selectFirstCompletionOnOpen !== undefined) editorSettings.value.selectFirstCompletionOnOpen = partial.selectFirstCompletionOnOpen === true;
if (partial.wordWrap !== undefined) editorSettings.value.wordWrap = partial.wordWrap;
if (partial.tableDdlWordWrap !== undefined) editorSettings.value.tableDdlWordWrap = partial.tableDdlWordWrap === true;
if (partial.refreshDdlOnOpen !== undefined) editorSettings.value.refreshDdlOnOpen = partial.refreshDdlOnOpen === true;
if (partial.vimModeEnabled !== undefined) editorSettings.value.vimModeEnabled = partial.vimModeEnabled === true;
if (partial.autoCloseBrackets !== undefined) editorSettings.value.autoCloseBrackets = partial.autoCloseBrackets === true;
if (partial.sqlSemanticDiagnosticsMode !== undefined || partial.sqlSemanticDiagnosticsEnabled !== undefined) {