fix(dameng): complete table column data type options

Closes #5275
This commit is contained in:
t8y2 committed 2026-08-12 08:40:07 +00:00
1 parent 747e9900df
commit 056e46504e
3 files changed
+188 -9

No files matched your search

@@ -152,10 +152,24 @@ vi.mock("@/components/ui/searchable-select", async () => {
SearchableSelect: defineComponent({
name: "SearchableSelect",
inheritAttrs: false,
props: {
modelValue: { type: String, default: "" },
options: { type: Array, default: () => [] },
allowCustom: { type: Boolean, default: false },
},
emits: ["update:modelValue"],
setup:
(_props, { attrs }) =>
(props, { attrs, emit }) =>
() =>
h("div", attrs),
h("button", {
...attrs,
type: "button",
"data-searchable-select": "true",
"data-model-value": props.modelValue,
"data-options": JSON.stringify(props.options),
"data-allow-custom": String(props.allowCustom),
onClick: () => emit("update:modelValue", "custom_domain"),
}),
}),
};
});
@@ -240,19 +254,19 @@ function draft(isPrimaryKey = false) {
};
}
async function mountEditor(databaseType: "sqlserver" | "postgres" | "sqlite" | "oracle" | "dameng" | "duckdb" | "informix", isPrimaryKey = false) {
async function mountEditor(databaseType: "sqlserver" | "postgres" | "sqlite" | "oracle" | "dameng" | "duckdb" | "informix", isPrimaryKey = false, options: { database?: string; dynamicTypes?: string[] } = {}) {
mocks.connection.db_type = databaseType;
mocks.connection.name = databaseType;
mocks.connection.driver_label = databaseType;
mocks.ensureConnected.mockResolvedValue(undefined);
mocks.listDataTypes.mockResolvedValue([]);
mocks.listDataTypes.mockResolvedValue(options.dynamicTypes ?? []);
mocks.buildTableStructureChangeSql.mockResolvedValue({ statements: [], warnings: [] });
const root = document.createElement("div");
document.body.append(root);
const app = createApp(TableStructureEditor, {
connectionId: mocks.connection.id,
database: "test",
database: options.database ?? "test",
schema: "SYSDBA",
tableName: "users",
draft: draft(isPrimaryKey),
@@ -394,6 +408,33 @@ describe("TableStructureEditor primary key editing", () => {
});
});
describe("TableStructureEditor data type options", () => {
it("keeps dynamic Dameng types first and deduplicates fallback types case-insensitively", async () => {
const root = await mountEditor("dameng", false, {
database: "dynamic-types-5275",
dynamicTypes: ["VARCHAR", "CUSTOM_DM_TYPE", "NUMBER"],
});
const picker = root.querySelector<HTMLElement>('[data-searchable-select="true"]');
if (!picker) throw new Error("Missing data type picker");
await vi.waitFor(() => expect(JSON.parse(picker.dataset.options ?? "[]").slice(0, 3)).toEqual(["VARCHAR", "CUSTOM_DM_TYPE", "NUMBER"]));
const options = JSON.parse(picker.dataset.options ?? "[]") as string[];
expect(options.filter((option) => option.toLowerCase() === "varchar")).toEqual(["VARCHAR"]);
expect(options.filter((option) => option.toLowerCase() === "number")).toEqual(["NUMBER"]);
expect(options).toContain("longvarchar");
});
it("continues to accept manually entered Dameng data types", async () => {
const root = await mountEditor("dameng", false, { database: "manual-type-5275" });
const picker = root.querySelector<HTMLButtonElement>('[data-searchable-select="true"]');
if (!picker) throw new Error("Missing data type picker");
expect(picker.dataset.allowCustom).toBe("true");
picker.click();
await vi.waitFor(() => expect(mocks.buildTableStructureChangeSql).toHaveBeenLastCalledWith(expect.objectContaining({ columns: [expect.objectContaining({ dataType: "custom_domain" })] })));
});
});
describe("TableStructureEditor local column order notice", () => {
it.each(["sqlserver", "postgres", "sqlite", "oracle", "dameng", "duckdb", "informix"] as const)("does not show the reorder notice when adding a %s column", async (databaseType) => {
const root = await mountEditor(databaseType);
@@ -199,6 +199,63 @@ export const DATA_TYPE_OPTIONS: Record<string, string[]> = {
"xmltype",
"sdo_geometry",
],
dameng: [
"number",
"numeric",
"decimal",
"dec",
"integer",
"int",
"bigint",
"smallint",
"tinyint",
"byte",
"float",
"double",
"real",
"double precision",
"bit",
"binary",
"varbinary",
"raw",
"char",
"character",
"varchar2",
"varchar",
"rowid",
"bool",
"boolean",
"date",
"time",
"timestamp",
"datetime",
"time with time zone",
"timestamp with time zone",
"timestamp with local time zone",
"interval year",
"interval month",
"interval year to month",
"interval day",
"interval hour",
"interval minute",
"interval second",
"interval day to hour",
"interval day to minute",
"interval day to second",
"interval hour to minute",
"interval hour to second",
"interval minute to second",
"text",
"long",
"longvarchar",
"image",
"longvarbinary",
"blob",
"clob",
"bfile",
"json",
"jsonb",
],
clickhouse: [
"Int8",
"Int16",
@@ -301,7 +358,6 @@ const DATA_TYPE_OPTION_ALIASES: Partial<Record<DatabaseType, string>> = {
vastbase: "postgres",
kingbase: "postgres",
firebird: "postgres",
dameng: "oracle",
"oceanbase-oracle": "oracle",
iris: "oracle",
yashandb: "oracle",
@@ -1138,7 +1194,11 @@ export function defaultNewColumnDataType(dbType: DatabaseType | undefined, dataT
}
if (options.length > 0) {
const preferred = options.find((type) => /^(varchar|character varying|nvarchar)$/i.test(type.trim())) ?? options.find((type) => /^(string|clob|lvarchar|text)$/i.test(type.trim())) ?? options.find((type) => /^varchar/i.test(type.trim()));
const preferred =
(dbType === "dameng" ? options.find((type) => /^varchar2$/i.test(type.trim())) : undefined) ??
options.find((type) => /^(varchar|character varying|nvarchar)$/i.test(type.trim())) ??
options.find((type) => /^(string|clob|lvarchar|text)$/i.test(type.trim())) ??
options.find((type) => /^varchar/i.test(type.trim()));
if (preferred) {
return combineDataTypeForDatabase(dbType, preferred, getDefaultLengthForType(dbType, preferred));
}