fix(sql): support brace placeholders in formatter

This commit is contained in:
vrustx 2026-07-15 21:18:57 +08:00 committed by GitHub
parent 9234c33e24
commit c80313eed2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 46 additions and 3 deletions

View File

@ -14,6 +14,18 @@ describe("sqlFormatter", () => {
}
});
it("preserves DBX brace placeholders in generic and MySQL SQL", async () => {
const sql = "SELECT ${x} AS shell_value, #{x} AS mybatis_value, '${date}' AS quoted_value";
for (const dialect of ["generic", "mysql"] as const) {
const formatted = await formatSqlText(sql, dialect);
expect(formatted).toContain("${x}");
expect(formatted).toContain("#{x}");
expect(formatted).toContain("'${date}'");
}
});
it("falls back to the postgres formatter when the generic dialect cannot parse SQL", async () => {
const formatted = await formatSqlText("SELECT 1::int AS id;", "generic");

View File

@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { DEFAULT_SQL_FORMATTER_SETTINGS, parseSqlFormatterConfig, serializeSqlFormatterConfig } from "@/lib/sql/sqlFormatterConfig";
import { DEFAULT_SQL_FORMATTER_SETTINGS, parseSqlFormatterConfig, serializeSqlFormatterConfig, sqlFormatterOptions } from "@/lib/sql/sqlFormatterConfig";
describe("sqlFormatterConfig shortcut storage", () => {
it("does not serialize JSON editor shortcut settings", () => {
@ -23,4 +23,20 @@ describe("sqlFormatterConfig shortcut storage", () => {
expect(result.ok).toBe(true);
});
it("merges DBX custom parameter types with user paramTypes", () => {
const options = sqlFormatterOptions({
paramTypes: {
positional: false,
named: ["@"],
custom: [{ regex: String.raw`\{\{[^}]+\}\}` }],
},
});
expect(options.paramTypes).toEqual({
positional: false,
named: ["@"],
custom: [{ regex: String.raw`\{\{[^}]+\}\}` }, { regex: String.raw`\$\{[^}]+\}` }, { regex: String.raw`#\{[^}]+\}` }],
});
});
});

View File

@ -22,6 +22,11 @@ export interface SqlFormatterCustomParameter {
regex: string;
}
// DBX substitutes `${name}`/`#{name}` placeholders client-side (see sqlVariableSyntax.ts),
// but no sql-formatter dialect tokenizes them, so raw SQL containing them would fail to
// format with a parse error. Always registering them as custom params keeps formatting working.
const DBX_CUSTOM_PARAM_TYPES: SqlFormatterCustomParameter[] = [{ regex: String.raw`\$\{[^}]+\}` }, { regex: String.raw`#\{[^}]+\}` }];
export interface SqlFormatterParamTypes {
positional?: boolean;
numbered?: ("?" | ":" | "$")[];
@ -239,6 +244,7 @@ export function syncSqlFormatterConfigDraft(text: string, syncSettings: (setting
export function sqlFormatterOptions(settings: unknown) {
const normalized = sqlFormatterOptionSettings(settings);
const paramTypes = normalized.paramTypes ?? {};
return {
keywordCase: normalized.keywordCase,
dataTypeCase: normalized.dataTypeCase,
@ -252,6 +258,9 @@ export function sqlFormatterOptions(settings: unknown) {
linesBetweenQueries: normalized.linesBetweenQueries,
denseOperators: normalized.denseOperators,
newlineBeforeSemicolon: normalized.newlineBeforeSemicolon,
...(normalized.paramTypes !== null ? { paramTypes: normalized.paramTypes } : {}),
paramTypes: {
...paramTypes,
custom: [...(paramTypes.custom ?? []), ...DBX_CUSTOM_PARAM_TYPES],
},
};
}

View File

@ -249,6 +249,9 @@ test("maps DBX formatter settings to sql-formatter options", () => {
linesBetweenQueries: 1,
denseOperators: false,
newlineBeforeSemicolon: true,
paramTypes: {
custom: [{ regex: String.raw`\$\{[^}]+\}` }, { regex: String.raw`#\{[^}]+\}` }],
},
},
);
@ -270,7 +273,10 @@ test("maps DBX formatter settings to sql-formatter options", () => {
linesBetweenQueries: 1,
denseOperators: false,
newlineBeforeSemicolon: false,
paramTypes: { positional: true },
paramTypes: {
positional: true,
custom: [{ regex: String.raw`\$\{[^}]+\}` }, { regex: String.raw`#\{[^}]+\}` }],
},
},
);
});