diff --git a/README.md b/README.md index b0306c1398..9a6271adb7 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ ### 50+ Databases, One Tool -MySQL, PostgreSQL, SQLite, Redis, MongoDB, DuckDB, ClickHouse, SQL Server, Oracle, Elasticsearch, MariaDB, TiDB, OceanBase, openGauss, GaussDB, KWDB, KingBase, Vastbase, GoldenDB, Doris, SelectDB, StarRocks, Redshift, DM, TDengine, XuguDB, CockroachDB, Access, HighGo, and more. Agent/JDBC-oriented profiles extend DBX to H2, Snowflake, Trino, Hive, DB2, Informix, Neo4j, Cassandra, BigQuery, Kylin, SunDB, and custom JDBC connections. New native and agent-driven drivers also cover Databricks, SAP HANA, Teradata, Vertica, Firebird, Exasol, YashanDB, GBase, Databend, RQLite, Turso, InfluxDB, IoTDB, etcd, IRIS, and more. All in a single ~15 MB app. No bundled Chromium. +MySQL, PostgreSQL, SQLite, Redis, MongoDB, DuckDB, ClickHouse, SQL Server, Oracle, Elasticsearch, MariaDB, TiDB, OceanBase, openGauss, GaussDB, KWDB, KingBase, Vastbase, GoldenDB, Doris, SelectDB, StarRocks, Manticore Search, Redshift, DM, TDengine, XuguDB, CockroachDB, Access, HighGo, and more. Agent/JDBC-oriented profiles extend DBX to H2, Snowflake, Trino, Hive, DB2, Informix, Neo4j, Cassandra, BigQuery, Kylin, SunDB, and custom JDBC connections. New native and agent-driven drivers also cover Databricks, SAP HANA, Teradata, Vertica, Firebird, Exasol, YashanDB, GBase, Databend, RQLite, Turso, InfluxDB, IoTDB, etcd, IRIS, and more. All in a single ~15 MB app. No bundled Chromium. ### Query Editor @@ -324,7 +324,7 @@ DBX is 15 MB with no runtime dependencies (no Java, no Python). It includes AI a
What databases are supported? -MySQL, PostgreSQL, SQLite, Redis, MongoDB, DuckDB, ClickHouse, SQL Server, Oracle, Elasticsearch, MariaDB, TiDB, OceanBase, openGauss, GaussDB, KWDB, KingBase, Vastbase, GoldenDB, Doris, SelectDB, StarRocks, Redshift, DM, TDengine, XuguDB, CockroachDB, Access, HighGo, and more. Agent/JDBC-oriented profiles extend support to H2, Snowflake, Trino, Hive, DB2, Informix, Neo4j, Cassandra, BigQuery, Kylin, SunDB, Databricks, SAP HANA, Teradata, Vertica, Firebird, Exasol, YashanDB, GBase, Databend, RQLite, Turso, InfluxDB, IoTDB, etcd, IRIS, and custom JDBC connections. +MySQL, PostgreSQL, SQLite, Redis, MongoDB, DuckDB, ClickHouse, SQL Server, Oracle, Elasticsearch, MariaDB, TiDB, OceanBase, openGauss, GaussDB, KWDB, KingBase, Vastbase, GoldenDB, Doris, SelectDB, StarRocks, Manticore Search, Redshift, DM, TDengine, XuguDB, CockroachDB, Access, HighGo, and more. Agent/JDBC-oriented profiles extend support to H2, Snowflake, Trino, Hive, DB2, Informix, Neo4j, Cassandra, BigQuery, Kylin, SunDB, Databricks, SAP HANA, Teradata, Vertica, Firebird, Exasol, YashanDB, GBase, Databend, RQLite, Turso, InfluxDB, IoTDB, etcd, IRIS, and custom JDBC connections.
diff --git a/README.zh-CN.md b/README.zh-CN.md index b8f78e512b..3610cae541 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -87,7 +87,7 @@ ### 50+ 种数据库,一个工具搞定 -MySQL、PostgreSQL、SQLite、Redis、MongoDB、DuckDB、ClickHouse、SQL Server、Oracle、Elasticsearch、MariaDB、TiDB、OceanBase、openGauss、GaussDB、KWDB、KingBase、Vastbase、GoldenDB、Doris、SelectDB、StarRocks、Redshift、DM、TDengine、虚谷 XuguDB、CockroachDB、Access、HighGo 等数据库都能直接连接。Agent/JDBC 方向的配置还可扩展到 H2、Snowflake、Trino、Hive、DB2、Informix、Neo4j、Cassandra、BigQuery、Kylin、SunDB 和自定义 JDBC。新增的原生与 Agent 驱动还覆盖了 Databricks、SAP HANA、Teradata、Vertica、Firebird、Exasol、崖山 YashanDB、GBase、Databend、RQLite、Turso、InfluxDB、IoTDB、etcd、IRIS 等。全部装进约 15 MB 的应用里,不内嵌 Chromium。 +MySQL、PostgreSQL、SQLite、Redis、MongoDB、DuckDB、ClickHouse、SQL Server、Oracle、Elasticsearch、MariaDB、TiDB、OceanBase、openGauss、GaussDB、KWDB、KingBase、Vastbase、GoldenDB、Doris、SelectDB、StarRocks、Manticore Search、Redshift、DM、TDengine、虚谷 XuguDB、CockroachDB、Access、HighGo 等数据库都能直接连接。Agent/JDBC 方向的配置还可扩展到 H2、Snowflake、Trino、Hive、DB2、Informix、Neo4j、Cassandra、BigQuery、Kylin、SunDB 和自定义 JDBC。新增的原生与 Agent 驱动还覆盖了 Databricks、SAP HANA、Teradata、Vertica、Firebird、Exasol、崖山 YashanDB、GBase、Databend、RQLite、Turso、InfluxDB、IoTDB、etcd、IRIS 等。全部装进约 15 MB 的应用里,不内嵌 Chromium。 ### 查询编辑器 @@ -320,7 +320,7 @@ DBX 仅 15 MB,无需运行时依赖(无需 Java、无需 Python)。AI 和
支持哪些数据库? -MySQL、PostgreSQL、SQLite、Redis、MongoDB、DuckDB、ClickHouse、SQL Server、Oracle、Elasticsearch、MariaDB、TiDB、OceanBase、openGauss、GaussDB、KWDB、KingBase、Vastbase、GoldenDB、Doris、SelectDB、StarRocks、Redshift、DM、TDengine、虚谷 XuguDB、CockroachDB、Access、HighGo 等。JDBC 方向配置可扩展到 H2、Snowflake、Trino、Hive、DB2、Informix、Neo4j、Cassandra、BigQuery、Kylin、SunDB、Databricks、SAP HANA、Teradata、Vertica、Firebird、Exasol、崖山 YashanDB、GBase、Databend、RQLite、Turso、InfluxDB、IoTDB、etcd、IRIS 及自定义 JDBC 连接。 +MySQL、PostgreSQL、SQLite、Redis、MongoDB、DuckDB、ClickHouse、SQL Server、Oracle、Elasticsearch、MariaDB、TiDB、OceanBase、openGauss、GaussDB、KWDB、KingBase、Vastbase、GoldenDB、Doris、SelectDB、StarRocks、Manticore Search、Redshift、DM、TDengine、虚谷 XuguDB、CockroachDB、Access、HighGo 等。JDBC 方向配置可扩展到 H2、Snowflake、Trino、Hive、DB2、Informix、Neo4j、Cassandra、BigQuery、Kylin、SunDB、Databricks、SAP HANA、Teradata、Vertica、Firebird、Exasol、崖山 YashanDB、GBase、Databend、RQLite、Turso、InfluxDB、IoTDB、etcd、IRIS 及自定义 JDBC 连接。
diff --git a/apps/desktop/public/icons/database/manticoresearch.png b/apps/desktop/public/icons/database/manticoresearch.png new file mode 100644 index 0000000000..420cb72a59 Binary files /dev/null and b/apps/desktop/public/icons/database/manticoresearch.png differ diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue index e7af392606..cad99a3de9 100644 --- a/apps/desktop/src/components/connection/ConnectionDialog.vue +++ b/apps/desktop/src/components/connection/ConnectionDialog.vue @@ -420,6 +420,14 @@ const driverProfiles: Record< icon: "starrocks", urlParams: "", }, + manticoresearch: { + type: "manticoresearch", + port: 9306, + user: "root", + label: "Manticore Search", + icon: "manticoresearch", + urlParams: "", + }, redshift: { type: "redshift", port: 5439, user: "awsuser", label: "Redshift", icon: "redshift" }, cockroachdb: { type: "postgres", @@ -734,6 +742,7 @@ const iconTypeMap: Record = { doris: "doris", selectdb: "selectdb", starrocks: "starrocks", + manticoresearch: "manticoresearch", redshift: "redshift", cockroachdb: "cockroachdb", tdengine: "tdengine", @@ -819,6 +828,9 @@ const dbOptions: DbOption[] = [ { value: "influxdb", label: "InfluxDB" }, { value: "iris", label: "IRIS" }, { value: "jdbc", label: "JDBC" }, + { value: "manticoresearch", label: "Manticore Search" }, + { value: "custom_mysql", label: "Custom (MySQL)" }, + { value: "custom_postgres", label: "Custom (PostgreSQL)" }, ]; const dbCategories = computed(() => [{ key: "all", title: "", options: dbOptions }]); @@ -867,6 +879,7 @@ const sqliteExtensionPaths = computed({ const tlsCapableDatabaseTypes = new Set(["mysql", "postgres", "redshift", "gaussdb", "kwdb", "opengauss", "redis", "etcd", "clickhouse", "elasticsearch", "influxdb"]); const supportsTlsToggle = computed(() => tlsCapableDatabaseTypes.has(form.value.db_type)); const supportsCaCertificatePath = computed(() => form.value.db_type === "clickhouse"); +const supportsGenericUrlParams = computed(() => form.value.db_type !== "manticoresearch"); const bareMysqlProfiles = new Set(["doris", "starrocks", "selectdb", "oceanbase"]); const supportsMysqlTlsOptions = computed(() => form.value.db_type === "mysql" && !bareMysqlProfiles.has(selectedType.value)); const mysqlTlsMode = computed({ @@ -1072,6 +1085,9 @@ function connectionConfigForSubmit(id: string): ConnectionConfig { config.query_timeout_secs = Number.isFinite(queryTimeout) && queryTimeout >= 0 ? queryTimeout : 30; const idleTimeout = Number(config.idle_timeout_secs); config.idle_timeout_secs = Number.isFinite(idleTimeout) && idleTimeout >= 0 ? idleTimeout : 60; + if (config.db_type === "manticoresearch") { + config.url_params = ""; + } if (!config.one_time) config.one_time = undefined; if (!config.read_only) config.read_only = undefined; if (config.db_type === "mongodb" && !mongoUseUrl.value) { @@ -2606,7 +2622,7 @@ function openExternalUrl(url: string) { -
+
= { bigquery: "bigquery", cassandra: "cassandra", doris: "doris", + manticoresearch: "manticoresearch.png", selectdb: "selectdb", tdengine: "tdengine", starrocks: "starrocks", diff --git a/apps/desktop/src/lib/connectionPresentation.ts b/apps/desktop/src/lib/connectionPresentation.ts index 6bb3e01490..44aa463c0d 100644 --- a/apps/desktop/src/lib/connectionPresentation.ts +++ b/apps/desktop/src/lib/connectionPresentation.ts @@ -82,6 +82,7 @@ export function connectionUrlPlaceholder(dbType: DatabaseType): string { case "mysql": case "doris": case "starrocks": + case "manticoresearch": return "mysql://user:password@host:port/database"; case "postgres": @@ -162,4 +163,4 @@ export function connectionOptionSubtitle(connection?: ConnectionPresentationConf export function connectionRedactedOptionSubtitle(connection?: ConnectionPresentationConfig): string { return [connectionDriverLabel(connection), connectionRedactedEndpointLabel(connection)].filter(Boolean).join(" · "); -} +} \ No newline at end of file diff --git a/apps/desktop/src/lib/databaseFeatureSupport.ts b/apps/desktop/src/lib/databaseFeatureSupport.ts index fef170e2ac..928cbaeb3b 100644 --- a/apps/desktop/src/lib/databaseFeatureSupport.ts +++ b/apps/desktop/src/lib/databaseFeatureSupport.ts @@ -82,9 +82,9 @@ export function supportsObjectBrowserTreeNode(dbType: DatabaseType | undefined, } export function supportsTableTruncate(dbType?: DatabaseType): boolean { - return !!dbType && dbType !== "sqlite" && dbType !== "rqlite" && dbType !== "turso" && dbType !== "duckdb" && dbType !== "influxdb"; + return !!dbType && dbType !== "sqlite" && dbType !== "rqlite" && dbType !== "turso" && dbType !== "duckdb" && dbType !== "influxdb" && dbType !== "manticoresearch"; } export function usesPostgresLikeStructureCopy(dbType?: DatabaseType): boolean { return !!dbType && PG_LIKE_STRUCTURE_TYPES.has(dbType); -} +} \ No newline at end of file diff --git a/apps/desktop/src/lib/visibleDatabases.ts b/apps/desktop/src/lib/visibleDatabases.ts index 1c616b5963..fd7eac3d3e 100644 --- a/apps/desktop/src/lib/visibleDatabases.ts +++ b/apps/desktop/src/lib/visibleDatabases.ts @@ -4,6 +4,7 @@ const SYSTEM_DATABASE_RULES: Partial>> mysql: new Set(["information_schema", "mysql", "performance_schema", "sys"]), doris: new Set(["information_schema", "mysql", "performance_schema", "sys"]), starrocks: new Set(["information_schema", "mysql", "performance_schema", "sys"]), + manticoresearch: new Set(["information_schema", "mysql", "performance_schema", "sys"]), goldendb: new Set(["information_schema", "mysql", "performance_schema", "sys"]), gbase: new Set(["information_schema", "mysql", "performance_schema", "sys"]), postgres: new Set(["template0", "template1"]), @@ -94,4 +95,4 @@ export function filterDatabaseNamesForConnection(databaseNames: string[], connec return databaseNames; } return databaseNames.filter((name) => !isSystemDatabaseName(connection?.db_type, name)); -} +} \ No newline at end of file diff --git a/apps/desktop/src/stores/connectionStore.ts b/apps/desktop/src/stores/connectionStore.ts index ed9e276990..b5f41f4eb2 100644 --- a/apps/desktop/src/stores/connectionStore.ts +++ b/apps/desktop/src/stores/connectionStore.ts @@ -241,6 +241,7 @@ export const useConnectionStore = defineStore("connection", () => { elasticsearch: "Elasticsearch", doris: "Doris", starrocks: "StarRocks", + manticoresearch: "Manticore Search", redshift: "Redshift", dameng: "DM (Dameng)", gaussdb: "GaussDB", @@ -2768,4 +2769,4 @@ export const useConnectionStore = defineStore("connection", () => { if (changed) updateLayoutAndRebuild(layout); }, }; -}); +}); \ No newline at end of file diff --git a/apps/desktop/src/types/database.ts b/apps/desktop/src/types/database.ts index e96836f068..5682299692 100644 --- a/apps/desktop/src/types/database.ts +++ b/apps/desktop/src/types/database.ts @@ -13,6 +13,7 @@ export type DatabaseType = | "elasticsearch" | "doris" | "starrocks" + | "manticoresearch" | "databend" | "redshift" | "dameng" @@ -542,4 +543,4 @@ export interface SavedSqlFile { export interface SavedSqlLibrary { folders: SavedSqlFolder[]; files: SavedSqlFile[]; -} +} \ No newline at end of file diff --git a/crates/dbx-core/assets/database-drivers.manifest.json b/crates/dbx-core/assets/database-drivers.manifest.json index a1cd9b1c27..17ef47063b 100644 --- a/crates/dbx-core/assets/database-drivers.manifest.json +++ b/crates/dbx-core/assets/database-drivers.manifest.json @@ -378,6 +378,35 @@ "driverManagement": false } }, + { + "dbType": "manticoresearch", + "label": "Manticore Search", + "runtimeMode": "native", + "mcpMode": "direct", + "singleConnectionPool": false, + "metadataConnectionScoped": false, + "skipTcpProbe": false, + "defaultPort": 9306, + "supportLevel": "browse", + "capabilities": { + "queryExecution": true, + "metadataBrowse": true, + "objectBrowser": false, + "objectSource": false, + "schemaSearch": false, + "diagram": false, + "tableDataEdit": false, + "tableStructureEdit": false, + "tableImport": false, + "dataTransfer": false, + "sqlFileExecution": true, + "databaseCreate": false, + "fieldLineage": false, + "sqlExplain": false, + "userAdmin": false, + "driverManagement": false + } + }, { "dbType": "redshift", "label": "Redshift", diff --git a/crates/dbx-core/src/connection.rs b/crates/dbx-core/src/connection.rs index e4ac498e2a..218479f2e2 100644 --- a/crates/dbx-core/src/connection.rs +++ b/crates/dbx-core/src/connection.rs @@ -358,7 +358,7 @@ impl AppState { .await?; PoolKind::Mysql(pool, mode) } - DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::Databend => { + DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch | DatabaseType::Databend => { let pool = if database.is_none() { connect_bare_metadata_pool(&db_config, &host, port, connect_timeout, mysql_pool_max_connections) .await? diff --git a/crates/dbx-core/src/db/mysql.rs b/crates/dbx-core/src/db/mysql.rs index 60cc0ca4ca..bdc5b2fb1c 100644 --- a/crates/dbx-core/src/db/mysql.rs +++ b/crates/dbx-core/src/db/mysql.rs @@ -29,8 +29,12 @@ impl MySqlQueryDialect { pub fn for_connection(db_type: DatabaseType, driver_profile: Option<&str>) -> Self { let profile = driver_profile.map(str::to_ascii_lowercase); Self { - supports_admin_show_results: matches!(db_type, DatabaseType::Doris | DatabaseType::StarRocks) - || profile.as_deref().is_some_and(|profile| matches!(profile, "doris" | "selectdb" | "starrocks")), + supports_admin_show_results: matches!( + db_type, + DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch + ) || profile + .as_deref() + .is_some_and(|profile| matches!(profile, "doris" | "selectdb" | "starrocks" | "manticoresearch")), } } } diff --git a/crates/dbx-core/src/models/connection.rs b/crates/dbx-core/src/models/connection.rs index 6cf07e66c5..23997f38ad 100644 --- a/crates/dbx-core/src/models/connection.rs +++ b/crates/dbx-core/src/models/connection.rs @@ -240,6 +240,8 @@ pub enum DatabaseType { Doris, #[serde(rename = "starrocks")] StarRocks, + #[serde(rename = "manticoresearch")] + ManticoreSearch, Databend, Redshift, Dameng, @@ -593,12 +595,10 @@ impl ConnectionConfig { } pub fn needs_bare_mysql(&self) -> bool { - matches!(self.db_type, DatabaseType::Doris | DatabaseType::StarRocks) - || self - .driver_profile - .as_deref() - .map(|p| p.to_lowercase()) - .is_some_and(|p| matches!(p.as_str(), "doris" | "starrocks" | "selectdb" | "oceanbase")) + matches!(self.db_type, DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch) + || self.driver_profile.as_deref().map(|p| p.to_lowercase()).is_some_and(|p| { + matches!(p.as_str(), "doris" | "starrocks" | "manticoresearch" | "selectdb" | "oceanbase") + }) } pub fn canonicalized(&self) -> Self { @@ -656,7 +656,11 @@ impl ConnectionConfig { let fragment = self.redis_tls_insecure_fragment(); format!("{scheme}://{host}:{port}/{fragment}") } - DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::Databend => { + DatabaseType::Mysql + | DatabaseType::Doris + | DatabaseType::StarRocks + | DatabaseType::ManticoreSearch + | DatabaseType::Databend => { let suffix = if params.is_empty() { String::new() } else { format!("?{params}") }; format!("mysql://{host}:{port}{db_part}{suffix}") } @@ -777,7 +781,11 @@ impl ConnectionConfig { format!("{scheme}://{username}:{password}@{host}:{port}/{fragment}") } } - DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::Databend => { + DatabaseType::Mysql + | DatabaseType::Doris + | DatabaseType::StarRocks + | DatabaseType::ManticoreSearch + | DatabaseType::Databend => { let suffix = if params.is_empty() { String::new() } else { format!("?{params}") }; format!("mysql://{}:{}@{host}:{port}{db_part}{suffix}", username, password) } @@ -958,7 +966,7 @@ impl ConnectionConfig { DatabaseType::Mysql => { normalize_mysql_url_params(value, self.mysql_uses_tls(), self.ca_cert_path.trim().is_empty()) } - DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::Databend => { + DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch | DatabaseType::Databend => { normalize_bare_mysql_url_params(value) } DatabaseType::Postgres | DatabaseType::Redshift => normalize_postgres_url_params(value, self.ssl), diff --git a/crates/dbx-core/src/schema.rs b/crates/dbx-core/src/schema.rs index c3ccf67446..ca6b99e25d 100644 --- a/crates/dbx-core/src/schema.rs +++ b/crates/dbx-core/src/schema.rs @@ -319,7 +319,9 @@ async fn list_databases_once(state: &AppState, connection_id: &str) -> Result { - db::mysql::list_databases_show(p).await + db::mysql::list_databases_show(p) + .await + .map(|databases| filter_mysql_system_databases_for_config(databases, db_config.as_ref())) } PoolKind::Mysql(p, mode) => dispatch_mysql!(p, mode, db::mysql::list_databases, db::ob_oracle::list_databases), PoolKind::Postgres(p) => db::postgres::list_databases(p).await, @@ -599,8 +601,8 @@ fn filter_table_infos( #[cfg(test)] mod tests { use super::{ - clickhouse_metadata_database, deduplicate_column_infos, filter_table_infos, - is_agent_postgres_metadata_fallback_config, + clickhouse_metadata_database, deduplicate_column_infos, filter_mysql_system_databases_for_config, + filter_table_infos, is_agent_postgres_metadata_fallback_config, }; #[cfg(feature = "duckdb-bundled")] use super::{duckdb_attach_database, duckdb_list_databases, duckdb_query_tables_in_database}; @@ -675,6 +677,39 @@ mod tests { } } + fn test_database_info(name: &str) -> super::db::DatabaseInfo { + super::db::DatabaseInfo { name: name.to_string() } + } + + #[test] + fn manticoresearch_database_list_filters_mysql_system_databases() { + let databases = vec![ + test_database_info("Manticore"), + test_database_info("information_schema"), + test_database_info("mysql"), + test_database_info("performance_schema"), + test_database_info("sys"), + ]; + let config = test_connection_config(DatabaseType::ManticoreSearch); + + let filtered = filter_mysql_system_databases_for_config(databases, Some(&config)); + + assert_eq!(filtered.into_iter().map(|database| database.name).collect::>(), vec!["Manticore"]); + } + + #[test] + fn doris_database_list_keeps_system_databases() { + let databases = vec![test_database_info("information_schema"), test_database_info("analytics")]; + let config = test_connection_config(DatabaseType::Doris); + + let filtered = filter_mysql_system_databases_for_config(databases, Some(&config)); + + assert_eq!( + filtered.into_iter().map(|database| database.name).collect::>(), + vec!["information_schema", "analytics"] + ); + } + #[test] fn filter_table_infos_applies_filter_offset_and_limit() { let tables = vec![ @@ -1469,8 +1504,28 @@ fn is_opengauss_family_config(config: &ConnectionConfig) -> bool { } fn is_doris_family_config(config: &ConnectionConfig) -> bool { - matches!(config.db_type, DatabaseType::Doris | DatabaseType::StarRocks) - || matches!(config.driver_profile.as_deref(), Some("doris" | "selectdb" | "starrocks")) + matches!(config.db_type, DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch) + || matches!(config.driver_profile.as_deref(), Some("doris" | "selectdb" | "starrocks" | "manticoresearch")) +} + +fn is_manticoresearch_config(config: &ConnectionConfig) -> bool { + matches!(config.db_type, DatabaseType::ManticoreSearch) + || matches!(config.driver_profile.as_deref(), Some("manticoresearch")) +} + +fn filter_mysql_system_databases_for_config( + databases: Vec, + config: Option<&ConnectionConfig>, +) -> Vec { + if !config.is_some_and(is_manticoresearch_config) { + return databases; + } + + databases.into_iter().filter(|database| !is_mysql_system_database(&database.name)).collect() +} + +fn is_mysql_system_database(name: &str) -> bool { + matches!(name.to_ascii_lowercase().as_str(), "information_schema" | "mysql" | "performance_schema" | "sys") } fn sql_string(value: &str) -> String { diff --git a/crates/dbx-core/src/schema/providers/native.rs b/crates/dbx-core/src/schema/providers/native.rs index 013e3a6fa9..1d62799d7d 100644 --- a/crates/dbx-core/src/schema/providers/native.rs +++ b/crates/dbx-core/src/schema/providers/native.rs @@ -7,7 +7,9 @@ pub(in crate::schema) async fn list_databases( config: Option<&ConnectionConfig>, ) -> Result, String> { match pool { - PoolKind::Mysql(p, _) if config.is_some_and(is_doris_family_config) => db::mysql::list_databases_show(p).await, + PoolKind::Mysql(p, _) if config.is_some_and(is_doris_family_config) => db::mysql::list_databases_show(p) + .await + .map(|databases| filter_mysql_system_databases_for_config(databases, config)), PoolKind::Mysql(p, mode) if *mode == MysqlMode::OceanBaseOracle => db::ob_oracle::list_databases(p).await, PoolKind::Mysql(p, _) => db::mysql::list_databases(p).await, PoolKind::Postgres(p) => db::postgres::list_databases(p).await, @@ -262,6 +264,26 @@ fn is_opengauss_family_config(config: &ConnectionConfig) -> bool { } fn is_doris_family_config(config: &ConnectionConfig) -> bool { - matches!(config.db_type, DatabaseType::Doris | DatabaseType::StarRocks) - || matches!(config.driver_profile.as_deref(), Some("doris" | "selectdb" | "starrocks")) + matches!(config.db_type, DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch) + || matches!(config.driver_profile.as_deref(), Some("doris" | "selectdb" | "starrocks" | "manticoresearch")) +} + +fn is_manticoresearch_config(config: &ConnectionConfig) -> bool { + matches!(config.db_type, DatabaseType::ManticoreSearch) + || matches!(config.driver_profile.as_deref(), Some("manticoresearch")) +} + +fn filter_mysql_system_databases_for_config( + databases: Vec, + config: Option<&ConnectionConfig>, +) -> Vec { + if !config.is_some_and(is_manticoresearch_config) { + return databases; + } + + databases.into_iter().filter(|database| !is_mysql_system_database(&database.name)).collect() +} + +fn is_mysql_system_database(name: &str) -> bool { + matches!(name.to_ascii_lowercase().as_str(), "information_schema" | "mysql" | "performance_schema" | "sys") } diff --git a/crates/dbx-core/src/sql.rs b/crates/dbx-core/src/sql.rs index 4d5dcfcead..62753ac9e2 100644 --- a/crates/dbx-core/src/sql.rs +++ b/crates/dbx-core/src/sql.rs @@ -64,7 +64,11 @@ impl SqlParsingOptions { Self { supports_hash_line_comments: matches!( db_type, - DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::Goldendb + DatabaseType::Mysql + | DatabaseType::Doris + | DatabaseType::StarRocks + | DatabaseType::ManticoreSearch + | DatabaseType::Goldendb ), supports_oracle_plsql_blocks: matches!( db_type, @@ -1203,13 +1207,27 @@ fn executable_sql_keyword_matches(token: &str, keyword: &str) -> bool { } fn is_mysql_compatible_import_target(db_type: &DatabaseType, driver_profile: Option<&str>) -> bool { - matches!(db_type, DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::Goldendb) - || driver_profile.map(|profile| profile.to_ascii_lowercase()).is_some_and(|profile| { - matches!( - profile.as_str(), - "mariadb" | "tidb" | "oceanbase" | "custom_mysql" | "doris" | "starrocks" | "selectdb" | "goldendb" - ) - }) + matches!( + db_type, + DatabaseType::Mysql + | DatabaseType::Doris + | DatabaseType::StarRocks + | DatabaseType::ManticoreSearch + | DatabaseType::Goldendb + ) || driver_profile.map(|profile| profile.to_ascii_lowercase()).is_some_and(|profile| { + matches!( + profile.as_str(), + "mariadb" + | "tidb" + | "oceanbase" + | "custom_mysql" + | "doris" + | "starrocks" + | "manticoresearch" + | "selectdb" + | "goldendb" + ) + }) } fn mysql_executable_comment_body(statement: &str) -> Option<&str> { diff --git a/crates/dbx-core/src/sql_analysis.rs b/crates/dbx-core/src/sql_analysis.rs index 642b04fcb7..15e35b0304 100644 --- a/crates/dbx-core/src/sql_analysis.rs +++ b/crates/dbx-core/src/sql_analysis.rs @@ -91,7 +91,7 @@ fn starts_with_duckdb_parser_gap_sql(sql: &str) -> bool { fn normalize_dialect(dialect: Option<&str>) -> String { match dialect.unwrap_or("generic").to_ascii_lowercase().as_str() { "postgres" | "postgresql" | "redshift" | "opengauss" | "gaussdb" | "highgo" => "postgres".to_string(), - "mysql" | "mariadb" | "doris" | "starrocks" | "oceanbase" => "mysql".to_string(), + "mysql" | "mariadb" | "doris" | "starrocks" | "manticoresearch" | "oceanbase" => "mysql".to_string(), "sqlite" => "sqlite".to_string(), "sqlserver" | "mssql" => "sqlserver".to_string(), "clickhouse" => "clickhouse".to_string(), diff --git a/crates/dbx-core/src/sql_dialect/identifiers.rs b/crates/dbx-core/src/sql_dialect/identifiers.rs index 5d4a119713..f1ffb61feb 100644 --- a/crates/dbx-core/src/sql_dialect/identifiers.rs +++ b/crates/dbx-core/src/sql_dialect/identifiers.rs @@ -36,6 +36,7 @@ pub fn quote_table_identifier(database_type: Option, name: &str) - DatabaseType::Mysql | DatabaseType::Goldendb | DatabaseType::StarRocks + | DatabaseType::ManticoreSearch | DatabaseType::Hive | DatabaseType::Databend | DatabaseType::Tdengine diff --git a/crates/dbx-core/src/sql_risk.rs b/crates/dbx-core/src/sql_risk.rs index c4339374fb..9b330b010d 100644 --- a/crates/dbx-core/src/sql_risk.rs +++ b/crates/dbx-core/src/sql_risk.rs @@ -34,7 +34,7 @@ impl std::fmt::Display for SqlRisk { fn normalize_dialect(dialect: &str) -> &'static str { match dialect.to_ascii_lowercase().as_str() { "postgres" | "postgresql" | "redshift" | "opengauss" | "gaussdb" | "highgo" => "postgres", - "mysql" | "mariadb" | "doris" | "starrocks" | "oceanbase" => "mysql", + "mysql" | "mariadb" | "doris" | "starrocks" | "manticoresearch" | "oceanbase" => "mysql", "sqlite" => "sqlite", "sqlserver" | "mssql" => "sqlserver", "clickhouse" => "clickhouse", diff --git a/docs/app/[lang]/databases/page.tsx b/docs/app/[lang]/databases/page.tsx index b1f18cbf56..fc3d4900a0 100644 --- a/docs/app/[lang]/databases/page.tsx +++ b/docs/app/[lang]/databases/page.tsx @@ -19,6 +19,7 @@ const databaseSupport = [ { name: "Elasticsearch", icon: "/icons/database/elasticsearch.svg", tone: "#00bfb3" }, { name: "Doris", icon: "/icons/database/doris.svg", tone: "#5b7cfa" }, { name: "StarRocks", icon: "/icons/database/starrocks.svg", tone: "#6750ff" }, + { name: "Manticore Search", icon: "/icons/database/manticoresearch.png", tone: "#b8e646" }, { name: "Redshift", icon: "/icons/database/redshift.svg", tone: "#8c4fff" }, { name: "Dameng", icon: "/icons/database/dm.svg", tone: "#3857ff" }, { name: "GaussDB", icon: "/icons/database/gaussdb.svg", tone: "#ff5a3d" }, diff --git a/docs/app/[lang]/page.tsx b/docs/app/[lang]/page.tsx index 125df2c2bb..cf013304ae 100644 --- a/docs/app/[lang]/page.tsx +++ b/docs/app/[lang]/page.tsx @@ -71,6 +71,7 @@ const databaseSupport = [ { name: "Elasticsearch", icon: "/icons/database/elasticsearch.svg", tone: "#00bfb3" }, { name: "Doris", icon: "/icons/database/doris.svg", tone: "#5b7cfa" }, { name: "StarRocks", icon: "/icons/database/starrocks.svg", tone: "#6750ff" }, + { name: "Manticore Search", icon: "/icons/database/manticoresearch.png", tone: "#b8e646" }, { name: "Redshift", icon: "/icons/database/redshift.svg", tone: "#8c4fff" }, { name: "Dameng", icon: "/icons/database/dm.svg", tone: "#3857ff" }, { name: "GaussDB", icon: "/icons/database/gaussdb.svg", tone: "#ff5a3d" }, diff --git a/docs/content/docs/databases.cn.mdx b/docs/content/docs/databases.cn.mdx index 4c30de7762..8ec1855eeb 100644 --- a/docs/content/docs/databases.cn.mdx +++ b/docs/content/docs/databases.cn.mdx @@ -13,7 +13,7 @@ description: 了解 DBX 可以连接哪些数据库,以及每类高级功能 | ------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | 核心 SQL 数据库 | MySQL、PostgreSQL、SQLite、DuckDB、ClickHouse、SQL Server、Oracle、Redshift、DM、GaussDB、KWDB、Teradata、Vertica、Exasol、Firebird、SAP HANA、崖山 YashanDB、GBase | 直接出现在 DBX 连接选择器中 | | 文档与键值数据库 | Redis、MongoDB、Elasticsearch、etcd | 根据数据模型使用专门浏览器或查询流程,不完全等同于关系型表格 | -| MySQL 兼容类型 | MariaDB、TiDB、OceanBase、Doris、SelectDB、StarRocks、GoldenDB、TDSQL、PolarDB、GreatSQL、自定义 MySQL | 复用 MySQL 风格连接能力 | +| MySQL 兼容类型 | MariaDB、TiDB、OceanBase、Doris、SelectDB、StarRocks、Manticore Search、GoldenDB、TDSQL、PolarDB、GreatSQL、自定义 MySQL | 复用 MySQL 风格连接能力 | | PostgreSQL 兼容类型 | openGauss、KingBase、HighGo、Vastbase、CockroachDB、自定义 PostgreSQL | 复用 PostgreSQL 风格连接能力 | | 文件型数据库 | SQLite、DuckDB、Microsoft Access、RQLite、Turso | 选择本地数据库文件或 HTTP 端点,不填写主机和端口 | | 时序与边缘数据库 | InfluxDB、IoTDB、TDengine、Databend | 面向时序、IoT 或边缘场景优化 | @@ -34,6 +34,7 @@ description: 了解 DBX 可以连接哪些数据库,以及每类高级功能 | TiDB | 4000 | | OceanBase | 2881 | | Doris / SelectDB / StarRocks / Databend | 9030 | +| Manticore Search | 9306 | | Redshift | 5439 | | CockroachDB | 26257 | | DM | 5236 | diff --git a/docs/content/docs/databases.mdx b/docs/content/docs/databases.mdx index 6d03237607..f68cbf0cff 100644 --- a/docs/content/docs/databases.mdx +++ b/docs/content/docs/databases.mdx @@ -13,7 +13,7 @@ The connection dialog exposes ready-to-use profiles with default ports and drive | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | | Core SQL engines | MySQL, PostgreSQL, SQLite, DuckDB, ClickHouse, SQL Server, Oracle, Redshift, DM, GaussDB, KWDB, Teradata, Vertica, Exasol, Firebird, SAP HANA, YashanDB, GBase | Available directly in the DBX connection picker | | Document and key-value engines | Redis, MongoDB, Elasticsearch, etcd | Use dedicated browsers or query flows instead of the generic relational grid where appropriate | -| MySQL-compatible profiles | MariaDB, TiDB, OceanBase, Doris, SelectDB, StarRocks, GoldenDB, TDSQL, PolarDB, GreatSQL, custom MySQL | Reuse MySQL-style connection handling where the engine speaks a compatible protocol | +| MySQL-compatible profiles | MariaDB, TiDB, OceanBase, Doris, SelectDB, StarRocks, Manticore Search, GoldenDB, TDSQL, PolarDB, GreatSQL, custom MySQL | Reuse MySQL-style connection handling where the engine speaks a compatible protocol | | PostgreSQL-compatible profiles | openGauss, KingBase, HighGo, Vastbase, CockroachDB, custom PostgreSQL | Reuse PostgreSQL-style connection handling where the engine speaks a compatible protocol | | File-based engines | SQLite, DuckDB, Microsoft Access, RQLite, Turso | Choose a local database file or HTTP endpoint instead of host and port | | Time-series and edge | InfluxDB, IoTDB, TDengine, Databend | Optimized for time-series, IoT, or edge workloads | @@ -34,6 +34,7 @@ The connection dialog exposes ready-to-use profiles with default ports and drive | TiDB | 4000 | | OceanBase | 2881 | | Doris / SelectDB / StarRocks / Databend | 9030 | +| Manticore Search | 9306 | | Redshift | 5439 | | CockroachDB | 26257 | | DM | 5236 | diff --git a/docs/public/icons/database/manticoresearch.png b/docs/public/icons/database/manticoresearch.png new file mode 100644 index 0000000000..420cb72a59 Binary files /dev/null and b/docs/public/icons/database/manticoresearch.png differ diff --git a/packages/app-tests/connectionUrlPlaceholder.test.ts b/packages/app-tests/connectionUrlPlaceholder.test.ts index 45516eaa0d..24b8b8f102 100644 --- a/packages/app-tests/connectionUrlPlaceholder.test.ts +++ b/packages/app-tests/connectionUrlPlaceholder.test.ts @@ -6,6 +6,7 @@ const expected: Record = { mysql: "mysql://user:password@host:port/database", doris: "mysql://user:password@host:port/database", starrocks: "mysql://user:password@host:port/database", + manticoresearch: "mysql://user:password@host:port/database", postgres: "postgresql://user:password@host:port/database", gaussdb: "postgresql://user:password@host:port/database", kwdb: "postgresql://user:password@host:port/database", @@ -42,6 +43,7 @@ test("mysql-family types share the same placeholder", () => { const mysql = connectionUrlPlaceholder("mysql"); assert.equal(connectionUrlPlaceholder("doris"), mysql); assert.equal(connectionUrlPlaceholder("starrocks"), mysql); + assert.equal(connectionUrlPlaceholder("manticoresearch"), mysql); }); test("postgres-family types share the same placeholder", () => { diff --git a/packages/app-tests/databaseCapabilities.test.ts b/packages/app-tests/databaseCapabilities.test.ts index d276b6304d..9b6f71612f 100644 --- a/packages/app-tests/databaseCapabilities.test.ts +++ b/packages/app-tests/databaseCapabilities.test.ts @@ -225,7 +225,9 @@ test("describes feature support through capability helpers", () => { assert.equal(supportsTableStructureEditing("clickhouse"), true); assert.equal(supportsTableStructureEditing("rqlite"), true); assert.equal(supportsTableStructureEditing("mongodb"), false); + assert.equal(supportsTableStructureEditing("manticoresearch"), false); assert.equal(supportsDatabaseCreation("clickhouse"), true); + assert.equal(supportsDatabaseCreation("manticoresearch"), false); assert.equal(supportsDatabaseCreation("sqlite"), false); assert.equal(supportsFieldLineage("gaussdb"), true); assert.equal(supportsFieldLineage("kwdb"), true); @@ -233,15 +235,19 @@ test("describes feature support through capability helpers", () => { assert.equal(supportsTransfer("duckdb"), true); assert.equal(supportsTransfer("hive"), true); assert.equal(supportsTransfer("mongodb"), true); + assert.equal(supportsTransfer("manticoresearch"), false); assert.equal(supportsDriverManagement("oracle"), true); assert.equal(supportsDriverManagement("mysql"), false); + assert.equal(supportsDriverManagement("manticoresearch"), false); assert.equal(supportsDriverManagement("kwdb"), false); assert.equal(usesPostgresLikeStructureCopy("gaussdb"), true); assert.equal(usesPostgresLikeStructureCopy("kwdb"), true); assert.equal(usesPostgresLikeStructureCopy("mysql"), false); assert.equal(supportsObjectBrowser("mysql"), true); + assert.equal(supportsObjectBrowser("manticoresearch"), false); assert.equal(supportsObjectBrowser("mongodb"), false); assert.equal(supportsTableTruncate("mysql"), true); + assert.equal(supportsTableTruncate("manticoresearch"), false); assert.equal(supportsTableTruncate("duckdb"), false); assert.equal(supportsTableTruncate("rqlite"), false); }); @@ -249,6 +255,7 @@ test("describes feature support through capability helpers", () => { test("loads product support levels and capabilities from the driver manifest", () => { assert.equal(manifestDatabaseTypes().includes("mysql"), true); assert.equal(databaseSupportLevel("mysql"), "operate"); + assert.equal(databaseSupportLevel("manticoresearch"), "browse"); assert.equal(databaseSupportLevel("jdbc"), "browse"); assert.equal(databaseSupportLevel("redis"), "connect"); @@ -266,6 +273,27 @@ test("loads product support levels and capabilities from the driver manifest", ( userAdmin: false, }, ); + + assert.deepEqual( + { + queryExecution: databaseProductCapabilities("manticoresearch").queryExecution, + metadataBrowse: databaseProductCapabilities("manticoresearch").metadataBrowse, + objectBrowser: databaseProductCapabilities("manticoresearch").objectBrowser, + tableDataEdit: databaseProductCapabilities("manticoresearch").tableDataEdit, + tableStructureEdit: databaseProductCapabilities("manticoresearch").tableStructureEdit, + sqlFileExecution: databaseProductCapabilities("manticoresearch").sqlFileExecution, + userAdmin: databaseProductCapabilities("manticoresearch").userAdmin, + }, + { + queryExecution: true, + metadataBrowse: true, + objectBrowser: false, + tableDataEdit: false, + tableStructureEdit: false, + sqlFileExecution: true, + userAdmin: false, + }, + ); }); test("object browser entry follows database tree shape", () => { diff --git a/packages/app-tests/tableStructureCapabilities.test.ts b/packages/app-tests/tableStructureCapabilities.test.ts index fa70c2af70..275abf7825 100644 --- a/packages/app-tests/tableStructureCapabilities.test.ts +++ b/packages/app-tests/tableStructureCapabilities.test.ts @@ -94,7 +94,7 @@ test("limited analytic engines can open the editor for supported operations only }); test("unsupported non-relational databases do not open the structure editor", () => { - for (const dbType of ["redis", "mongodb", "elasticsearch", "neo4j", undefined] as const) { + for (const dbType of ["redis", "mongodb", "elasticsearch", "manticoresearch", "neo4j", undefined] as const) { const caps = getTableStructureCapabilities(dbType); assert.equal(caps.dialect, "unsupported"); assert.equal(canEditTableStructure(dbType), false); diff --git a/packages/app-tests/visibleDatabases.test.ts b/packages/app-tests/visibleDatabases.test.ts index 8f07d9ebdd..4b25f99dda 100644 --- a/packages/app-tests/visibleDatabases.test.ts +++ b/packages/app-tests/visibleDatabases.test.ts @@ -29,8 +29,10 @@ test("normalizes selected database names against fresh database names", () => { test("mysql system databases are hidden by default but can be explicitly selected", () => { const databases = ["app", "information_schema", "mysql", "performance_schema", "sys"]; assert.deepEqual(filterDatabaseNamesForConnection(databases, { db_type: "mysql" }), ["app"]); + assert.deepEqual(filterDatabaseNamesForConnection(databases, { db_type: "manticoresearch" }), ["app"]); assert.deepEqual(filterDatabaseNamesForConnection(databases, { db_type: "mysql", visible_databases: ["app", "sys"] }), ["app", "sys"]); assert.equal(isSystemDatabaseName("mysql", "performance_schema"), true); + assert.equal(isSystemDatabaseName("manticoresearch", "information_schema"), true); assert.equal(isSystemDatabaseName("postgres", "information_schema"), false); }); diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index fffe58f990..e51ed0d4ba 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -46,7 +46,7 @@ function formatQueryToolResult(result: QueryResult, title?: string) { } export const DBX_CONNECTION_TYPE_DESCRIPTION = - "Database type: postgres, mysql, sqlite, rqlite, redis, duckdb, clickhouse, sqlserver, mongodb, oracle, elasticsearch, etcd, doris, starrocks, redshift, dameng, kingbase, highgo, vastbase, goldendb, databend, gaussdb, kwdb, yashandb, databricks, saphana, teradata, vertica, firebird, exasol, opengauss, oceanbase-oracle, gbase, h2, snowflake, trino, hive, db2, informix, influxdb, iris, neo4j, cassandra, bigquery, kylin, sundb, tdengine, iotdb, xugu, jdbc, access"; + "Database type: postgres, mysql, sqlite, rqlite, redis, duckdb, clickhouse, sqlserver, mongodb, oracle, elasticsearch, etcd, doris, starrocks, manticoresearch, redshift, dameng, kingbase, highgo, vastbase, goldendb, databend, gaussdb, kwdb, yashandb, databricks, saphana, teradata, vertica, firebird, exasol, opengauss, oceanbase-oracle, gbase, h2, snowflake, trino, hive, db2, informix, influxdb, iris, neo4j, cassandra, bigquery, kylin, sundb, tdengine, iotdb, xugu, jdbc, access"; const FILE_CAPABLE_CONNECTION_TYPES = new Set(["sqlite", "duckdb", "access", "h2"]); export function createDbxMcpServer(backend: Backend, options: { isWebMode?: boolean } = {}): McpServer { diff --git a/packages/node-core/src/database.ts b/packages/node-core/src/database.ts index 2d6b2491a9..d4859cedf8 100644 --- a/packages/node-core/src/database.ts +++ b/packages/node-core/src/database.ts @@ -284,7 +284,7 @@ function portBytes(port: number): Buffer { } function isMysqlType(dbType: string): boolean { - return dbType === "mysql" || dbType === "doris" || dbType === "starrocks"; + return dbType === "mysql" || dbType === "doris" || dbType === "starrocks" || dbType === "manticoresearch"; } interface BridgeQueryResult { diff --git a/packages/node-core/src/diagnostics.ts b/packages/node-core/src/diagnostics.ts index a8f7dff796..859cfa7e7d 100644 --- a/packages/node-core/src/diagnostics.ts +++ b/packages/node-core/src/diagnostics.ts @@ -2,7 +2,7 @@ import { access, readFile } from "node:fs/promises"; import { bridgePortFilePath, dbPath, appDataDir } from "./paths.js"; import { inspectConnectionStore } from "./connections.js"; -export const DIRECT_QUERY_TYPES = ["postgres", "redshift", "mysql", "doris", "starrocks", "sqlite", "rqlite", "gaussdb", "kwdb", "opengauss"] as const; +export const DIRECT_QUERY_TYPES = ["postgres", "redshift", "mysql", "doris", "starrocks", "manticoresearch", "sqlite", "rqlite", "gaussdb", "kwdb", "opengauss"] as const; export type DirectQueryType = (typeof DIRECT_QUERY_TYPES)[number]; diff --git a/packages/node-core/tests/driver-manifest.test.ts b/packages/node-core/tests/driver-manifest.test.ts index 6ab514223c..c76a3d6cfb 100644 --- a/packages/node-core/tests/driver-manifest.test.ts +++ b/packages/node-core/tests/driver-manifest.test.ts @@ -57,6 +57,11 @@ test("runtime direct query routing matches diagnostic direct query types", () => } }); +test("Manticore Search is direct-query capable", () => { + assert.equal(isDirectQueryType("manticoresearch"), true); + assert.equal(DIRECT_QUERY_TYPES.includes("manticoresearch" as any), true); +}); + test("driver manifest declares support levels and product capabilities", () => { const manifest = loadManifest(); @@ -72,4 +77,14 @@ test("driver manifest declares support levels and product capabilities", () => { assert.equal(jdbc?.supportLevel, "browse"); assert.equal(jdbc?.capabilities.metadataBrowse, true); assert.equal(jdbc?.capabilities.tableStructureEdit, false); + + const manticore = manifest.drivers.find((driver) => driver.dbType === "manticoresearch"); + assert.equal(manticore?.supportLevel, "browse"); + assert.equal(manticore?.capabilities.queryExecution, true); + assert.equal(manticore?.capabilities.metadataBrowse, true); + assert.equal(manticore?.capabilities.objectBrowser, false); + assert.equal(manticore?.capabilities.tableDataEdit, false); + assert.equal(manticore?.capabilities.tableStructureEdit, false); + assert.equal(manticore?.capabilities.databaseCreate, false); + assert.equal(manticore?.capabilities.userAdmin, false); }); diff --git a/src-tauri/src/commands/connection.rs b/src-tauri/src/commands/connection.rs index f0e2993c8c..e1b821a0c6 100644 --- a/src-tauri/src/commands/connection.rs +++ b/src-tauri/src/commands/connection.rs @@ -273,7 +273,7 @@ pub async fn test_connection(state: State<'_, Arc>, config: Connection Err(e) => Err(e), } } - DatabaseType::Doris | DatabaseType::StarRocks => { + DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch => { match db::mysql::connect_bare(&url, connect_timeout).await { Ok(pool) => { let _ = pool.disconnect().await; @@ -488,7 +488,7 @@ pub async fn connect_db(state: State<'_, Arc>, config: ConnectionConfi connect_mysql_metadata_pool(&config, &db_config, &host, port, connect_timeout, 3).await?; PoolKind::Mysql(pool, mode) } - DatabaseType::Doris | DatabaseType::StarRocks => PoolKind::Mysql( + DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch => PoolKind::Mysql( connect_bare_metadata_pool(&db_config, &host, port, connect_timeout, 3).await?, MysqlMode::Bare, ),