fix(import): preserve explicit DBeaver database names
This commit is contained in:
1 parent
2bb85dcdc9
commit
68acf9f132
2 files changed
+270
-4
No files matched your search
+257
-2
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { SidebarLayout, SidebarOrderEntry } from "@/types/database";
|
||||
import { parseDbeaverConnections, parseDbeaverImport } from "@/lib/imports/dbeaverImport";
|
||||
import type { SidebarLayout, SidebarOrderEntry } from "../../../types/database";
|
||||
import { parseDbeaverConnections, parseDbeaverImport } from "../../imports/dbeaverImport";
|
||||
|
||||
function payload(dataSources: Record<string, unknown>) {
|
||||
return JSON.stringify({ format: "dbeaver-import", dataSources: JSON.stringify(dataSources) });
|
||||
@@ -17,6 +17,16 @@ function mysqlConnection(id: string, name: string, folder?: string) {
|
||||
};
|
||||
}
|
||||
|
||||
function clickhouseConnection(id: string, name: string, configuration: Record<string, unknown>) {
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
provider: "clickhouse",
|
||||
driver: "com_clickhouse",
|
||||
configuration,
|
||||
};
|
||||
}
|
||||
|
||||
function layoutLabels(layout: SidebarLayout, connectionNames: Map<string, string>): unknown[] {
|
||||
const groupNames = new Map(layout.groups.map((group) => [group.id, group.name]));
|
||||
const visit = (entries: SidebarOrderEntry[]): unknown[] => entries.map((entry) => (entry.type === "connection" ? connectionNames.get(entry.id) : { group: groupNames.get(entry.id), children: visit(entry.children ?? []) }));
|
||||
@@ -50,6 +60,251 @@ describe("DBeaver folder import", () => {
|
||||
expect(connection?.database).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps the default database empty for MySQL root JDBC URLs", async () => {
|
||||
const [connection] = await parseDbeaverConnections(
|
||||
payload({
|
||||
connections: {
|
||||
mysql: {
|
||||
id: "mysql",
|
||||
name: "208",
|
||||
provider: "mysql",
|
||||
driver: "mysql8",
|
||||
configuration: {
|
||||
host: "192.168.3.12",
|
||||
port: "51345",
|
||||
url: "jdbc:mysql://192.168.3.12:51345/",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(connection).toMatchObject({
|
||||
name: "208",
|
||||
db_type: "mysql",
|
||||
host: "192.168.3.12",
|
||||
port: 51345,
|
||||
});
|
||||
expect(connection?.database).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps the default database empty for ClickHouse root JDBC URLs", async () => {
|
||||
const [connection] = await parseDbeaverConnections(
|
||||
payload({
|
||||
connections: {
|
||||
clickhouse: clickhouseConnection("clickhouse", "CH", {
|
||||
host: "192.168.1.39",
|
||||
port: "8123",
|
||||
url: "jdbc:clickhouse://192.168.1.39:8123",
|
||||
}),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(connection).toMatchObject({
|
||||
name: "CH",
|
||||
db_type: "clickhouse",
|
||||
host: "192.168.1.39",
|
||||
port: 8123,
|
||||
});
|
||||
expect(connection?.database).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps the default database empty for SQL Server connections without databaseName", async () => {
|
||||
const [connection] = await parseDbeaverConnections(
|
||||
payload({
|
||||
connections: {
|
||||
sqlserver: {
|
||||
id: "sqlserver",
|
||||
name: "MSSQL",
|
||||
provider: "sqlserver",
|
||||
driver: "mssql_jdbc",
|
||||
configuration: {
|
||||
host: "192.168.10.25",
|
||||
port: "1433",
|
||||
url: "jdbc:sqlserver://192.168.10.25:1433;encrypt=true",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(connection).toMatchObject({
|
||||
name: "MSSQL",
|
||||
db_type: "sqlserver",
|
||||
host: "192.168.10.25",
|
||||
port: 1433,
|
||||
});
|
||||
expect(connection?.database).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps the default database empty for Oracle connections without a configured service", async () => {
|
||||
const [connection] = await parseDbeaverConnections(
|
||||
payload({
|
||||
connections: {
|
||||
oracle: {
|
||||
id: "oracle",
|
||||
name: "Oracle",
|
||||
provider: "oracle",
|
||||
driver: "oracle_jdbc",
|
||||
configuration: {
|
||||
host: "192.168.10.30",
|
||||
port: "1521",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(connection).toMatchObject({
|
||||
name: "Oracle",
|
||||
db_type: "oracle",
|
||||
host: "192.168.10.30",
|
||||
port: 1521,
|
||||
});
|
||||
expect(connection?.database).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps the default database empty for PostgreSQL root JDBC URLs", async () => {
|
||||
const [connection] = await parseDbeaverConnections(
|
||||
payload({
|
||||
connections: {
|
||||
postgres: {
|
||||
id: "postgres",
|
||||
name: "PG",
|
||||
provider: "postgresql",
|
||||
driver: "postgres-jdbc",
|
||||
configuration: {
|
||||
host: "192.168.10.40",
|
||||
port: "5432",
|
||||
url: "jdbc:postgresql://192.168.10.40:5432/",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(connection).toMatchObject({
|
||||
name: "PG",
|
||||
db_type: "postgres",
|
||||
host: "192.168.10.40",
|
||||
port: 5432,
|
||||
});
|
||||
expect(connection?.database).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps the default database empty for MariaDB root JDBC URLs", async () => {
|
||||
const [connection] = await parseDbeaverConnections(
|
||||
payload({
|
||||
connections: {
|
||||
mariadb: {
|
||||
id: "mariadb",
|
||||
name: "MariaDB",
|
||||
provider: "mysql",
|
||||
driver: "mariadb",
|
||||
configuration: {
|
||||
host: "192.168.10.50",
|
||||
port: "3306",
|
||||
url: "jdbc:mariadb://192.168.10.50:3306/",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(connection).toMatchObject({
|
||||
name: "MariaDB",
|
||||
db_type: "mysql",
|
||||
driver_profile: "mariadb",
|
||||
host: "192.168.10.50",
|
||||
port: 3306,
|
||||
});
|
||||
expect(connection?.database).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps the default database empty for DB2 connections (fallback to JDBC) without database configured", async () => {
|
||||
const [connection] = await parseDbeaverConnections(
|
||||
payload({
|
||||
connections: {
|
||||
db2: {
|
||||
id: "db2",
|
||||
name: "DB2",
|
||||
provider: "db2",
|
||||
driver: "db2",
|
||||
configuration: {
|
||||
host: "192.168.10.60",
|
||||
port: "50000",
|
||||
url: "jdbc:db2://192.168.10.60:50000/",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(connection).toMatchObject({
|
||||
name: "DB2",
|
||||
db_type: "jdbc",
|
||||
host: "192.168.10.60",
|
||||
port: 50000,
|
||||
});
|
||||
expect(connection?.database).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not treat an opaque JDBC host and port as the database", async () => {
|
||||
const [connection] = await parseDbeaverConnections(
|
||||
payload({
|
||||
connections: {
|
||||
opaque: {
|
||||
id: "opaque",
|
||||
name: "Opaque JDBC",
|
||||
provider: "generic",
|
||||
driver: "com.example.Driver",
|
||||
configuration: {
|
||||
url: "jdbc:example:db.example.com:1234",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(connection).toMatchObject({
|
||||
name: "Opaque JDBC",
|
||||
db_type: "jdbc",
|
||||
connection_string: "jdbc:example:db.example.com:1234",
|
||||
});
|
||||
expect(connection?.database).toBeUndefined();
|
||||
});
|
||||
|
||||
it("preserves explicit database names that resemble the host or port", async () => {
|
||||
const connections = await parseDbeaverConnections(
|
||||
payload({
|
||||
connections: {
|
||||
mysql: {
|
||||
id: "mysql",
|
||||
name: "208",
|
||||
provider: "mysql",
|
||||
driver: "mysql8",
|
||||
configuration: {
|
||||
host: "192.168.3.12",
|
||||
port: "51345",
|
||||
database: "192.168.3.12:51345",
|
||||
url: "jdbc:mysql://192.168.3.12:51345/",
|
||||
},
|
||||
},
|
||||
clickhouse: clickhouseConnection("clickhouse", "CH", {
|
||||
host: "192.168.1.39",
|
||||
port: "8123",
|
||||
database: "8123",
|
||||
url: "jdbc:clickhouse://192.168.1.39:8123",
|
||||
}),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(connections[0]?.database).toBe("192.168.3.12:51345");
|
||||
expect(connections[1]?.database).toBe("8123");
|
||||
});
|
||||
|
||||
it("keeps parseDbeaverConnections compatible when no folders exist", async () => {
|
||||
const connections = await parseDbeaverConnections(payload({ connections: { root: mysqlConnection("root", "Root") } }));
|
||||
|
||||
|
||||
@@ -81,6 +81,15 @@ function getNumber(value: unknown) {
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
||||
}
|
||||
|
||||
function firstNonEmptyString(...values: unknown[]) {
|
||||
for (const value of values) {
|
||||
if (typeof value !== "string") continue;
|
||||
const normalized = value.trim();
|
||||
if (normalized) return normalized;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function inferProfile(entry: DbeaverConnectionEntry): ConnectionProfile {
|
||||
if (/^jdbcx:/i.test(getString(entry.configuration?.url))) return profileMap.jdbcx;
|
||||
if (normalizeKey(entry.provider) === "opentenbase") return profileMap.opentenbase;
|
||||
@@ -179,6 +188,7 @@ function parseJdbcUrl(url: string, profile: ConnectionProfile) {
|
||||
|
||||
try {
|
||||
const parsed = new URL(withoutJdbc);
|
||||
if (!parsed.hostname) return result;
|
||||
result.host = parsed.hostname;
|
||||
result.port = parsed.port ? Number(parsed.port) : profile.port;
|
||||
result.database = parsed.pathname.replace(/^\/+/, "").split("/")[0] || undefined;
|
||||
@@ -223,7 +233,8 @@ function buildConnection(entry: DbeaverConnectionEntry, credentials: ReturnType<
|
||||
const config = entry.configuration || {};
|
||||
const url = getString(config.url);
|
||||
const parsedUrl = parseJdbcUrl(url, profile);
|
||||
const configuredDatabase = getString(config.database || config["database-name"] || config.schema || parsedUrl.database);
|
||||
const configuredPort = getNumber(config.port || config["host-port"] || parsedUrl.port) || profile.port;
|
||||
const configuredDatabase = firstNonEmptyString(config.database, config["database-name"], config.schema, parsedUrl.database);
|
||||
const host = getString(config.host || config["host-name"] || parsedUrl.host || (profile.dbType === "sqlite" ? configuredDatabase : "127.0.0.1"));
|
||||
const database = profile.dbType === "sqlite" ? "" : configuredDatabase;
|
||||
const name = getString(entry.name || database || host || profile.label);
|
||||
@@ -236,7 +247,7 @@ function buildConnection(entry: DbeaverConnectionEntry, credentials: ReturnType<
|
||||
driver_label: profile.label,
|
||||
url_params: getString(parsedUrl.params),
|
||||
host,
|
||||
port: getNumber(config.port || config["host-port"] || parsedUrl.port) || profile.port,
|
||||
port: configuredPort,
|
||||
username: credentials.username || getString(parsedUrl.username) || profile.user,
|
||||
password: credentials.password || getString(parsedUrl.password),
|
||||
database: database || undefined,
|
||||
|
||||
Reference in new issue
Block a user