fix(sql-format): format source and DDL with proper dialects
This commit is contained in:
1 parent
ed35164828
commit
ff810f3058
7 files changed
+136
-56
No files matched your search
@@ -63,7 +63,7 @@ import type { SqlExecutionOverride } from "@/lib/sqlExecutionTarget";
|
||||
import type { DataGridSortMode } from "@/lib/dataGridSort";
|
||||
import { useTabScroll } from "@/composables/useTabScroll";
|
||||
import type { QueryTab, ConnectionConfig, TableInfoTab, TreeNode, VectorCollectionMeta } from "@/types/database";
|
||||
import type { SqlFormatDialect } from "@/lib/sqlFormatter";
|
||||
import { sqlFormatDialectForDbType, type SqlFormatDialect } from "@/lib/sqlFormatter";
|
||||
|
||||
type DataGridHandle = {
|
||||
onToolbarRefresh: () => Promise<void> | void;
|
||||
@@ -196,23 +196,7 @@ const activeTabDimension = computed(() => {
|
||||
return meta && "dimension" in meta ? (meta as VectorCollectionMeta).dimension : undefined;
|
||||
});
|
||||
|
||||
const activeSqlFormatDialect = computed<SqlFormatDialect>(() => {
|
||||
switch (activeEffectiveDatabaseType.value) {
|
||||
case "mysql":
|
||||
return "mysql";
|
||||
case "postgres":
|
||||
case "kwdb":
|
||||
return "postgres";
|
||||
case "sqlite":
|
||||
case "rqlite":
|
||||
case "turso":
|
||||
return "sqlite";
|
||||
case "sqlserver":
|
||||
return "sqlserver";
|
||||
default:
|
||||
return "generic";
|
||||
}
|
||||
});
|
||||
const activeSqlFormatDialect = computed<SqlFormatDialect>(() => sqlFormatDialectForDbType(activeEffectiveDatabaseType.value));
|
||||
|
||||
const editorDialect = computed<"mysql" | "postgres" | "sqlserver">(() => {
|
||||
if (activeEffectiveDatabaseType.value === "postgres" || activeEffectiveDatabaseType.value === "kwdb") return "postgres";
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import { loadEditorTheme, editorFontTheme } from "@/lib/editorThemes";
|
||||
import { createDbxCodeMirrorSqlDialect } from "@/lib/codemirrorSqlDialect";
|
||||
import { copyToClipboard } from "@/lib/clipboard";
|
||||
import { formatSqlForDisplay, type SqlFormatDialect } from "@/lib/sqlFormatter";
|
||||
import * as api from "@/lib/api";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
@@ -23,6 +24,8 @@ const props = withDefaults(
|
||||
tableName: string;
|
||||
/** SQL dialect for syntax highlighting. Non-PG/non-MSSQL databases fall back to MySQL (same as QueryEditor's source viewer). */
|
||||
dialect: "mysql" | "postgres" | "sqlserver";
|
||||
/** SQL formatter dialect. Kept separate from the syntax-highlighting dialect because several PG-compatible DBs highlight as MySQL. */
|
||||
formatDialect?: SqlFormatDialect;
|
||||
}>(),
|
||||
{},
|
||||
);
|
||||
@@ -54,7 +57,7 @@ watch(
|
||||
try {
|
||||
const schema = props.schema || props.database;
|
||||
const ddl = await api.getTableDdl(props.connectionId, props.database, schema, props.tableName);
|
||||
ddlContent.value = ddl;
|
||||
ddlContent.value = await formatSqlForDisplay(ddl, props.formatDialect ?? props.dialect, settingsStore.editorSettings.sqlFormatter);
|
||||
} catch (e: any) {
|
||||
ddlError.value = e?.message || String(e);
|
||||
} finally {
|
||||
@@ -160,8 +163,8 @@ function retry() {
|
||||
const schema = props.schema || props.database;
|
||||
api
|
||||
.getTableDdl(props.connectionId, props.database, schema, props.tableName)
|
||||
.then((ddl) => {
|
||||
ddlContent.value = ddl;
|
||||
.then(async (ddl) => {
|
||||
ddlContent.value = await formatSqlForDisplay(ddl, props.formatDialect ?? props.dialect, settingsStore.editorSettings.sqlFormatter);
|
||||
})
|
||||
.catch((e: any) => {
|
||||
ddlError.value = e?.message || String(e);
|
||||
|
||||
@@ -67,7 +67,7 @@ import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import { useQueryStore } from "@/stores/queryStore";
|
||||
import QueryEditor from "@/components/editor/QueryEditor.vue";
|
||||
import DdlViewDialog from "./DdlViewDialog.vue";
|
||||
import type { SqlFormatDialect } from "@/lib/sqlFormatter";
|
||||
import { formatSqlForDisplay, sqlFormatDialectForDbType, type SqlFormatDialect } from "@/lib/sqlFormatter";
|
||||
import { isCancelSearchShortcut } from "@/lib/keyboardShortcuts";
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import {
|
||||
@@ -122,6 +122,7 @@ const sourceRow = ref<ObjectBrowserRow | null>(null);
|
||||
const sourceEditing = ref(false);
|
||||
const effectiveDatabaseType = computed(() => effectiveDatabaseTypeForConnection(props.connection) ?? props.connection.db_type);
|
||||
const tableStructureDatabaseType = computed(() => tableStructureDatabaseTypeForConnection(props.connection) ?? props.connection.db_type);
|
||||
const sourceEditableText = ref("");
|
||||
const sourceDraft = ref("");
|
||||
const sourceSaving = ref(false);
|
||||
const sourceSaveError = ref("");
|
||||
@@ -178,25 +179,7 @@ const canOpenDiagram = computed(() => !!props.database && supportsSchemaDiagram(
|
||||
const canOpenTableImport = computed(() => !!props.database && supportsTableImport(effectiveDatabaseType.value));
|
||||
const supportsTruncateTable = computed(() => supportsTableTruncate(effectiveDatabaseType.value));
|
||||
const sourceDialect = computed(() => codeMirrorSqlDialect(effectiveDatabaseType.value));
|
||||
const sourceFormatDialect = computed<SqlFormatDialect>(() => {
|
||||
switch (effectiveDatabaseType.value) {
|
||||
case "mysql":
|
||||
case "postgres":
|
||||
case "sqlite":
|
||||
case "sqlserver":
|
||||
return effectiveDatabaseType.value;
|
||||
case "rqlite":
|
||||
case "turso":
|
||||
return "sqlite";
|
||||
case "gaussdb":
|
||||
case "kwdb":
|
||||
case "opengauss":
|
||||
case "questdb":
|
||||
return "postgres";
|
||||
default:
|
||||
return "generic";
|
||||
}
|
||||
});
|
||||
const sourceFormatDialect = computed<SqlFormatDialect>(() => sqlFormatDialectForDbType(effectiveDatabaseType.value));
|
||||
const objectFilters = computed<ObjectFilter[]>(() =>
|
||||
(
|
||||
[
|
||||
@@ -425,6 +408,7 @@ async function openSource(row: ObjectBrowserRow) {
|
||||
sourceContent.value = "";
|
||||
sourceError.value = "";
|
||||
sourceEditing.value = false;
|
||||
sourceEditableText.value = "";
|
||||
sourceDraft.value = "";
|
||||
sourceSaveError.value = "";
|
||||
sourceLoading.value = true;
|
||||
@@ -437,7 +421,8 @@ async function openSource(row: ObjectBrowserRow) {
|
||||
name: row.name,
|
||||
source: result.source,
|
||||
});
|
||||
sourceContent.value = editable;
|
||||
sourceEditableText.value = editable;
|
||||
sourceContent.value = await formatSqlForDisplay(editable, sourceFormatDialect.value, settingsStore.editorSettings.sqlFormatter);
|
||||
sourceDraft.value = editable;
|
||||
sourceEditing.value = row.type !== "SEQUENCE";
|
||||
} catch (e: any) {
|
||||
@@ -457,8 +442,9 @@ async function openViewDdl(row: ObjectBrowserRow) {
|
||||
name: row.name,
|
||||
source: result.source,
|
||||
});
|
||||
const formatted = await formatSqlForDisplay(ddl, sourceFormatDialect.value, settingsStore.editorSettings.sqlFormatter);
|
||||
const tabId = queryStore.createTab(props.connection.id, props.database, `DDL - ${row.name}`);
|
||||
queryStore.updateSql(tabId, ddl);
|
||||
queryStore.updateSql(tabId, formatted);
|
||||
} catch (e: any) {
|
||||
toast(e?.message || String(e), 5000);
|
||||
}
|
||||
@@ -630,6 +616,7 @@ function closeSource() {
|
||||
sourceContent.value = "";
|
||||
sourceError.value = "";
|
||||
sourceEditing.value = false;
|
||||
sourceEditableText.value = "";
|
||||
sourceDraft.value = "";
|
||||
sourceSaveError.value = "";
|
||||
}
|
||||
@@ -1040,8 +1027,8 @@ async function copySource() {
|
||||
}
|
||||
|
||||
function editSource() {
|
||||
if (!sourceRow.value || !sourceContent.value) return;
|
||||
sourceDraft.value = sourceContent.value;
|
||||
if (!sourceRow.value || !sourceEditableText.value) return;
|
||||
sourceDraft.value = sourceEditableText.value;
|
||||
sourceSaveError.value = "";
|
||||
sourceEditing.value = true;
|
||||
}
|
||||
@@ -1684,7 +1671,7 @@ function getObjectBrowserMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<DdlViewDialog v-if="ddlDialogTarget" :connection-id="props.connection.id" :database="props.database" :schema="ddlDialogTarget.schema || selectedSchema" :table-name="ddlDialogTarget.name" :dialect="sourceDialect" v-model:open="showDdlDialog" />
|
||||
<DdlViewDialog v-if="ddlDialogTarget" :connection-id="props.connection.id" :database="props.database" :schema="ddlDialogTarget.schema || selectedSchema" :table-name="ddlDialogTarget.name" :dialect="sourceDialect" :format-dialect="sourceFormatDialect" v-model:open="showDdlDialog" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -100,6 +100,7 @@ import {
|
||||
import { buildRenameObjectSql, supportsObjectRename, type RenameableObjectType } from "@/lib/objectRenameSql";
|
||||
import { buildRoutineRenameObjectSourceStatements, supportsSourceBackedRoutineRename } from "@/lib/objectSourceEditor";
|
||||
import { buildViewDdl } from "@/lib/viewDdl";
|
||||
import { formatSqlForDisplay, sqlFormatDialectForDbType } from "@/lib/sqlFormatter";
|
||||
import DdlViewDialog from "@/components/objects/DdlViewDialog.vue";
|
||||
import { getTableStructureCapabilities } from "@/lib/tableStructureCapabilities";
|
||||
import { codeMirrorSqlDialect, connectionObjectTreeNodeSchema, connectionObjectTreeQuerySchema, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection, tableStructureDatabaseTypeForConnection } from "@/lib/jdbcDialect";
|
||||
@@ -1278,7 +1279,8 @@ async function generateDdlTemplate() {
|
||||
source: result.source,
|
||||
});
|
||||
}
|
||||
openSqlTemplateTab(node.connectionId, node.database, node.schema, ddl, `DDL - ${node.label}`);
|
||||
const formatted = await formatSqlForDisplay(ddl, sqlFormatDialectForDbType(currentDatabaseType()), settingsStore.editorSettings.sqlFormatter);
|
||||
openSqlTemplateTab(node.connectionId, node.database, node.schema, formatted, `DDL - ${node.label}`);
|
||||
} catch (e: any) {
|
||||
toast(e?.message || String(e), 5000);
|
||||
}
|
||||
@@ -1452,6 +1454,10 @@ const ddlDialect = computed(() => {
|
||||
if (!ddlTarget.value?.connectionId) return "mysql";
|
||||
return codeMirrorSqlDialect(effectiveDatabaseTypeForConnection(connectionStore.getConfig(ddlTarget.value.connectionId)));
|
||||
});
|
||||
const ddlFormatDialect = computed(() => {
|
||||
if (!ddlTarget.value?.connectionId) return "generic";
|
||||
return sqlFormatDialectForDbType(effectiveDatabaseTypeForConnection(connectionStore.getConfig(ddlTarget.value.connectionId)));
|
||||
});
|
||||
const showCreateDatabaseDialog = ref(false);
|
||||
const createDatabaseName = ref("");
|
||||
const createDatabaseCharset = ref("utf8mb4");
|
||||
@@ -1619,7 +1625,8 @@ function viewObjectSource() {
|
||||
})
|
||||
.then(async (result) => {
|
||||
const tabId = queryStore.createTab(node.connectionId!, node.database!, `Source - ${node.label}`);
|
||||
queryStore.updateSql(tabId, result.source);
|
||||
const formatted = await formatSqlForDisplay(result.source, sqlFormatDialectForDbType(currentDatabaseType()), settingsStore.editorSettings.sqlFormatter);
|
||||
queryStore.updateSql(tabId, formatted);
|
||||
if (objectType !== "SEQUENCE") {
|
||||
queryStore.setObjectSource(tabId, {
|
||||
schema,
|
||||
@@ -1653,8 +1660,9 @@ function viewObjectDdl() {
|
||||
name: node.label,
|
||||
source: result.source,
|
||||
});
|
||||
const formatted = await formatSqlForDisplay(ddl, sqlFormatDialectForDbType(effectiveDatabaseTypeForConnection(connection)), settingsStore.editorSettings.sqlFormatter);
|
||||
const tabId = queryStore.createTab(node.connectionId!, node.database!, `DDL - ${node.label}`);
|
||||
queryStore.updateSql(tabId, ddl);
|
||||
queryStore.updateSql(tabId, formatted);
|
||||
})
|
||||
.catch((e: any) => {
|
||||
toast(e?.message || String(e), 5000);
|
||||
@@ -4432,7 +4440,7 @@ function treeItemMenuItems(): ContextMenuItem[] {
|
||||
|
||||
<DangerConfirmDialog v-model:open="showDropSchemaConfirm" :title="t('contextMenu.confirmDropSchemaTitle')" :message="t('contextMenu.confirmDropSchemaMessage', { name: node.label })" :sql="dropSchemaPreviewSql" :confirm-label="t('contextMenu.dropSchema')" @confirm="confirmDropSchema" />
|
||||
|
||||
<DdlViewDialog v-if="ddlTarget" :connection-id="ddlTarget.connectionId!" :database="ddlTarget.database!" :schema="ddlTarget.schema" :table-name="ddlTarget.label" :dialect="ddlDialect" v-model:open="showDdlDialog" />
|
||||
<DdlViewDialog v-if="ddlTarget" :connection-id="ddlTarget.connectionId!" :database="ddlTarget.database!" :schema="ddlTarget.schema" :table-name="ddlTarget.label" :dialect="ddlDialect" :format-dialect="ddlFormatDialect" v-model:open="showDdlDialog" />
|
||||
</template>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -20,6 +20,7 @@ import { useTheme } from "@/composables/useTheme";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
import { type SqlHighlighter, createShikiSqlHighlighter } from "@/lib/sqlHighlighter";
|
||||
import { copyToClipboard } from "@/lib/clipboard";
|
||||
import { formatSqlForDisplay, sqlFormatDialectForDbType } from "@/lib/sqlFormatter";
|
||||
import { queryTimeoutSecsForConnection } from "@/lib/queryTimeout";
|
||||
import { type EditableStructureColumn, type EditableStructureForeignKey, type EditableStructureIndex, type EditableStructureTrigger } from "@/lib/tableStructureEditorSql";
|
||||
import { PRESET_FIELDS_TEMPLATE_ID, createTableColumnTemplateDrafts } from "@/lib/tableColumnTemplates";
|
||||
@@ -101,7 +102,8 @@ async function fetchDdl() {
|
||||
if (!props.connectionId || !props.database || !props.tableName || ddlFetched.value || !tableMetadataCapabilities.value.ddl) return;
|
||||
ddlLoading.value = true;
|
||||
try {
|
||||
ddlContent.value = await api.getTableDdl(props.connectionId, props.database, metadataSchema.value, props.tableName);
|
||||
const ddl = await api.getTableDdl(props.connectionId, props.database, metadataSchema.value, props.tableName);
|
||||
ddlContent.value = await formatSqlForDisplay(ddl, sqlFormatDialectForDbType(databaseType.value), settingsStore.editorSettings.sqlFormatter);
|
||||
ddlFetched.value = true;
|
||||
} catch (e: any) {
|
||||
ddlContent.value = `-- Error: ${e?.message || e}`;
|
||||
@@ -794,7 +796,7 @@ async function loadStructure(silent = false, scope: StructureRefreshScope = FULL
|
||||
if (databaseType.value === "manticoresearch" && tableMetadataCapabilities.value.ddl) {
|
||||
try {
|
||||
const ddl = await api.getTableDdl(connectionId, database, schema, tableName);
|
||||
ddlContent.value = ddl;
|
||||
ddlContent.value = await formatSqlForDisplay(ddl, sqlFormatDialectForDbType(databaseType.value), settingsStore.editorSettings.sqlFormatter);
|
||||
ddlFetched.value = true;
|
||||
nextColumns = applyManticoreDdlColumnExtras(nextColumns, ddl);
|
||||
} catch {
|
||||
|
||||
Reference in new issue
Block a user