feat(opentenbase): add PostgreSQL-compatible database support

This commit is contained in:
t8y2 committed 2026-08-14 23:40:50 +08:00
1 parent 722b6e7d19
commit 2d526db91b
16 files changed
+412 -19

No files matched your search

@@ -0,0 +1,37 @@
import { describe, expect, it } from "vitest";
import { connectionProfileForScheme, parseConnectionUrl } from "@/lib/connection/connectionUrl";
describe("OpenTenBase connection URLs", () => {
it("parses the OpenTenBase alias as a PostgreSQL-compatible profile", () => {
const parsed = parseConnectionUrl("opentenbase://opentenbase:secret@cn.example.com/postgres");
expect(parsed).toMatchObject({
dbType: "postgres",
driverProfile: "opentenbase",
driverLabel: "OpenTenBase",
host: "cn.example.com",
port: 11000,
username: "opentenbase",
password: "secret",
database: "postgres",
});
});
it("keeps the OpenTenBase profile for standard PostgreSQL URLs", () => {
const parsed = parseConnectionUrl("postgresql://cn.example.com:15432/postgres", "opentenbase");
expect(parsed.dbType).toBe("postgres");
expect(parsed.driverProfile).toBe("opentenbase");
expect(parsed.driverLabel).toBe("OpenTenBase");
expect(parsed.port).toBe(15432);
});
it("exposes OpenTenBase to connection deep links", () => {
expect(connectionProfileForScheme("opentenbase")).toEqual({
type: "postgres",
profile: "opentenbase",
label: "OpenTenBase",
defaultPort: 11000,
});
});
});
@@ -140,3 +140,36 @@ describe("DBeaver Cloudberry import", () => {
});
});
});
describe("DBeaver OpenTenBase import", () => {
it("preserves OpenTenBase while reusing the PostgreSQL backend", async () => {
const connections = await parseDbeaverConnections(
payload({
connections: {
opentenbase: {
id: "opentenbase",
name: "distributed-postgres",
provider: "opentenbase",
driver: "opentenbase-postgresql",
configuration: {
host: "cn.example.com",
port: 11000,
database: "postgres",
user: "opentenbase",
},
},
},
}),
);
expect(connections[0]).toMatchObject({
db_type: "postgres",
driver_profile: "opentenbase",
driver_label: "OpenTenBase",
host: "cn.example.com",
port: 11000,
database: "postgres",
username: "opentenbase",
});
});
});
@@ -34,6 +34,7 @@ const SCHEME_PROFILES: Record<string, ConnectionProfile> = {
postgres: { type: "postgres", profile: "postgres", label: "PostgreSQL", defaultPort: 5432 },
postgresql: { type: "postgres", profile: "postgres", label: "PostgreSQL", defaultPort: 5432 },
cloudberry: { type: "postgres", profile: "cloudberry", label: "Apache Cloudberry", defaultPort: 5432 },
opentenbase: { type: "postgres", profile: "opentenbase", label: "OpenTenBase", defaultPort: 11000 },
redshift: { type: "redshift", profile: "redshift", label: "Redshift", defaultPort: 5439 },
redis: { type: "redis", profile: "redis", label: "Redis", defaultPort: 6379 },
rediss: { type: "redis", profile: "redis", label: "Redis", defaultPort: 6379 },
@@ -325,9 +326,10 @@ export function connectionProfileForScheme(scheme: string, preferredProfile?: st
if ((normalizedScheme === "http" || normalizedScheme === "https") && normalizedPreferredProfile) {
return HTTP_SELECTED_PROFILES[normalizedPreferredProfile];
}
// Cloudberry uses PostgreSQL URLs, so keep the selected product profile when parsing a pasted URL.
if ((normalizedScheme === "postgres" || normalizedScheme === "postgresql") && normalizedPreferredProfile === "cloudberry") {
return SCHEME_PROFILES.cloudberry;
// PostgreSQL-compatible products use standard PostgreSQL URLs, so keep the
// selected product profile when parsing a pasted URL.
if ((normalizedScheme === "postgres" || normalizedScheme === "postgresql") && (normalizedPreferredProfile === "cloudberry" || normalizedPreferredProfile === "opentenbase")) {
return SCHEME_PROFILES[normalizedPreferredProfile];
}
return SCHEME_PROFILES[normalizedScheme];
}
@@ -42,6 +42,7 @@ const profileMap: Record<string, ConnectionProfile> = {
postgresql: { dbType: "postgres", profile: "postgres", label: "PostgreSQL", port: 5432, user: "postgres" },
postgres: { dbType: "postgres", profile: "postgres", label: "PostgreSQL", port: 5432, user: "postgres" },
cloudberry: { dbType: "postgres", profile: "cloudberry", label: "Apache Cloudberry", port: 5432, user: "postgres" },
opentenbase: { dbType: "postgres", profile: "opentenbase", label: "OpenTenBase", port: 11000, user: "opentenbase" },
sqlite: { dbType: "sqlite", profile: "sqlite", label: "SQLite", port: 0, user: "" },
sqlserver: { dbType: "sqlserver", profile: "sqlserver", label: "SQL Server", port: 1433, user: "sa" },
mssql: { dbType: "sqlserver", profile: "sqlserver", label: "SQL Server", port: 1433, user: "sa" },
@@ -82,6 +83,7 @@ function getNumber(value: unknown) {
function inferProfile(entry: DbeaverConnectionEntry): ConnectionProfile {
if (/^jdbcx:/i.test(getString(entry.configuration?.url))) return profileMap.jdbcx;
if (normalizeKey(entry.provider) === "opentenbase") return profileMap.opentenbase;
const driverProfile = profileMap[normalizeKey(entry.driver)];
if (driverProfile) return driverProfile;
const candidates = [entry.provider, entry.driver, entry.configuration?.url, entry.name].map(normalizeKey).join(" ");