feat(structure): keep newly created tables open for editing

This commit is contained in:
二丫讲梵 authored and GitHub committed 2026-09-24 12:20:33 +08:00
1 parent 1aa8b21a87
commit 1b2e4e1a6f
18 files changed
+476 -10

No files matched your search

@@ -31,6 +31,7 @@ import {
structureColumnCommentsForCopy,
structureColumnNamesForCopy,
tableStructureIdentifierComparisonKey,
foldCreatedTableName,
} from "@/lib/table/tableStructureEditorState";
describe("tableStructureEditorState", () => {
@@ -215,6 +216,40 @@ describe("tableStructureEditorState", () => {
expect(jdbcNames.has(tableStructureIdentifierComparisonKey("foo", "jdbc", { unquotedIdentifierCase: "lower", quotedIdentifierCase: "mixed" }))).toBe(false);
});
describe("foldCreatedTableName", () => {
it("folds plain Oracle names to upper case and trims surrounding whitespace", () => {
expect(foldCreatedTableName("MyTable", "oracle")).toBe("MYTABLE");
expect(foldCreatedTableName(" MyTable ", "oracle")).toBe("MYTABLE");
expect(foldCreatedTableName("order_items$", "oracle")).toBe("ORDER_ITEMS$");
expect(foldCreatedTableName("t#1", "oracle")).toBe("T#1");
});
it("keeps Oracle names that the DDL generator must quote unchanged", () => {
// A leading digit, spaces or special characters force quoting, and a
// quoted identifier keeps its exact spelling on the server.
expect(foldCreatedTableName("1MyTable", "oracle")).toBe("1MyTable");
expect(foldCreatedTableName("my table", "oracle")).toBe("my table");
expect(foldCreatedTableName("МойТable", "oracle")).toBe("МойТable");
expect(foldCreatedTableName("", "oracle")).toBe("");
});
it("folds plain Informix-family names to lower case and keeps quoted ones unchanged", () => {
expect(foldCreatedTableName("MyTable", "informix")).toBe("mytable");
expect(foldCreatedTableName(" MyTable ", "informix")).toBe("mytable");
expect(foldCreatedTableName("_t1$", "informix")).toBe("_t1$");
expect(foldCreatedTableName("1MyTable", "informix")).toBe("1MyTable");
expect(foldCreatedTableName("my table", "informix")).toBe("my table");
});
it("preserves names exactly on dialects that quote new identifiers", () => {
for (const databaseType of ["postgres", "mysql", "sqlserver", "dameng", "oceanbase-oracle", undefined] as const) {
expect(foldCreatedTableName("MyTable", databaseType)).toBe("MyTable");
expect(foldCreatedTableName(" MyTable ", databaseType)).toBe("MyTable");
expect(foldCreatedTableName("1MyTable", databaseType)).toBe("1MyTable");
}
});
});
it("keeps existing Oracle trigger drafts read-only until full source editing is available", () => {
const [existing] = createTriggerDrafts([{ name: "ORDERS_AUDIT", timing: "AFTER EACH ROW", event: "INSERT OR UPDATE", statement: "BEGIN NULL; END;" }]);
if (!existing) throw new Error("expected an existing trigger draft");
@@ -105,6 +105,44 @@ export function tableStructureIdentifierComparisonKey(name: string, databaseType
return `unquoted:${normalizedUnquoted}`;
}
/** Plain-identifier rule for newly created Oracle names: an ASCII letter first,
* then letters/digits/`_`/`$`/`#`. Anything else is emitted quoted by the DDL
* generator and keeps its exact spelling. */
function isPlainOracleCreateIdentifier(name: string): boolean {
if (!/^[A-Za-z]/.test(name)) return false;
return /^[A-Za-z0-9_$#]*$/.test(name.slice(1));
}
/** Plain-identifier rule for newly created Informix-family names: an ASCII
* letter or `_` first, then letters/digits/`_`/`$`. */
function isPlainInformixCreateIdentifier(name: string): boolean {
if (!/^[A-Za-z_]/.test(name)) return false;
return /^[A-Za-z0-9_$]*$/.test(name.slice(1));
}
/**
* Storage name of a newly created table, mirroring how the CREATE DDL
* generator quotes new identifiers. Plain (unquoted) Oracle names fold to
* upper case on the server; plain Informix-family names fold to lower case.
* Every other dialect quotes new names — or does not fold them — so the
* as-typed spelling is preserved exactly. Names the DDL would have to quote
* (leading digit, special characters, spaces) keep their exact spelling on
* the folding dialects too. Boundary: a reserved-word name typed in mixed
* case is quoted by the generator and keeps its spelling, while this helper
* still folds it — accepted because the reserved-word vocabulary lives with
* the SQL builder, not the frontend.
*/
export function foldCreatedTableName(name: string, databaseType?: DatabaseType): string {
const value = name.trim();
if (databaseType === "oracle") {
return isPlainOracleCreateIdentifier(value) ? value.toUpperCase() : value;
}
if (databaseType === "informix") {
return isPlainInformixCreateIdentifier(value) ? value.toLowerCase() : value;
}
return value;
}
const POSTGRES_SERIAL_PSEUDO_TYPES = new Set(["smallserial", "serial", "bigserial"]);
function withPostgresArrayTypes(types: readonly string[]): string[] {