fix(editor): unquote DDL view when identifier quoting disabled
This commit is contained in:
7 files changed
+87
-5
No files matched your search
@@ -0,0 +1,23 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { omitDdlIdentifierQuotes } from "@/lib/sql/ddlDisplay";
|
||||
|
||||
describe("omitDdlIdentifierQuotes", () => {
|
||||
it("removes safe MySQL identifier quotes without changing literals or comments", () => {
|
||||
const ddl = "CREATE TABLE `demo_table` (`id` int DEFAULT 'a`b') COMMENT='`keep`'; -- `keep`";
|
||||
expect(omitDdlIdentifierQuotes(ddl, "mysql")).toBe("CREATE TABLE demo_table (id int DEFAULT 'a`b') COMMENT='`keep`'; -- `keep`");
|
||||
});
|
||||
|
||||
it("keeps quotes for names that require them", () => {
|
||||
expect(omitDdlIdentifierQuotes("CREATE TABLE `order` (`with space` int)", "mysql")).toBe("CREATE TABLE `order` (`with space` int)");
|
||||
});
|
||||
|
||||
it("supports PostgreSQL and SQL Server identifier delimiters", () => {
|
||||
expect(omitDdlIdentifierQuotes('CREATE TABLE "demo_table" ("id" integer)', "postgres")).toBe("CREATE TABLE demo_table (id integer)");
|
||||
expect(omitDdlIdentifierQuotes("CREATE TABLE [demo_table] ([id] int)", "sqlserver")).toBe("CREATE TABLE demo_table (id int)");
|
||||
});
|
||||
|
||||
it("keeps brackets on SQL Server reserved words while unquoting safe names", () => {
|
||||
const ddl = "CREATE TABLE [demo_table] ([order] int, [key] int, [user] nvarchar(50), [id] int)";
|
||||
expect(omitDdlIdentifierQuotes(ddl, "sqlserver")).toBe("CREATE TABLE demo_table ([order] int, [key] int, [user] nvarchar(50), id int)");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
import { requiresMysqlIdentifierQuote, requiresPostgresIdentifierQuote } from "@/lib/sql/sqlIdentifier";
|
||||
import { tokenizeSqlSemantic, unquoteSqlSemanticIdentifier } from "@/lib/sql/semantic/tokens";
|
||||
import type { SqlFormatDialect } from "@/lib/sql/sqlFormatter";
|
||||
|
||||
const SIMPLE_SQLSERVER_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
||||
|
||||
function canRenderUnquoted(identifier: string, dialect: SqlFormatDialect): boolean {
|
||||
switch (dialect) {
|
||||
case "mysql":
|
||||
case "clickhouse":
|
||||
return !requiresMysqlIdentifierQuote(identifier);
|
||||
case "postgres":
|
||||
case "sqlite":
|
||||
case "oracle":
|
||||
case "duckdb":
|
||||
case "dameng":
|
||||
case "generic":
|
||||
return !requiresPostgresIdentifierQuote(identifier);
|
||||
case "sqlserver":
|
||||
return SIMPLE_SQLSERVER_IDENTIFIER.test(identifier) && !requiresMysqlIdentifierQuote(identifier.toLowerCase());
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes dialect identifier quotes from safe names while preserving strings, comments, and unsafe names. */
|
||||
export function omitDdlIdentifierQuotes(sql: string, dialect: SqlFormatDialect): string {
|
||||
const tokens = tokenizeSqlSemantic(sql, dialect === "sqlserver" ? "sqlserver" : dialect);
|
||||
const replacements: Array<{ start: number; end: number; value: string }> = [];
|
||||
|
||||
for (const token of tokens) {
|
||||
if (token.kind !== "quoted_identifier") continue;
|
||||
const identifier = unquoteSqlSemanticIdentifier(token);
|
||||
if (canRenderUnquoted(identifier, dialect)) replacements.push({ start: token.span.start, end: token.span.end, value: identifier });
|
||||
}
|
||||
|
||||
let result = sql;
|
||||
for (let index = replacements.length - 1; index >= 0; index -= 1) {
|
||||
const replacement = replacements[index]!;
|
||||
result = `${result.slice(0, replacement.start)}${replacement.value}${result.slice(replacement.end)}`;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Reference in new issue
Block a user