mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-20 00:17:44 +00:00
fix(editor): ignore formatter parse errors for incomplete SQL
Closes #5462
This commit is contained in:
@@ -18,7 +18,7 @@ import { executableStatementRangeAtCursor, executableStatementRangeCacheForDoc,
|
||||
import { currentStatementFrameRangeTo, shouldRebuildCurrentStatementFrame, visualSqlColumnsWithInlineHints } from "@/lib/sql/currentStatementFrame";
|
||||
import { expandToSqlStatementWindow, parseInsertValueHints } from "@/lib/sql/insertValueHints";
|
||||
import { insertValueHintColumnNames } from "@/lib/sql/insertValueHintColumns";
|
||||
import { formatSqlText, compressSqlText, type SqlFormatDialect } from "@/lib/sql/sqlFormatter";
|
||||
import { formatSqlForEditing, compressSqlText, type SqlFormatDialect } from "@/lib/sql/sqlFormatter";
|
||||
import { detectAndFormatStructured } from "@/lib/sql/autoFormat";
|
||||
import { enabledSqlParameterSyntaxes, resolveSqlVariableSyntaxToggles } from "@/lib/sql/sqlVariableSyntax";
|
||||
import { blankLineDeletionChanges, replaceSelectedEditorText } from "@/lib/editor/queryEditorTextEdits";
|
||||
@@ -2563,7 +2563,7 @@ async function formatCurrentSql() {
|
||||
toast(t("toolbar.formatAutoDetectFailed"), 3000);
|
||||
return;
|
||||
} else {
|
||||
formatted = await formatSqlText(source, props.formatDialect ?? props.dialect ?? "generic", settingsStore.editorSettings.sqlFormatter);
|
||||
formatted = await formatSqlForEditing(source, props.formatDialect ?? props.dialect ?? "generic", settingsStore.editorSettings.sqlFormatter);
|
||||
}
|
||||
}
|
||||
if (view.value !== currentView || currentView.state !== originalState || currentView.state.sliceDoc(from, to) !== source) {
|
||||
|
||||
+14
-1
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { formatSqlForDisplay, formatSqlText, MAX_SQL_FORMAT_CHARS, sqlFormatDialectForDbType, UnsupportedStructuredInputError } from "@/lib/sql/sqlFormatter";
|
||||
import { formatSqlForDisplay, formatSqlForEditing, formatSqlText, MAX_SQL_FORMAT_CHARS, sqlFormatDialectForDbType, UnsupportedStructuredInputError } from "@/lib/sql/sqlFormatter";
|
||||
|
||||
describe("sqlFormatter", () => {
|
||||
it("maps PostgreSQL-compatible database types to the postgres formatter dialect", () => {
|
||||
@@ -50,6 +50,19 @@ describe("sqlFormatter", () => {
|
||||
expect(formatted).toContain("AS id");
|
||||
});
|
||||
|
||||
it("keeps incomplete editor SQL unchanged when the formatter cannot parse it", async () => {
|
||||
const sql = "select *\nfrom dbname.\n;";
|
||||
|
||||
await expect(formatSqlText(sql, "mysql")).rejects.toThrow("Parse error at token:");
|
||||
await expect(formatSqlForEditing(sql, "mysql")).resolves.toBe(sql);
|
||||
});
|
||||
|
||||
it("keeps non-parse editor formatting failures visible", async () => {
|
||||
const oversizedSql = "x".repeat(MAX_SQL_FORMAT_CHARS + 1);
|
||||
|
||||
await expect(formatSqlForEditing(oversizedSql, "mysql")).rejects.toThrow("SQL is too large to format safely.");
|
||||
});
|
||||
|
||||
it("returns the original SQL for display when formatting fails", async () => {
|
||||
const oversizedSql = "x".repeat(MAX_SQL_FORMAT_CHARS + 1);
|
||||
|
||||
|
||||
@@ -106,6 +106,21 @@ export async function formatSqlText(sql: string, dialect: SqlFormatDialect = "ge
|
||||
}
|
||||
}
|
||||
|
||||
function isSqlFormatterParseError(error: unknown): boolean {
|
||||
if (!(error instanceof Error) || !error.message.startsWith("Parse error at token:")) return false;
|
||||
const candidate = error as Error & { offset?: unknown; token?: unknown };
|
||||
return typeof candidate.offset === "number" && candidate.token !== undefined;
|
||||
}
|
||||
|
||||
export async function formatSqlForEditing(sql: string, dialect: SqlFormatDialect = "generic", settings: Partial<SqlFormatterSettings> = DEFAULT_SQL_FORMATTER_SETTINGS): Promise<string> {
|
||||
try {
|
||||
return await formatSqlText(sql, dialect, settings);
|
||||
} catch (error) {
|
||||
if (isSqlFormatterParseError(error)) return sql;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩 SQL 时使用的方言。不同方言对引号、注释、转义的处理不同:
|
||||
* - `mysql`:保留 MySQL 可执行注释与 optimizer hint;单引号字符串支持反斜杠转义
|
||||
|
||||
Reference in New Issue
Block a user