feat(gaussdb): add target server type selection
This commit is contained in:
1 parent
5695ef6e77
commit
722b6e7d19
13 files changed
+197
-2
No files matched your search
@@ -118,7 +118,19 @@ import {
|
||||
elasticsearchKibanaBasePathFromConfig,
|
||||
type ElasticsearchConnectionMode,
|
||||
} from "@/lib/connection/elasticsearchKibanaProxy";
|
||||
import { GAUSSDB_M_JDBC_DRIVER_CLASS, gaussdbConnectionMode, gaussdbIdentifierQuoteStyle, setGaussdbConnectionMode, setGaussdbIdentifierQuoteStyle, supportsGaussdbIdentifierQuoteStyle, type GaussdbConnectionMode, type GaussdbIdentifierQuoteStyle } from "@/lib/database/jdbcDialect";
|
||||
import {
|
||||
GAUSSDB_M_JDBC_DRIVER_CLASS,
|
||||
gaussdbConnectionMode,
|
||||
gaussdbIdentifierQuoteStyle,
|
||||
gaussdbTargetServerType,
|
||||
setGaussdbConnectionMode,
|
||||
setGaussdbIdentifierQuoteStyle,
|
||||
setGaussdbTargetServerType,
|
||||
supportsGaussdbIdentifierQuoteStyle,
|
||||
type GaussdbConnectionMode,
|
||||
type GaussdbIdentifierQuoteStyle,
|
||||
type GaussdbTargetServerType,
|
||||
} from "@/lib/database/jdbcDialect";
|
||||
import { normalizeStoredConnectionDatabase } from "@/lib/database/sqliteNamespace";
|
||||
import {
|
||||
createJdbcProductConnectionFieldsByMode,
|
||||
@@ -532,6 +544,14 @@ const gaussdbQuoteStyle = computed<GaussdbIdentifierQuoteStyle>({
|
||||
},
|
||||
});
|
||||
|
||||
const gaussdbTargetServerTypeComputed = computed<GaussdbTargetServerType>({
|
||||
get: () => gaussdbTargetServerType(form.value),
|
||||
set: (value) => {
|
||||
setGaussdbTargetServerType(form.value, value);
|
||||
resetTestState();
|
||||
},
|
||||
});
|
||||
|
||||
const gaussdbHostEntries = ref<GaussdbHostEntry[]>(parseGaussdbHosts(form.value.host, form.value.port));
|
||||
|
||||
watch(
|
||||
@@ -3866,8 +3886,10 @@ function connectionConfigForSubmit(id: string, generatedName = ""): ConnectionCo
|
||||
config.external_config = sqlServerPortExplicitFromConfig(config) ? { portExplicit: true } : undefined;
|
||||
} else if (supportsGaussdbIdentifierQuoteStyle(config)) {
|
||||
const style = gaussdbIdentifierQuoteStyle(config);
|
||||
const targetServerType = gaussdbTargetServerType(config);
|
||||
config.external_config = undefined;
|
||||
setGaussdbIdentifierQuoteStyle(config, style);
|
||||
setGaussdbTargetServerType(config, targetServerType);
|
||||
} else if (!isDoltDriverProfile(config.driver_profile)) {
|
||||
config.external_config = undefined;
|
||||
}
|
||||
@@ -7789,6 +7811,24 @@ function openExternalUrl(url: string) {
|
||||
<p class="text-xs leading-5 text-muted-foreground">{{ t("connection.gaussdbIdentifierQuoteHint") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isGaussdbMJdbcConnection" class="grid grid-cols-4 items-start gap-4">
|
||||
<Label :class="connectionLabelSmallPaddedClass">{{ t("connection.gaussdbTargetServerType") }}</Label>
|
||||
<div class="col-span-3 grid gap-1">
|
||||
<Select v-model="gaussdbTargetServerTypeComputed">
|
||||
<SelectTrigger class="h-9">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="master">{{ t("connection.gaussdbTargetServerTypeMaster") }}</SelectItem>
|
||||
<SelectItem value="slave">{{ t("connection.gaussdbTargetServerTypeSlave") }}</SelectItem>
|
||||
<SelectItem value="any">{{ t("connection.gaussdbTargetServerTypeAny") }}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p class="text-xs leading-5 text-muted-foreground">
|
||||
{{ t("connection.gaussdbTargetServerTypeHint") }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label :class="connectionLabelSmallClass">{{ t("connection.connectTimeout") }}</Label>
|
||||
<div class="col-span-3 grid grid-cols-2 gap-2">
|
||||
|
||||
@@ -907,6 +907,11 @@ export default {
|
||||
gaussdbIdentifierQuoteDouble: 'Oracle/PostgreSQL (double quotes ")',
|
||||
gaussdbIdentifierQuoteBacktick: "MySQL/M (backticks `)",
|
||||
gaussdbIdentifierQuoteHint: "Auto uses JDBC driver metadata or the native GaussDB default. Select a mode manually only when generated SQL uses the wrong identifier quotes.",
|
||||
gaussdbTargetServerType: "Target server type",
|
||||
gaussdbTargetServerTypeMaster: "Master (primary)",
|
||||
gaussdbTargetServerTypeSlave: "Slave (standby)",
|
||||
gaussdbTargetServerTypeAny: "Any (no preference)",
|
||||
gaussdbTargetServerTypeHint: "Controls which node in a GaussDB cluster the JDBC driver connects to. Master tries the primary, slave tries a standby, any connects to whichever is available. Only applies in M (JDBC) mode.",
|
||||
saveAndConnect: "Save & Connect",
|
||||
save: "Save",
|
||||
editTitle: "Edit Connection",
|
||||
|
||||
@@ -726,6 +726,11 @@ export default withEnglishFallback({
|
||||
gaussdbIdentifierQuoteDouble: 'Oracle/PostgreSQL (comillas dobles ")',
|
||||
gaussdbIdentifierQuoteBacktick: "MySQL/M (acentos graves `)",
|
||||
gaussdbIdentifierQuoteHint: "El modo automático usa los metadatos del controlador JDBC o el valor predeterminado de GaussDB nativo. Seleccione un modo manualmente solo si el SQL generado usa comillas de identificador incorrectas.",
|
||||
gaussdbTargetServerType: "Tipo de servidor de destino",
|
||||
gaussdbTargetServerTypeMaster: "Principal (primario)",
|
||||
gaussdbTargetServerTypeSlave: "Réplica (en espera)",
|
||||
gaussdbTargetServerTypeAny: "Cualquiera (sin preferencia)",
|
||||
gaussdbTargetServerTypeHint: "Controla a qué nodo del clúster GaussDB se conecta el controlador JDBC. Se aplica solo al modo M (JDBC).",
|
||||
saveAndConnect: "Guardar y conectar",
|
||||
save: "Guardar",
|
||||
editTitle: "Editar conexión",
|
||||
|
||||
@@ -725,6 +725,11 @@ export default withEnglishFallback({
|
||||
gaussdbIdentifierQuoteDouble: 'Oracle/PostgreSQL (virgolette doppie ")',
|
||||
gaussdbIdentifierQuoteBacktick: "MySQL/M (accenti gravi `)",
|
||||
gaussdbIdentifierQuoteHint: "La modalità automatica usa i metadati del driver JDBC o il valore predefinito di GaussDB nativo. Seleziona manualmente una modalità solo se l'SQL generato usa virgolette errate per gli identificatori.",
|
||||
gaussdbTargetServerType: "Tipo di server di destinazione",
|
||||
gaussdbTargetServerTypeMaster: "Master (primario)",
|
||||
gaussdbTargetServerTypeSlave: "Slave (standby)",
|
||||
gaussdbTargetServerTypeAny: "Qualsiasi (nessuna preferenza)",
|
||||
gaussdbTargetServerTypeHint: "Controlla il nodo del cluster GaussDB a cui si connette il driver JDBC. Si applica solo alla modalità M (JDBC).",
|
||||
saveAndConnect: "Salva & Connetti",
|
||||
save: "Salva",
|
||||
editTitle: "Modifica Connessione",
|
||||
|
||||
@@ -691,6 +691,11 @@ export default withEnglishFallback({
|
||||
gaussdbIdentifierQuoteDouble: 'Oracle/PostgreSQL(二重引用符 ")',
|
||||
gaussdbIdentifierQuoteBacktick: "MySQL/M(バッククォート `)",
|
||||
gaussdbIdentifierQuoteHint: "自動モードでは JDBC ドライバーのメタデータまたはネイティブ GaussDB の既定値を使用します。生成された SQL の識別子引用符が誤っている場合のみ手動で選択してください。",
|
||||
gaussdbTargetServerType: "接続先サーバー種別",
|
||||
gaussdbTargetServerTypeMaster: "マスター(プライマリ)",
|
||||
gaussdbTargetServerTypeSlave: "スレーブ(スタンバイ)",
|
||||
gaussdbTargetServerTypeAny: "任意(優先なし)",
|
||||
gaussdbTargetServerTypeHint: "JDBC ドライバーが接続する GaussDB クラスターのノードを制御します。M モード(JDBC)にのみ適用されます。",
|
||||
saveAndConnect: "保存して接続",
|
||||
save: "保存",
|
||||
editTitle: "接続を編集",
|
||||
|
||||
@@ -801,6 +801,11 @@ export default withEnglishFallback({
|
||||
gaussdbMJdbcDriverHint: "드라이버는 각 GaussDB 서버 버전과 함께 배포됩니다. 해당 GaussDB 드라이버 패키지에서 gaussdbjdbc.jar를 가져오세요.",
|
||||
gaussdbMJdbcDriverRequired: "GaussDB M 모드에는 공급업체 JDBC 드라이버가 필요합니다. 서버 버전에 맞는 gaussdbjdbc.jar를 선택하세요.",
|
||||
gaussdbMJdbcPluginInstalling: "JDBC 런타임 설치 중...",
|
||||
gaussdbTargetServerType: "대상 서버 유형",
|
||||
gaussdbTargetServerTypeMaster: "마스터(기본)",
|
||||
gaussdbTargetServerTypeSlave: "슬레이브(대기)",
|
||||
gaussdbTargetServerTypeAny: "임의(선호 없음)",
|
||||
gaussdbTargetServerTypeHint: "JDBC 드라이버가 연결할 GaussDB 클러스터 노드를 제어합니다. M 모드(JDBC)에만 적용됩니다.",
|
||||
saveAndConnect: "저장 후 연결",
|
||||
save: "저장",
|
||||
editTitle: "연결 편집",
|
||||
|
||||
@@ -726,6 +726,11 @@ export default withEnglishFallback({
|
||||
gaussdbIdentifierQuoteDouble: 'Oracle/PostgreSQL (aspas duplas ")',
|
||||
gaussdbIdentifierQuoteBacktick: "MySQL/M (crases `)",
|
||||
gaussdbIdentifierQuoteHint: "O modo automático usa os metadados do driver JDBC ou o padrão do GaussDB nativo. Selecione um modo manualmente apenas quando o SQL gerado usar aspas de identificador incorretas.",
|
||||
gaussdbTargetServerType: "Tipo de servidor de destino",
|
||||
gaussdbTargetServerTypeMaster: "Master (primário)",
|
||||
gaussdbTargetServerTypeSlave: "Slave (standby)",
|
||||
gaussdbTargetServerTypeAny: "Qualquer (sem preferência)",
|
||||
gaussdbTargetServerTypeHint: "Controla a qual nó do cluster GaussDB o driver JDBC se conecta. Aplica-se apenas ao modo M (JDBC).",
|
||||
saveAndConnect: "Salvar e Conectar",
|
||||
save: "Salvar",
|
||||
editTitle: "Editar Conexão",
|
||||
|
||||
@@ -831,6 +831,11 @@ export default withEnglishFallback({
|
||||
gaussdbIdentifierQuoteDouble: 'Oracle/PostgreSQL(双引号 ")',
|
||||
gaussdbIdentifierQuoteBacktick: "MySQL/M(反引号 `)",
|
||||
gaussdbIdentifierQuoteHint: "自动模式使用 JDBC 驱动元数据或原生 GaussDB 默认值。仅当生成的 SQL 使用了错误的标识符引号时手动选择。",
|
||||
gaussdbTargetServerType: "目标服务器类型",
|
||||
gaussdbTargetServerTypeMaster: "主节点(Primary)",
|
||||
gaussdbTargetServerTypeSlave: "备节点(Standby)",
|
||||
gaussdbTargetServerTypeAny: "任意(不指定)",
|
||||
gaussdbTargetServerTypeHint: "控制 JDBC 驱动连接到 GaussDB 集群中的哪个节点。主节点优先连接主库,备节点连接备库,任意节点连接可用节点。仅适用于 M 模式(JDBC)。",
|
||||
saveAndConnect: "保存并连接",
|
||||
save: "保存",
|
||||
editTitle: "编辑连接",
|
||||
|
||||
@@ -725,6 +725,11 @@ export default withEnglishFallback({
|
||||
gaussdbIdentifierQuoteDouble: 'Oracle/PostgreSQL(雙引號 ")',
|
||||
gaussdbIdentifierQuoteBacktick: "MySQL/M(反引號 `)",
|
||||
gaussdbIdentifierQuoteHint: "自動模式使用 JDBC 驅動程式中繼資料或原生 GaussDB 預設值。僅在產生的 SQL 使用錯誤的識別字引號時手動選擇。",
|
||||
gaussdbTargetServerType: "目標伺服器類型",
|
||||
gaussdbTargetServerTypeMaster: "主節點(Primary)",
|
||||
gaussdbTargetServerTypeSlave: "備節點(Standby)",
|
||||
gaussdbTargetServerTypeAny: "任意(不指定)",
|
||||
gaussdbTargetServerTypeHint: "控制 JDBC 驅動程式連線到 GaussDB 叢集中的哪個節點。僅適用於 M 模式(JDBC)。",
|
||||
saveAndConnect: "儲存並連線",
|
||||
save: "儲存",
|
||||
editTitle: "編輯連線",
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { parse } from "vue/compiler-sfc";
|
||||
import ts from "typescript";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
|
||||
const parsedDialog = parse(dialogSource, { filename: "ConnectionDialog.vue" });
|
||||
|
||||
function connectionConfigForSubmitSource(): string {
|
||||
const script = parsedDialog.descriptor.scriptSetup;
|
||||
expect(parsedDialog.errors).toEqual([]);
|
||||
expect(script).toBeDefined();
|
||||
|
||||
const source = ts.createSourceFile("ConnectionDialog.vue.ts", script!.content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
||||
const declaration = source.statements.find((statement): statement is ts.FunctionDeclaration => ts.isFunctionDeclaration(statement) && statement.name?.text === "connectionConfigForSubmit");
|
||||
expect(declaration).toBeDefined();
|
||||
return declaration!.getText();
|
||||
}
|
||||
|
||||
describe("ConnectionDialog driver profile configuration", () => {
|
||||
it("preserves GaussDB routing and Dolt external configuration on submit", () => {
|
||||
const submitConfig = connectionConfigForSubmitSource();
|
||||
|
||||
expect(submitConfig).toContain("setGaussdbTargetServerType(config, targetServerType)");
|
||||
expect(submitConfig).toContain("else if (!isDoltDriverProfile(config.driver_profile))");
|
||||
});
|
||||
});
|
||||
@@ -13,9 +13,11 @@ import {
|
||||
gaussdbConnectionMode,
|
||||
gaussdbIdentifierQuoteOverride,
|
||||
gaussdbIdentifierQuoteStyle,
|
||||
gaussdbTargetServerType,
|
||||
inferJdbcDialect,
|
||||
setGaussdbConnectionMode,
|
||||
setGaussdbIdentifierQuoteStyle,
|
||||
setGaussdbTargetServerType,
|
||||
supportsGaussdbIdentifierQuoteStyle,
|
||||
} from "@/lib/database/jdbcDialect";
|
||||
|
||||
@@ -217,6 +219,23 @@ describe("GaussDB connection mode", () => {
|
||||
expect(connection.driver_profile).toBe("gaussdb");
|
||||
expect(connection.jdbc_driver_class).toBeUndefined();
|
||||
});
|
||||
|
||||
it("uses the driver default and preserves targetServerType from legacy URL fields", () => {
|
||||
const connection = { db_type: "gaussdb", driver_profile: "gaussdb-m" } as ConnectionConfig;
|
||||
|
||||
expect(gaussdbTargetServerType(connection)).toBe("any");
|
||||
|
||||
connection.url_params = "currentSchema=app&targetServerType=slave";
|
||||
expect(gaussdbTargetServerType(connection)).toBe("slave");
|
||||
|
||||
connection.url_params = undefined;
|
||||
connection.connection_string = "jdbc:gaussdb://db.internal:8000/app?targetServerType=MASTER&ssl=true";
|
||||
expect(gaussdbTargetServerType(connection)).toBe("master");
|
||||
|
||||
setGaussdbTargetServerType(connection, "any");
|
||||
expect(gaussdbTargetServerType(connection)).toBe("any");
|
||||
expect(connection.external_config).toEqual({ gaussdbTargetServerType: "any" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("query execution schema", () => {
|
||||
|
||||
@@ -2,12 +2,14 @@ import type { ConnectionConfig, DatabaseType } from "@/types/database";
|
||||
import { isSchemaAware, usesDatabaseObjectTreeMode, usesTreeSchemaMode } from "@/lib/database/databaseFeatureSupport";
|
||||
import type { CodeMirrorSqlDialectName } from "@/lib/editor/codemirrorSqlDialect";
|
||||
|
||||
type JdbcDialectConnection = Partial<Pick<ConnectionConfig, "db_type" | "driver_profile" | "driver_label" | "connection_string" | "jdbc_driver_class" | "jdbc_driver_paths" | "database_info" | "external_config">>;
|
||||
type JdbcDialectConnection = Partial<Pick<ConnectionConfig, "db_type" | "driver_profile" | "driver_label" | "connection_string" | "url_params" | "jdbc_driver_class" | "jdbc_driver_paths" | "database_info" | "external_config">>;
|
||||
|
||||
export type GaussdbIdentifierQuoteStyle = "auto" | "double" | "backtick";
|
||||
export type GaussdbConnectionMode = "native" | "m-jdbc";
|
||||
export type GaussdbTargetServerType = "master" | "slave" | "any";
|
||||
|
||||
const GAUSSDB_IDENTIFIER_QUOTE_STYLE_KEY = "gaussdbIdentifierQuoteStyle";
|
||||
const GAUSSDB_TARGET_SERVER_TYPE_KEY = "gaussdbTargetServerType";
|
||||
export const GAUSSDB_M_JDBC_DRIVER_PROFILE = "gaussdb-m";
|
||||
export const GAUSSDB_M_JDBC_DRIVER_CLASS = "com.huawei.gaussdb.jdbc.Driver";
|
||||
|
||||
@@ -125,6 +127,36 @@ export function setGaussdbIdentifierQuoteStyle(
|
||||
connection.external_config = Object.keys(external).length > 0 ? external : undefined;
|
||||
}
|
||||
|
||||
export function gaussdbTargetServerType(connection: JdbcDialectConnection | undefined): GaussdbTargetServerType {
|
||||
const external = externalConfigRecord(connection?.external_config);
|
||||
return normalizeGaussdbTargetServerType(external[GAUSSDB_TARGET_SERVER_TYPE_KEY]) ?? gaussdbTargetServerTypeFromUrl(connection) ?? "any";
|
||||
}
|
||||
|
||||
export function setGaussdbTargetServerType(connection: Pick<ConnectionConfig, "db_type"> & Partial<Pick<ConnectionConfig, "driver_profile" | "driver_label" | "connection_string" | "jdbc_driver_class" | "jdbc_driver_paths" | "database_info" | "external_config">>, value: GaussdbTargetServerType) {
|
||||
const external = externalConfigRecord(connection.external_config);
|
||||
external[GAUSSDB_TARGET_SERVER_TYPE_KEY] = value;
|
||||
connection.external_config = Object.keys(external).length > 0 ? external : undefined;
|
||||
}
|
||||
|
||||
function normalizeGaussdbTargetServerType(value: unknown): GaussdbTargetServerType | undefined {
|
||||
if (typeof value !== "string") return undefined;
|
||||
const normalized = value.trim().toLowerCase();
|
||||
return normalized === "master" || normalized === "slave" || normalized === "any" ? normalized : undefined;
|
||||
}
|
||||
|
||||
function gaussdbTargetServerTypeFromUrl(connection: JdbcDialectConnection | undefined): GaussdbTargetServerType | undefined {
|
||||
const values = [connection?.url_params, connection?.connection_string?.split("?", 2)[1]?.split("#", 1)[0]];
|
||||
for (const value of values) {
|
||||
const params = new URLSearchParams((value || "").trim().replace(/^\?/, "").replace(/;/g, "&"));
|
||||
for (const [key, paramValue] of params) {
|
||||
if (key.toLowerCase() === "targetservertype") {
|
||||
return normalizeGaussdbTargetServerType(paramValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function sqlSnippetDatabaseTypeForConnection(connection?: JdbcDialectConnection): DatabaseType | undefined {
|
||||
// ASE uses T-SQL snippets, but mapping it globally to SQL Server would also
|
||||
// enable incompatible SQL Server metadata and pagination behavior.
|
||||
|
||||
Reference in new issue
Block a user