fix(db): normalize default database handling
This commit is contained in:
parent
5cffe12014
commit
af029daf57
|
|
@ -58,10 +58,7 @@ pub fn metadata_connection_config(config: &ConnectionConfig) -> ConnectionConfig
|
|||
pub fn database_connection_config(config: &ConnectionConfig, database: Option<&str>) -> ConnectionConfig {
|
||||
let mut db_config = if database.is_some() { config.clone() } else { metadata_connection_config(config) };
|
||||
if let Some(db) = database {
|
||||
if db_config.db_type != DatabaseType::Oracle
|
||||
&& db_config.db_type != DatabaseType::Dameng
|
||||
&& db_config.db_type != DatabaseType::Gaussdb
|
||||
{
|
||||
if db_config.db_type != DatabaseType::Oracle && db_config.db_type != DatabaseType::Dameng {
|
||||
db_config.database = Some(db.to_string());
|
||||
}
|
||||
}
|
||||
|
|
@ -90,8 +87,7 @@ impl AppState {
|
|||
return Ok(connection_id.to_string());
|
||||
}
|
||||
|
||||
let is_single_conn =
|
||||
matches!(db_type, Some(DatabaseType::Oracle) | Some(DatabaseType::Dameng) | Some(DatabaseType::Gaussdb));
|
||||
let is_single_conn = matches!(db_type, Some(DatabaseType::Oracle) | Some(DatabaseType::Dameng));
|
||||
let pool_key = if is_single_conn {
|
||||
connection_id.to_string()
|
||||
} else {
|
||||
|
|
@ -207,7 +203,7 @@ impl AppState {
|
|||
let client = db::gaussdb_driver::connect(
|
||||
&host,
|
||||
port,
|
||||
db_config.database.as_deref().unwrap_or(""),
|
||||
db_config.effective_database().unwrap_or("postgres"),
|
||||
&db_config.username,
|
||||
&db_config.password,
|
||||
)
|
||||
|
|
@ -272,7 +268,6 @@ impl AppState {
|
|||
c.db_type == DatabaseType::Oracle
|
||||
|| c.db_type == DatabaseType::Elasticsearch
|
||||
|| c.db_type == DatabaseType::Dameng
|
||||
|| c.db_type == DatabaseType::Gaussdb
|
||||
})
|
||||
.unwrap_or(false)
|
||||
};
|
||||
|
|
@ -378,4 +373,24 @@ mod tests {
|
|||
|
||||
assert_eq!(scoped.database.as_deref(), Some("analytics"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gaussdb_database_connection_keeps_requested_database() {
|
||||
let mut config = mysql_config(Some("postgres"));
|
||||
config.db_type = DatabaseType::Gaussdb;
|
||||
|
||||
let scoped = database_connection_config(&config, Some("analytics"));
|
||||
|
||||
assert_eq!(scoped.database.as_deref(), Some("analytics"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oracle_database_connection_ignores_requested_database() {
|
||||
let mut config = mysql_config(Some("ORCL"));
|
||||
config.db_type = DatabaseType::Oracle;
|
||||
|
||||
let scoped = database_connection_config(&config, Some("analytics"));
|
||||
|
||||
assert_eq!(scoped.database.as_deref(), Some("ORCL"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ impl GaussdbClient {
|
|||
}
|
||||
|
||||
pub async fn connect(host: &str, port: u16, database: &str, user: &str, pass: &str) -> Result<GaussdbClient, String> {
|
||||
let database = normalize_database(database);
|
||||
let dsn = format!("host={host} port={port} user={user} password={pass} dbname={database}");
|
||||
|
||||
let result = tokio::time::timeout(std::time::Duration::from_secs(CONNECTION_TIMEOUT_SECS), async {
|
||||
|
|
@ -41,6 +42,15 @@ pub async fn connect(host: &str, port: u16, database: &str, user: &str, pass: &s
|
|||
result.map(|client| GaussdbClient { client })
|
||||
}
|
||||
|
||||
fn normalize_database(database: &str) -> &str {
|
||||
let database = database.trim();
|
||||
if database.is_empty() {
|
||||
"postgres"
|
||||
} else {
|
||||
database
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_databases(client: &mut GaussdbClient) -> Result<Vec<DatabaseInfo>, String> {
|
||||
let rows = client
|
||||
.query_single_column("SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname")
|
||||
|
|
@ -276,3 +286,19 @@ pub async fn execute_query(client: &mut GaussdbClient, sql: &str) -> Result<Quer
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::normalize_database;
|
||||
|
||||
#[test]
|
||||
fn normalize_database_defaults_blank_to_postgres() {
|
||||
assert_eq!(normalize_database(""), "postgres");
|
||||
assert_eq!(normalize_database(" "), "postgres");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_database_keeps_explicit_database() {
|
||||
assert_eq!(normalize_database("app"), "app");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,26 @@ pub enum DatabaseType {
|
|||
}
|
||||
|
||||
impl ConnectionConfig {
|
||||
pub fn effective_database(&self) -> Option<&str> {
|
||||
self.database
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|database| !database.is_empty())
|
||||
.or_else(|| self.default_database())
|
||||
}
|
||||
|
||||
fn default_database(&self) -> Option<&'static str> {
|
||||
match self.db_type {
|
||||
DatabaseType::Postgres => match self.driver_profile.as_deref() {
|
||||
Some("cockroachdb") => Some("defaultdb"),
|
||||
_ => Some("postgres"),
|
||||
},
|
||||
DatabaseType::Redshift => Some("dev"),
|
||||
DatabaseType::Gaussdb => Some("postgres"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn needs_bare_mysql(&self) -> bool {
|
||||
matches!(self.db_type, DatabaseType::Doris | DatabaseType::StarRocks)
|
||||
|| self
|
||||
|
|
@ -94,12 +114,7 @@ impl ConnectionConfig {
|
|||
|
||||
pub fn redacted_connection_url_with_host(&self, host: &str, port: u16) -> String {
|
||||
let host = bracket_ipv6(host);
|
||||
let db_part = self
|
||||
.database
|
||||
.as_deref()
|
||||
.filter(|d| !d.is_empty())
|
||||
.map(|d| format!("/{}", encode_url_part(d)))
|
||||
.unwrap_or_default();
|
||||
let db_part = self.effective_database().map(|d| format!("/{}", encode_url_part(d))).unwrap_or_default();
|
||||
let params = self.normalized_url_params();
|
||||
|
||||
match self.db_type {
|
||||
|
|
@ -148,12 +163,7 @@ impl ConnectionConfig {
|
|||
|
||||
pub fn connection_url_with_host(&self, host: &str, port: u16) -> String {
|
||||
let host = bracket_ipv6(host);
|
||||
let db_part = self
|
||||
.database
|
||||
.as_deref()
|
||||
.filter(|d| !d.is_empty())
|
||||
.map(|d| format!("/{}", encode_url_part(d)))
|
||||
.unwrap_or_default();
|
||||
let db_part = self.effective_database().map(|d| format!("/{}", encode_url_part(d))).unwrap_or_default();
|
||||
let username = encode_url_part(&self.username);
|
||||
let password = encode_url_part(&self.password);
|
||||
let params = self.normalized_url_params();
|
||||
|
|
@ -413,6 +423,47 @@ mod tests {
|
|||
assert_eq!(config.connection_url(), "postgres://postgres:secret@10.1.2.3:2883/test?sslmode=disable");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn postgres_url_defaults_to_postgres_database_when_omitted() {
|
||||
let mut config = mysql_config("root", "secret", None);
|
||||
config.db_type = DatabaseType::Postgres;
|
||||
|
||||
assert_eq!(config.connection_url(), "postgres://root:secret@10.1.2.3:2883/postgres");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn postgres_url_defaults_to_postgres_database_when_empty() {
|
||||
let mut config = mysql_config("root", "secret", Some(""));
|
||||
config.db_type = DatabaseType::Postgres;
|
||||
|
||||
assert_eq!(config.connection_url(), "postgres://root:secret@10.1.2.3:2883/postgres");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn redshift_url_defaults_to_dev_database_when_empty() {
|
||||
let mut config = mysql_config("awsuser", "secret", Some(""));
|
||||
config.db_type = DatabaseType::Redshift;
|
||||
|
||||
assert_eq!(config.connection_url(), "postgres://awsuser:secret@10.1.2.3:2883/dev");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cockroachdb_url_defaults_to_defaultdb_database() {
|
||||
let mut config = mysql_config("root", "secret", None);
|
||||
config.db_type = DatabaseType::Postgres;
|
||||
config.driver_profile = Some("cockroachdb".to_string());
|
||||
|
||||
assert_eq!(config.connection_url(), "postgres://root:secret@10.1.2.3:2883/defaultdb");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gaussdb_url_defaults_to_postgres_database() {
|
||||
let mut config = mysql_config("gaussdb", "secret", None);
|
||||
config.db_type = DatabaseType::Gaussdb;
|
||||
|
||||
assert_eq!(config.connection_url(), "gaussdb://gaussdb:secret@10.1.2.3:2883/postgres");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mongodb_form_url_without_params_does_not_force_topology_or_auth() {
|
||||
let config = mongodb_config("root", "secret", Some("admin"));
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ const driverProfiles: Record<
|
|||
icon: "starrocks",
|
||||
urlParams: "",
|
||||
},
|
||||
redshift: { type: "postgres", port: 5439, user: "awsuser", label: "Redshift", icon: "redshift" },
|
||||
redshift: { type: "redshift", port: 5439, user: "awsuser", label: "Redshift", icon: "redshift" },
|
||||
cockroachdb: {
|
||||
type: "postgres",
|
||||
port: 26257,
|
||||
|
|
@ -273,6 +273,26 @@ watch(
|
|||
},
|
||||
);
|
||||
|
||||
const databaseLabel = computed(() =>
|
||||
form.value.db_type === "oracle" ? t("connection.serviceName") : t("connection.database"),
|
||||
);
|
||||
|
||||
const databasePlaceholder = computed(() => {
|
||||
const fallback = defaultDatabaseForProfile();
|
||||
if (!fallback) return t("connection.databasePlaceholder");
|
||||
return t("connection.databasePlaceholderWithDefault", { database: fallback });
|
||||
});
|
||||
|
||||
function defaultDatabaseForProfile() {
|
||||
if (form.value.db_type === "redshift") return "dev";
|
||||
if (form.value.db_type === "gaussdb") return "postgres";
|
||||
if (selectedType.value === "cockroachdb") return "defaultdb";
|
||||
if (form.value.db_type === "postgres") return "postgres";
|
||||
if (form.value.db_type === "sqlserver") return "master";
|
||||
if (form.value.db_type === "oracle") return "ORCL";
|
||||
return "";
|
||||
}
|
||||
|
||||
function onDbTypeChange(val: string) {
|
||||
customDriverName.value = "";
|
||||
applyProfile(val, !!editingId.value);
|
||||
|
|
@ -821,12 +841,8 @@ async function browseDbFilePath() {
|
|||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label class="text-right">{{ t("connection.database") }}</Label>
|
||||
<Input
|
||||
v-model="form.database"
|
||||
class="col-span-3"
|
||||
:placeholder="t('connection.databasePlaceholder')"
|
||||
/>
|
||||
<Label class="text-right">{{ databaseLabel }}</Label>
|
||||
<Input v-model="form.database" class="col-span-3" :placeholder="databasePlaceholder" />
|
||||
</div>
|
||||
|
||||
<div v-if="selectedType === 'dm'" class="grid grid-cols-4 items-center gap-4">
|
||||
|
|
@ -852,14 +868,14 @@ async function browseDbFilePath() {
|
|||
</div>
|
||||
|
||||
<div
|
||||
v-if="form.db_type === 'mysql' || form.db_type === 'postgres'"
|
||||
v-if="form.db_type === 'mysql' || form.db_type === 'postgres' || form.db_type === 'redshift'"
|
||||
class="grid grid-cols-4 items-center gap-4"
|
||||
>
|
||||
<Label class="text-right">{{ t("connection.urlParams") }}</Label>
|
||||
<Input
|
||||
v-model="form.url_params"
|
||||
class="col-span-3"
|
||||
:placeholder="form.db_type === 'postgres' ? 'sslmode=disable' : 'charset=utf8mb4'"
|
||||
:placeholder="form.db_type === 'mysql' ? 'charset=utf8mb4' : 'sslmode=disable'"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ export default {
|
|||
password: "Password",
|
||||
database: "Database",
|
||||
databasePlaceholder: "Optional",
|
||||
databasePlaceholderWithDefault: "Optional, defaults to {database}",
|
||||
serviceName: "Service/SID",
|
||||
driverName: "Driver Name",
|
||||
driverNamePlaceholder: "Vendor or environment name",
|
||||
urlParams: "URL Params",
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ export default {
|
|||
password: "密码",
|
||||
database: "数据库",
|
||||
databasePlaceholder: "可选",
|
||||
databasePlaceholderWithDefault: "可选,默认 {database}",
|
||||
serviceName: "服务名/SID",
|
||||
driverName: "驱动名称",
|
||||
driverNamePlaceholder: "厂商或环境名称",
|
||||
urlParams: "URL 参数",
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ export const FIELD_LINEAGE_SUPPORTED_TYPES = new Set<DatabaseType>([
|
|||
|
||||
export const FETCH_FIRST_TYPES = new Set<DatabaseType>(["oracle", "dameng"]);
|
||||
|
||||
export const TREE_SCHEMA_TYPES = new Set<DatabaseType>(["postgres", "sqlserver", "gaussdb"]);
|
||||
export const TREE_SCHEMA_TYPES = new Set<DatabaseType>(["postgres", "redshift", "sqlserver", "gaussdb"]);
|
||||
|
||||
export const PG_LIKE_STRUCTURE_TYPES = new Set<DatabaseType>(["postgres", "redshift", "gaussdb"]);
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,8 @@ export const useConnectionStore = defineStore("connection", () => {
|
|||
let dbType = config.db_type;
|
||||
if ((profile === "gaussdb" || profile === "opengauss") && dbType === "postgres") {
|
||||
dbType = "gaussdb" as ConnectionConfig["db_type"];
|
||||
} else if (profile === "redshift" && dbType === "postgres") {
|
||||
dbType = "redshift" as ConnectionConfig["db_type"];
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
Loading…
Reference in New Issue