mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-28 08:08:02 +00:00
feat(structure): add DDL capability matrix
This commit is contained in:
@@ -137,6 +137,11 @@ test("describes feature support through capability helpers", () => {
|
||||
assert.equal(supportsTableStructureEditing("duckdb"), true);
|
||||
assert.equal(supportsTableStructureEditing("oracle"), true);
|
||||
assert.equal(supportsTableStructureEditing("dameng"), true);
|
||||
assert.equal(supportsTableStructureEditing("gaussdb"), true);
|
||||
assert.equal(supportsTableStructureEditing("opengauss"), true);
|
||||
assert.equal(supportsTableStructureEditing("redshift"), true);
|
||||
assert.equal(supportsTableStructureEditing("clickhouse"), true);
|
||||
assert.equal(supportsTableStructureEditing("mongodb"), false);
|
||||
assert.equal(supportsDatabaseCreation("clickhouse"), true);
|
||||
assert.equal(supportsDatabaseCreation("sqlite"), false);
|
||||
assert.equal(supportsFieldLineage("gaussdb"), true);
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import {
|
||||
canEditTableStructure,
|
||||
getTableStructureCapabilities,
|
||||
} from "../../apps/desktop/src/lib/tableStructureCapabilities.ts";
|
||||
|
||||
test("postgres-like databases expose safe structure editing capabilities", () => {
|
||||
for (const dbType of ["postgres", "gaussdb", "opengauss", "highgo", "vastbase", "kingbase"] as const) {
|
||||
const caps = getTableStructureCapabilities(dbType);
|
||||
assert.equal(caps.dialect, "postgres", `${dbType} should reuse postgres DDL`);
|
||||
assert.equal(caps.createTable, true, `${dbType} should create tables`);
|
||||
assert.equal(caps.addColumn, true, `${dbType} should add columns`);
|
||||
assert.equal(caps.dropColumn, true, `${dbType} should drop columns`);
|
||||
assert.equal(caps.renameColumn, true, `${dbType} should rename columns`);
|
||||
assert.equal(caps.alterExistingColumn, true, `${dbType} should edit existing columns`);
|
||||
assert.equal(caps.comment, true, `${dbType} should support comments`);
|
||||
assert.equal(caps.createIndex, true, `${dbType} should create indexes`);
|
||||
assert.equal(caps.dropIndex, true, `${dbType} should drop indexes`);
|
||||
assert.equal(caps.indexFilter, true, `${dbType} should support filtered indexes`);
|
||||
assert.equal(canEditTableStructure(dbType), true);
|
||||
}
|
||||
});
|
||||
|
||||
test("redshift reuses postgres column DDL but keeps indexes disabled", () => {
|
||||
const caps = getTableStructureCapabilities("redshift");
|
||||
assert.equal(caps.dialect, "postgres");
|
||||
assert.equal(caps.createTable, true);
|
||||
assert.equal(caps.addColumn, true);
|
||||
assert.equal(caps.dropColumn, true);
|
||||
assert.equal(caps.renameColumn, true);
|
||||
assert.equal(caps.alterExistingColumn, true);
|
||||
assert.equal(caps.comment, true);
|
||||
assert.equal(caps.createIndex, false);
|
||||
assert.equal(caps.dropIndex, false);
|
||||
assert.equal(caps.indexFilter, false);
|
||||
assert.equal(canEditTableStructure("redshift"), true);
|
||||
});
|
||||
|
||||
test("oracle-like databases expose oracle-compatible structure editing capabilities", () => {
|
||||
for (const dbType of ["oracle", "dameng", "oceanbase-oracle"] as const) {
|
||||
const caps = getTableStructureCapabilities(dbType);
|
||||
assert.equal(caps.dialect, "oracle", `${dbType} should reuse oracle DDL`);
|
||||
assert.equal(caps.createTable, true);
|
||||
assert.equal(caps.addColumn, true);
|
||||
assert.equal(caps.dropColumn, true);
|
||||
assert.equal(caps.renameColumn, true);
|
||||
assert.equal(caps.alterExistingColumn, true);
|
||||
assert.equal(caps.comment, true);
|
||||
assert.equal(caps.createIndex, true);
|
||||
assert.equal(caps.dropIndex, true);
|
||||
assert.equal(canEditTableStructure(dbType), true);
|
||||
}
|
||||
});
|
||||
|
||||
test("limited analytic engines can open the editor for supported operations only", () => {
|
||||
const clickhouse = getTableStructureCapabilities("clickhouse");
|
||||
assert.equal(clickhouse.dialect, "clickhouse");
|
||||
assert.equal(clickhouse.createTable, true);
|
||||
assert.equal(clickhouse.addColumn, true);
|
||||
assert.equal(clickhouse.dropColumn, true);
|
||||
assert.equal(clickhouse.renameColumn, false);
|
||||
assert.equal(clickhouse.alterExistingColumn, false);
|
||||
assert.equal(clickhouse.comment, false);
|
||||
assert.equal(clickhouse.createIndex, false);
|
||||
assert.equal(canEditTableStructure("clickhouse"), true);
|
||||
});
|
||||
|
||||
test("unsupported non-relational databases do not open the structure editor", () => {
|
||||
for (const dbType of ["redis", "mongodb", "elasticsearch", "neo4j", undefined] as const) {
|
||||
const caps = getTableStructureCapabilities(dbType);
|
||||
assert.equal(caps.dialect, "unsupported");
|
||||
assert.equal(canEditTableStructure(dbType), false);
|
||||
}
|
||||
});
|
||||
@@ -17,3 +17,18 @@ test("structure editor keeps columns when optional metadata fails", () => {
|
||||
assert.match(source, /api\s*\n\s*\.listForeignKeys[\s\S]*\.catch\(\(\) => \[\]\)/);
|
||||
assert.match(source, /api\s*\n\s*\.listTriggers[\s\S]*\.catch\(\(\) => \[\]\)/);
|
||||
});
|
||||
|
||||
test("structure editor gates controls through table structure capabilities", () => {
|
||||
assert.match(source, /getTableStructureCapabilities/);
|
||||
assert.match(source, /const structureCapabilities = computed/);
|
||||
assert.match(source, /function isColumnNameDisabled/);
|
||||
assert.match(source, /function isColumnTypeDisabled/);
|
||||
assert.match(source, /function isColumnDefaultDisabled/);
|
||||
assert.match(source, /function isColumnCommentDisabled/);
|
||||
assert.match(source, /function canDropColumn/);
|
||||
assert.match(source, /function canEditIndexDraft/);
|
||||
assert.match(source, /structureCapabilities\.value\.createIndex/);
|
||||
assert.match(source, /structureCapabilities\.value\.dropIndex/);
|
||||
assert.match(source, /structureCapabilities\.value\.indexInclude/);
|
||||
assert.match(source, /structureCapabilities\.value\.indexFilter/);
|
||||
});
|
||||
|
||||
@@ -592,3 +592,151 @@ test("builds Dameng existing column and create table statements", () => {
|
||||
'CREATE INDEX "IDX_USERS_NAME" ON "SYSDBA"."USERS" ("NAME");',
|
||||
]);
|
||||
});
|
||||
|
||||
test("builds GaussDB statements with PostgreSQL-compatible DDL", () => {
|
||||
const result = buildTableStructureChangeSql({
|
||||
databaseType: "gaussdb",
|
||||
schema: "public",
|
||||
tableName: "accounts",
|
||||
columns: [
|
||||
column({
|
||||
id: "status",
|
||||
name: "account_status",
|
||||
dataType: "text",
|
||||
isNullable: false,
|
||||
defaultValue: "'active'",
|
||||
comment: "Current status",
|
||||
original: {
|
||||
name: "status",
|
||||
data_type: "varchar",
|
||||
is_nullable: true,
|
||||
column_default: null,
|
||||
is_primary_key: false,
|
||||
extra: null,
|
||||
comment: "",
|
||||
},
|
||||
}),
|
||||
],
|
||||
indexes: [index({ id: "idx", name: "idx_accounts_status", columns: ["account_status"] })],
|
||||
});
|
||||
|
||||
assert.deepEqual(result.warnings, []);
|
||||
assert.deepEqual(result.statements, [
|
||||
'ALTER TABLE "public"."accounts" RENAME COLUMN "status" TO "account_status";',
|
||||
'ALTER TABLE "public"."accounts" ALTER COLUMN "account_status" TYPE text;',
|
||||
'ALTER TABLE "public"."accounts" ALTER COLUMN "account_status" SET NOT NULL;',
|
||||
'ALTER TABLE "public"."accounts" ALTER COLUMN "account_status" SET DEFAULT \'active\';',
|
||||
'COMMENT ON COLUMN "public"."accounts"."account_status" IS \'Current status\';',
|
||||
'CREATE INDEX "idx_accounts_status" ON "public"."accounts" ("account_status");',
|
||||
]);
|
||||
});
|
||||
|
||||
test("builds openGauss statements with PostgreSQL-compatible DDL", () => {
|
||||
const result = buildTableStructureChangeSql({
|
||||
databaseType: "opengauss",
|
||||
schema: "public",
|
||||
tableName: "accounts",
|
||||
columns: [column({ id: "email", name: "email", dataType: "text", isNullable: true })],
|
||||
indexes: [],
|
||||
});
|
||||
|
||||
assert.deepEqual(result.warnings, []);
|
||||
assert.deepEqual(result.statements, ['ALTER TABLE "public"."accounts" ADD COLUMN "email" text;']);
|
||||
});
|
||||
|
||||
test("Redshift skips unsupported index operations while keeping column DDL", () => {
|
||||
const result = buildTableStructureChangeSql({
|
||||
databaseType: "redshift",
|
||||
schema: "public",
|
||||
tableName: "events",
|
||||
columns: [column({ id: "email", name: "email", dataType: "varchar(255)", isNullable: true })],
|
||||
indexes: [index({ id: "idx", name: "idx_events_email", columns: ["email"], filter: "email IS NOT NULL" })],
|
||||
});
|
||||
|
||||
assert.deepEqual(result.statements, ['ALTER TABLE "public"."events" ADD COLUMN "email" varchar(255);']);
|
||||
assert.deepEqual(result.warnings, ['Creating indexes is not supported for redshift from this editor.']);
|
||||
});
|
||||
|
||||
test("builds ClickHouse limited column DDL and skips indexes", () => {
|
||||
const result = buildTableStructureChangeSql({
|
||||
databaseType: "clickhouse",
|
||||
tableName: "events",
|
||||
columns: [
|
||||
column({ id: "new", name: "name", dataType: "String", isNullable: true }),
|
||||
column({
|
||||
id: "legacy",
|
||||
name: "legacy",
|
||||
markedForDrop: true,
|
||||
original: {
|
||||
name: "legacy",
|
||||
data_type: "String",
|
||||
is_nullable: true,
|
||||
column_default: null,
|
||||
is_primary_key: false,
|
||||
extra: null,
|
||||
},
|
||||
}),
|
||||
column({
|
||||
id: "kind",
|
||||
name: "event_kind",
|
||||
dataType: "String",
|
||||
original: {
|
||||
name: "kind",
|
||||
data_type: "String",
|
||||
is_nullable: true,
|
||||
column_default: null,
|
||||
is_primary_key: false,
|
||||
extra: null,
|
||||
},
|
||||
}),
|
||||
],
|
||||
indexes: [index({ id: "idx", name: "idx_events_name", columns: ["name"] })],
|
||||
});
|
||||
|
||||
assert.deepEqual(result.statements, [
|
||||
'ALTER TABLE "events" ADD COLUMN "name" String;',
|
||||
'ALTER TABLE "events" DROP COLUMN "legacy";',
|
||||
]);
|
||||
assert.deepEqual(result.warnings, [
|
||||
'Renaming columns is not supported for clickhouse from this editor.',
|
||||
'Creating indexes is not supported for clickhouse from this editor.',
|
||||
]);
|
||||
});
|
||||
|
||||
test("builds H2 schema-qualified existing column statements", () => {
|
||||
const result = buildTableStructureChangeSql({
|
||||
databaseType: "h2",
|
||||
schema: "PUBLIC",
|
||||
tableName: "USERS",
|
||||
columns: [
|
||||
column({
|
||||
id: "name",
|
||||
name: "DISPLAY_NAME",
|
||||
dataType: "VARCHAR(120)",
|
||||
isNullable: false,
|
||||
defaultValue: "'guest'",
|
||||
comment: "Display name",
|
||||
original: {
|
||||
name: "NAME",
|
||||
data_type: "VARCHAR(80)",
|
||||
is_nullable: true,
|
||||
column_default: null,
|
||||
is_primary_key: false,
|
||||
extra: null,
|
||||
comment: "",
|
||||
},
|
||||
}),
|
||||
],
|
||||
indexes: [index({ id: "idx", name: "IDX_USERS_DISPLAY_NAME", columns: ["DISPLAY_NAME"] })],
|
||||
});
|
||||
|
||||
assert.deepEqual(result.warnings, []);
|
||||
assert.deepEqual(result.statements, [
|
||||
'ALTER TABLE "PUBLIC"."USERS" ALTER COLUMN "NAME" RENAME TO "DISPLAY_NAME";',
|
||||
'ALTER TABLE "PUBLIC"."USERS" ALTER COLUMN "DISPLAY_NAME" SET DATA TYPE VARCHAR(120);',
|
||||
'ALTER TABLE "PUBLIC"."USERS" ALTER COLUMN "DISPLAY_NAME" SET NOT NULL;',
|
||||
'ALTER TABLE "PUBLIC"."USERS" ALTER COLUMN "DISPLAY_NAME" SET DEFAULT \'guest\';',
|
||||
'COMMENT ON COLUMN "PUBLIC"."USERS"."DISPLAY_NAME" IS \'Display name\';',
|
||||
'CREATE INDEX "IDX_USERS_DISPLAY_NAME" ON "PUBLIC"."USERS" ("DISPLAY_NAME");',
|
||||
]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user