fix(gbase8s): support CREATE DATABASE and open mixed-locale databases

This commit is contained in:
弈秋 authored and GitHub committed 2026-09-16 11:54:56 +08:00
1 parent 4bf073d5d1
commit 72be4ad9eb
5 files changed
+329 -6

No files matched your search

@@ -0,0 +1,36 @@
import { describe, expect, it } from "vitest";
import { connectionNamespaceCreationTarget, databaseNodeNamespaceCreationTarget } from "@/lib/database/databaseNamespaceCreation";
type Conn = Parameters<typeof connectionNamespaceCreationTarget>[0];
const databaseNode = { type: "database" as const, database: "dcss" };
describe("database namespace creation targets", () => {
it("offers Create Database (not Create Schema) for GBase 8s", () => {
const gbase8s = { db_type: "gbase", driver_profile: "gbase8s" } as Conn;
expect(connectionNamespaceCreationTarget(gbase8s)).toBe("database");
expect(databaseNodeNamespaceCreationTarget(gbase8s, databaseNode)).toBeNull();
});
it("keeps the MySQL-style Create Schema target for GBase 8a", () => {
const gbase8a = { db_type: "gbase", driver_profile: "gbase8a" } as Conn;
expect(connectionNamespaceCreationTarget(gbase8a)).toBeNull();
expect(databaseNodeNamespaceCreationTarget(gbase8a, databaseNode)).toBe("schema");
});
it("offers Create Database for standalone Informix", () => {
const informix = { db_type: "informix" } as Conn;
expect(connectionNamespaceCreationTarget(informix)).toBe("database");
expect(databaseNodeNamespaceCreationTarget(informix, databaseNode)).toBeNull();
});
it("leaves unrelated engines on their existing targets", () => {
const postgres = { db_type: "postgres" } as Conn;
expect(connectionNamespaceCreationTarget(postgres)).toBe("database");
expect(databaseNodeNamespaceCreationTarget(postgres, databaseNode)).toBe("schema");
});
});
@@ -73,7 +73,7 @@ export const DATABASE_NAMESPACE_CREATION_MATRIX = {
impala: { deferred: "Impala database creation needs dedicated metadata validation first" },
spark: { deferred: "Spark database creation needs agent metadata validation first" },
db2: { database: "schema" },
informix: { database: "schema" },
informix: { connection: "database" },
neo4j: { deferred: "database creation depends on edition/admin privileges" },
cassandra: { deferred: "keyspace creation requires replication options" },
bigquery: { deferred: "dataset creation needs project/location options" },
@@ -100,19 +100,30 @@ export const DATABASE_NAMESPACE_CREATION_MATRIX = {
mqtt: { deferred: "MQTT topics are managed via the MQTT console" },
} satisfies Record<DatabaseType, DatabaseNamespaceCreationMatrixEntry>;
function namespaceCreationMatrixEntry(connection: NonNullable<CreationConnection>): DatabaseNamespaceCreationMatrixEntry {
// GBase 8s shares `db_type: "gbase"` with the MySQL-based GBase 8a but is Informix-derived:
// it has no `CREATE SCHEMA <name>` (a schema is the table owner) yet does support
// `CREATE DATABASE`. Route it to the Informix-family semantics instead of the shared `gbase`
// entry, which is written for GBase 8a.
if (connection.db_type === "gbase" && connection.driver_profile === "gbase8s") {
return { connection: "database" };
}
return DATABASE_NAMESPACE_CREATION_MATRIX[connection.db_type];
}
export function connectionNamespaceCreationTarget(connection: CreationConnection): ConnectionCreationTarget | null {
if (!connection || connectionIsEffectivelyReadOnly(connection)) return null;
if (connection.db_type === "mongodb" && isMongoLegacyDriverProfile(connection.driver_profile)) return null;
if (connection.db_type === "sqlite" && (connection.host?.trim().toLowerCase() === ":memory:" || Boolean(connection.password))) {
return null;
}
const entry: DatabaseNamespaceCreationMatrixEntry = DATABASE_NAMESPACE_CREATION_MATRIX[connection.db_type];
const entry: DatabaseNamespaceCreationMatrixEntry = namespaceCreationMatrixEntry(connection);
return entry.connection ?? null;
}
export function databaseNodeNamespaceCreationTarget(connection: CreationConnection, node: Pick<{ type: TreeNodeType; database?: string | null }, "type" | "database">): DatabaseNodeCreationTarget | null {
if (!connection || connectionIsEffectivelyReadOnly(connection) || node.type !== "database" || !node.database) return null;
const entry: DatabaseNamespaceCreationMatrixEntry = DATABASE_NAMESPACE_CREATION_MATRIX[connection.db_type];
const entry: DatabaseNamespaceCreationMatrixEntry = namespaceCreationMatrixEntry(connection);
return entry.database ?? null;
}