From 0827478078c810a74d91526d5967445d7045e29f Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Sun, 23 Aug 2026 16:38:06 +0800 Subject: [PATCH] feat(connection): centralize connection type registration --- .../connection/ConnectionDialog.vue | 503 +----------- .../connection/h2ConnectionDialog.spec.ts | 8 +- .../spannerConnectionDialog.spec.ts | 13 +- .../database/connectionProfiles.spec.ts | 29 + .../database/databaseDriverManifest.spec.ts | 21 +- .../src/lib/connection/connectionFile.ts | 3 +- .../lib/connection/connectionPresentation.ts | 12 +- .../__tests__/transferObjectKinds.spec.ts | 2 +- .../lib/database/databaseCapabilitySets.ts | 102 +-- .../lib/database/databaseDriverManifest.ts | 64 +- apps/desktop/src/types/database.ts | 81 +- .../src/types/generated/connectionProfiles.ts | 323 ++++++++ .../src/types/generated/databaseTypes.ts | 83 ++ apps/desktop/vite.config.ts | 3 +- apps/desktop/vite.docs-export.config.ts | 8 +- apps/desktop/viteConnectionTypesPlugin.ts | 43 ++ crates/dbx-core/Cargo.toml | 5 + .../assets/database-drivers.manifest.json | 584 +++++++++++++- crates/dbx-core/build.rs | 112 ++- crates/dbx-core/src/agent_catalog.rs | 453 ++--------- crates/dbx-core/src/database_capabilities.rs | 76 +- crates/dbx-core/src/database_manifest.rs | 145 ++++ crates/dbx-core/src/lib.rs | 1 + crates/dbx-core/src/models/connection.rs | 121 +-- crates/dbx-core/src/sql_dialect/descriptor.rs | 36 +- .../src/sql_dialect/dialect_loader.rs | 7 +- .../dbx-core/tests/database_capabilities.rs | 10 +- crates/dbx-mcp/src/server.rs | 21 +- package.json | 7 +- .../app-tests/databaseCategoryOptions.test.ts | 18 +- plugins/README.md | 5 +- plugins/connection-types/README.md | 29 + plugins/connection-types/access.yaml | 35 + plugins/connection-types/bigquery.yaml | 31 + plugins/connection-types/cassandra.yaml | 32 + plugins/connection-types/chromadb.yaml | 29 + plugins/connection-types/clickhouse.yaml | 30 + plugins/connection-types/cloudflare-d1.yaml | 32 + plugins/connection-types/consul.yaml | 30 + plugins/connection-types/dameng.yaml | 39 + plugins/connection-types/databend.yaml | 35 + plugins/connection-types/databricks.yaml | 35 + plugins/connection-types/db2.yaml | 35 + plugins/connection-types/doris.yaml | 30 + plugins/connection-types/duckdb.yaml | 38 + plugins/connection-types/dynamodb.yaml | 29 + plugins/connection-types/easysearch.yaml | 29 + plugins/connection-types/elasticsearch.yaml | 29 + plugins/connection-types/etcd.yaml | 32 + plugins/connection-types/exasol.yaml | 36 + plugins/connection-types/firebird.yaml | 35 + plugins/connection-types/gaussdb.yaml | 37 + plugins/connection-types/gbase.yaml | 47 ++ plugins/connection-types/goldendb.yaml | 33 + plugins/connection-types/h2.yaml | 59 ++ plugins/connection-types/hbase.yaml | 29 + plugins/connection-types/highgo.yaml | 37 + plugins/connection-types/hive.yaml | 34 + plugins/connection-types/ignite.yaml | 35 + plugins/connection-types/ignite3.yaml | 35 + plugins/connection-types/impala.yaml | 33 + plugins/connection-types/influxdb.yaml | 31 + plugins/connection-types/informix.yaml | 36 + plugins/connection-types/iotdb.yaml | 34 + plugins/connection-types/iris.yaml | 36 + plugins/connection-types/jdbc.yaml | 33 + plugins/connection-types/kingbase.yaml | 37 + plugins/connection-types/kwdb.yaml | 36 + plugins/connection-types/kylin.yaml | 32 + plugins/connection-types/kyuubi.yaml | 33 + plugins/connection-types/manticoresearch.yaml | 30 + plugins/connection-types/meilisearch.yaml | 29 + plugins/connection-types/milvus.yaml | 29 + plugins/connection-types/mongodb.yaml | 37 + plugins/connection-types/mq.yaml | 46 ++ plugins/connection-types/mqtt.yaml | 31 + plugins/connection-types/mysql.yaml | 32 + plugins/connection-types/nacos.yaml | 31 + plugins/connection-types/neo4j.yaml | 32 + .../connection-types/oceanbase-oracle.yaml | 39 + plugins/connection-types/opengauss.yaml | 36 + plugins/connection-types/oracle.yaml | 48 ++ plugins/connection-types/oscar.yaml | 35 + plugins/connection-types/postgres.yaml | 36 + plugins/connection-types/prestosql.yaml | 33 + .../connection-types/profiles/catalog.yaml | 727 ++++++++++++++++++ plugins/connection-types/qdrant.yaml | 29 + plugins/connection-types/questdb.yaml | 34 + plugins/connection-types/redis.yaml | 29 + plugins/connection-types/redshift.yaml | 35 + plugins/connection-types/rqlite.yaml | 32 + plugins/connection-types/saphana.yaml | 35 + plugins/connection-types/snowflake.yaml | 34 + plugins/connection-types/spanner.yaml | 35 + plugins/connection-types/spark.yaml | 34 + plugins/connection-types/sqlite.yaml | 32 + plugins/connection-types/sqlserver.yaml | 41 + plugins/connection-types/starrocks.yaml | 30 + plugins/connection-types/sundb.yaml | 33 + plugins/connection-types/tdengine.yaml | 32 + plugins/connection-types/teradata.yaml | 35 + plugins/connection-types/trino.yaml | 36 + plugins/connection-types/turso.yaml | 32 + plugins/connection-types/uxdb.yaml | 37 + plugins/connection-types/vastbase.yaml | 37 + plugins/connection-types/vertica.yaml | 36 + plugins/connection-types/victoriametrics.yaml | 31 + plugins/connection-types/weaviate.yaml | 29 + plugins/connection-types/xugu.yaml | 36 + plugins/connection-types/yashandb.yaml | 36 + plugins/connection-types/zookeeper.yaml | 32 + pnpm-lock.yaml | 3 + scripts/run-check.mjs | 5 + scripts/sync-connection-types.mjs | 289 +++++++ 114 files changed, 5284 insertions(+), 1342 deletions(-) create mode 100644 apps/desktop/src/lib/__tests__/database/connectionProfiles.spec.ts create mode 100644 apps/desktop/src/types/generated/connectionProfiles.ts create mode 100644 apps/desktop/src/types/generated/databaseTypes.ts create mode 100644 apps/desktop/viteConnectionTypesPlugin.ts create mode 100644 crates/dbx-core/src/database_manifest.rs create mode 100644 plugins/connection-types/README.md create mode 100644 plugins/connection-types/access.yaml create mode 100644 plugins/connection-types/bigquery.yaml create mode 100644 plugins/connection-types/cassandra.yaml create mode 100644 plugins/connection-types/chromadb.yaml create mode 100644 plugins/connection-types/clickhouse.yaml create mode 100644 plugins/connection-types/cloudflare-d1.yaml create mode 100644 plugins/connection-types/consul.yaml create mode 100644 plugins/connection-types/dameng.yaml create mode 100644 plugins/connection-types/databend.yaml create mode 100644 plugins/connection-types/databricks.yaml create mode 100644 plugins/connection-types/db2.yaml create mode 100644 plugins/connection-types/doris.yaml create mode 100644 plugins/connection-types/duckdb.yaml create mode 100644 plugins/connection-types/dynamodb.yaml create mode 100644 plugins/connection-types/easysearch.yaml create mode 100644 plugins/connection-types/elasticsearch.yaml create mode 100644 plugins/connection-types/etcd.yaml create mode 100644 plugins/connection-types/exasol.yaml create mode 100644 plugins/connection-types/firebird.yaml create mode 100644 plugins/connection-types/gaussdb.yaml create mode 100644 plugins/connection-types/gbase.yaml create mode 100644 plugins/connection-types/goldendb.yaml create mode 100644 plugins/connection-types/h2.yaml create mode 100644 plugins/connection-types/hbase.yaml create mode 100644 plugins/connection-types/highgo.yaml create mode 100644 plugins/connection-types/hive.yaml create mode 100644 plugins/connection-types/ignite.yaml create mode 100644 plugins/connection-types/ignite3.yaml create mode 100644 plugins/connection-types/impala.yaml create mode 100644 plugins/connection-types/influxdb.yaml create mode 100644 plugins/connection-types/informix.yaml create mode 100644 plugins/connection-types/iotdb.yaml create mode 100644 plugins/connection-types/iris.yaml create mode 100644 plugins/connection-types/jdbc.yaml create mode 100644 plugins/connection-types/kingbase.yaml create mode 100644 plugins/connection-types/kwdb.yaml create mode 100644 plugins/connection-types/kylin.yaml create mode 100644 plugins/connection-types/kyuubi.yaml create mode 100644 plugins/connection-types/manticoresearch.yaml create mode 100644 plugins/connection-types/meilisearch.yaml create mode 100644 plugins/connection-types/milvus.yaml create mode 100644 plugins/connection-types/mongodb.yaml create mode 100644 plugins/connection-types/mq.yaml create mode 100644 plugins/connection-types/mqtt.yaml create mode 100644 plugins/connection-types/mysql.yaml create mode 100644 plugins/connection-types/nacos.yaml create mode 100644 plugins/connection-types/neo4j.yaml create mode 100644 plugins/connection-types/oceanbase-oracle.yaml create mode 100644 plugins/connection-types/opengauss.yaml create mode 100644 plugins/connection-types/oracle.yaml create mode 100644 plugins/connection-types/oscar.yaml create mode 100644 plugins/connection-types/postgres.yaml create mode 100644 plugins/connection-types/prestosql.yaml create mode 100644 plugins/connection-types/profiles/catalog.yaml create mode 100644 plugins/connection-types/qdrant.yaml create mode 100644 plugins/connection-types/questdb.yaml create mode 100644 plugins/connection-types/redis.yaml create mode 100644 plugins/connection-types/redshift.yaml create mode 100644 plugins/connection-types/rqlite.yaml create mode 100644 plugins/connection-types/saphana.yaml create mode 100644 plugins/connection-types/snowflake.yaml create mode 100644 plugins/connection-types/spanner.yaml create mode 100644 plugins/connection-types/spark.yaml create mode 100644 plugins/connection-types/sqlite.yaml create mode 100644 plugins/connection-types/sqlserver.yaml create mode 100644 plugins/connection-types/starrocks.yaml create mode 100644 plugins/connection-types/sundb.yaml create mode 100644 plugins/connection-types/tdengine.yaml create mode 100644 plugins/connection-types/teradata.yaml create mode 100644 plugins/connection-types/trino.yaml create mode 100644 plugins/connection-types/turso.yaml create mode 100644 plugins/connection-types/uxdb.yaml create mode 100644 plugins/connection-types/vastbase.yaml create mode 100644 plugins/connection-types/vertica.yaml create mode 100644 plugins/connection-types/victoriametrics.yaml create mode 100644 plugins/connection-types/weaviate.yaml create mode 100644 plugins/connection-types/xugu.yaml create mode 100644 plugins/connection-types/yashandb.yaml create mode 100644 plugins/connection-types/zookeeper.yaml create mode 100644 scripts/sync-connection-types.mjs diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue index 1fe799b7cd..a0eda63d6f 100644 --- a/apps/desktop/src/components/connection/ConnectionDialog.vue +++ b/apps/desktop/src/components/connection/ConnectionDialog.vue @@ -15,6 +15,7 @@ import { HelpTooltip, Tooltip, TooltipContent, TooltipTrigger } from "@/componen import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Switch } from "@/components/ui/switch"; import type { ConnectionConfig, ConnectionTestResult, DatabaseConnectionInfo, DatabaseType, HttpTunnelConfig, IdentifierCase, JdbcDriverInfo, JdbcLocalBundleInfo, JdbcMavenBundleInfo, ProxyTunnelConfig, SshConfigHostEntry, SshTunnelConfig, TransportLayerConfig } from "@/types/database"; +import { CONNECTION_PICKER_OPTIONS, CONNECTION_PROFILES, CONNECTION_PROFILE_ICONS, type ConnectionPickerOption, type ConnectionProfileCategory, type ConnectionProfileDefinition } from "@/types/generated/connectionProfiles"; import type { InfluxDbExternalConfig, InfluxDbVersion } from "@/types/influxdb"; import type { VictoriaMetricsExternalConfig } from "@/types/victoriametrics"; import type { MqAdminConfig, MqAuth, MqSystemKind } from "@/types/mq"; @@ -104,6 +105,7 @@ import { import { buildDraftVisibleDatabasesConnectionId, connectionCanChooseVisibleDatabases, initialVisibleDatabaseSelection, visibleObjectFiltersNeedReset } from "@/lib/connection/connectionVisibleDatabases"; import { canSaveVisibleDatabaseSelection, connectionUsesVisibleSchemaFilter, filterDatabaseNamesForVisiblePicker, filterSchemaNamesForVisiblePicker, normalizeVisibleDatabaseSelection, buildDraftVisibleSchemasConnectionId, normalizeVisibleSchemaSelection } from "@/lib/database/visibleDatabases"; import { isSchemaAware, isSingleDatabase } from "@/lib/database/databaseFeatureSupport"; +import { databaseConnectionFormKind } from "@/lib/database/databaseDriverManifest"; import VisibleSchemasDialog from "@/components/sidebar/VisibleSchemasDialog.vue"; import CloudflareD1ConnectionFields from "@/components/connection/CloudflareD1ConnectionFields.vue"; import SpannerConnectionFields from "@/components/connection/SpannerConnectionFields.vue"; @@ -161,8 +163,8 @@ import { jdbcProductProfileIdsForCategory, } from "@/lib/database/jdbcProductProfiles"; -type DbOption = { value: string; label: string }; -type DbCategoryKey = "sql" | "analytics" | "domestic" | "lightweight" | "document" | "graph_ai" | "timeseries" | "mq" | "registry_config"; +type DbOption = ConnectionPickerOption; +type DbCategoryKey = ConnectionProfileCategory; type DbCategory = { key: DbCategoryKey; title: string; options: DbOption[] }; type DialogStep = "select" | "config"; export type ConfigTab = "connection" | "advanced" | "tls" | "transport"; @@ -1085,230 +1087,8 @@ function handleCustomColorInput(value: string) { applyCustomColor(value); } -const driverProfiles: Record< - string, - { - type: DatabaseType; - port: number; - user: string; - label: string; - icon: string; - host?: string; - urlParams?: string; - } -> = { - mysql: { type: "mysql", port: 3306, user: "root", label: "MySQL", icon: "mysql", urlParams: "" }, - postgres: { - type: "postgres", - port: 5432, - user: "postgres", - label: "PostgreSQL", - icon: "postgres", - urlParams: "", - }, - cloudberry: { - type: "postgres", - port: 5432, - user: "postgres", - label: "Apache Cloudberry", - icon: "cloudberry", - urlParams: "", - }, - opentenbase: { - type: "postgres", - port: 11000, - user: "opentenbase", - label: "OpenTenBase", - icon: "opentenbase", - urlParams: "", - }, - redis: { type: "redis", port: 6379, user: "", label: "Redis", icon: "redis" }, - sqlite: { type: "sqlite", port: 0, user: "", label: "SQLite", icon: "sqlite" }, - rqlite: { type: "rqlite", port: 4001, user: "", label: "RQLite", icon: "rqlite" }, - turso: { type: "turso", port: 443, user: "", label: "Turso", icon: "turso" }, - "cloudflare-d1": { type: "cloudflare-d1", port: 443, user: "", label: "Cloudflare D1", icon: "cloudflare-d1" }, - duckdb: { type: "duckdb", port: 0, user: "", label: "DuckDB", icon: "duckdb" }, - access: { type: "access", port: 0, user: "", label: "Microsoft Access", icon: "access" }, - mongodb: { type: "mongodb", port: 27017, user: "", label: "MongoDB", icon: "mongodb" }, - "mongodb-legacy": { type: "mongodb", port: 27017, user: "", label: "MongoDB (Legacy)", icon: "mongodb" }, - dynamodb: { - type: "dynamodb", - port: 443, - user: "", - label: "Amazon DynamoDB", - icon: "dynamodb", - host: "dynamodb.us-east-1.amazonaws.com", - }, - clickhouse: { - type: "clickhouse", - port: 8123, - user: "default", - label: "ClickHouse", - icon: "clickhouse", - }, - sqlserver: { type: "sqlserver", port: 1433, user: "sa", label: "SQL Server", icon: "sqlserver" }, - oracle: { type: "oracle", port: 1521, user: "system", label: "Oracle", icon: "oracle" }, - elasticsearch: { - type: "elasticsearch", - port: 9200, - user: "", - label: "Elasticsearch", - icon: "elasticsearch", - }, - easysearch: { - type: "easysearch", - port: 9200, - user: "", - label: "Easysearch", - icon: "easysearch", - }, - meilisearch: { - type: "meilisearch", - port: 7700, - user: "", - label: "Meilisearch", - icon: "meilisearch", - }, - hbase: { type: "hbase", port: 8080, user: "", label: "Apache HBase", icon: "hbase" }, - qdrant: { type: "qdrant", port: 6333, user: "", label: "Qdrant", icon: "qdrant" }, - milvus: { type: "milvus", port: 19530, user: "root", label: "Milvus", icon: "milvus" }, - weaviate: { type: "weaviate", port: 8080, user: "", label: "Weaviate", icon: "weaviate" }, - chromadb: { type: "chromadb", port: 8000, user: "", label: "ChromaDB", icon: "chromadb" }, - mariadb: { type: "mysql", port: 3306, user: "root", label: "MariaDB", icon: "mariadb" }, - tidb: { type: "mysql", port: 4000, user: "root", label: "TiDB", icon: "tidb" }, - oceanbase: { type: "mysql", port: 2883, user: "root", label: "OceanBase", icon: "oceanbase" }, - "oceanbase-oracle": { - type: "oceanbase-oracle", - port: 2883, - user: "SYS", - label: "OceanBase Oracle Mode", - icon: "oceanbase", - }, - goldendb: { type: "goldendb", port: 3306, user: "root", label: "金篆 GoldenDB", icon: "goldendb" }, - databend: { type: "databend", port: 8000, user: "databend", label: "Databend", icon: "databend" }, - tdsql: { type: "mysql", port: 3306, user: "root", label: "TDSQL", icon: "tdsql" }, - polardb: { type: "mysql", port: 3306, user: "root", label: "PolarDB", icon: "polardb" }, - greatsql: { type: "mysql", port: 3306, user: "root", label: "GreatSQL", icon: "greatsql" }, - databricks: { type: "databricks", port: 443, user: "token", label: "Databricks SQL", icon: "databricks" }, - saphana: { type: "saphana", port: 30015, user: "SYSTEM", label: "SAP HANA", icon: "saphana" }, - teradata: { type: "teradata", port: 1025, user: "", label: "Teradata", icon: "teradata" }, - vertica: { type: "vertica", port: 5433, user: "dbadmin", label: "Vertica", icon: "vertica" }, - firebird: { type: "firebird", port: 3050, user: "SYSDBA", label: "Firebird", icon: "firebird" }, - exasol: { type: "exasol", port: 8563, user: "sys", label: "Exasol", icon: "exasol" }, - gbase: { type: "gbase", port: 5258, user: "gbasedbt", label: "南大通用 GBase 8a", icon: "gbase" }, - gbase8a: { type: "gbase", port: 5258, user: "gbasedbt", label: "南大通用 GBase 8a", icon: "gbase" }, - gbase8s: { type: "gbase", port: 9088, user: "gbasedbt", label: "南大通用 GBase 8s", icon: "gbase" }, - opengauss: { - type: "opengauss", - port: 5432, - user: "gaussdb", - label: "openGauss", - icon: "opengauss", - }, - gaussdb: { type: "gaussdb", port: 5432, user: "gaussdb", label: "GaussDB", icon: "gaussdb" }, - kwdb: { type: "kwdb", port: 26257, user: "root", label: "KWDB", icon: "kwdb" }, - questdb: { type: "questdb", port: 8812, user: "questdb", label: "QuestDB", icon: "questdb" }, - kingbase: { type: "kingbase", port: 54321, user: "system", label: "金仓KingbaseES", icon: "kingbase" }, - highgo: { type: "highgo", port: 5866, user: "highgo", label: "瀚高 HighGo", icon: "highgo" }, - uxdb: { type: "uxdb", port: 52025, user: "uxdb", label: "优炫 UXDB", icon: "uxdb" }, - yashandb: { type: "yashandb", port: 1688, user: "sys", label: "崖山 YashanDB", icon: "yashandb" }, - vastbase: { type: "vastbase", port: 5432, user: "vastbase", label: "海量 Vastbase", icon: "vastbase" }, - doris: { type: "mysql", port: 9030, user: "root", label: "Doris", icon: "doris", urlParams: "" }, - selectdb: { - type: "mysql", - port: 9030, - user: "root", - label: "SelectDB", - icon: "selectdb", - urlParams: "", - }, - starrocks: { - type: "mysql", - port: 9030, - user: "root", - label: "StarRocks", - 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", - port: 26257, - user: "root", - label: "CockroachDB", - icon: "cockroachdb", - }, - dm: { type: "dameng", port: 5236, user: "SYSDBA", label: "达梦 Dameng", icon: "dm" }, - h2: { type: "h2", port: 9092, user: "sa", label: "H2", icon: "h2" }, - "h2-legacy": { type: "h2", port: 9092, user: "sa", label: "H2 2.1 Legacy", icon: "h2" }, - snowflake: { type: "snowflake", port: 443, user: "", label: "Snowflake", icon: "snowflake" }, - trino: { type: "trino", port: 8080, user: "", label: "Trino", icon: "trino" }, - prestosql: { type: "prestosql", port: 8080, user: "", label: "PrestoSQL", icon: "presto" }, - hive: { type: "hive", port: 10000, user: "", label: "Apache Hive", icon: "hive" }, - kyuubi: { type: "kyuubi", port: 10009, user: "", label: "Apache Kyuubi", icon: "kyuubi", urlParams: "auth=NONE" }, - impala: { type: "impala", port: 21050, user: "", label: "Apache Impala", icon: "impala", urlParams: "auth=noSasl" }, - spark: { type: "spark", port: 10015, user: "", label: "Apache Spark", icon: "spark" }, - db2: { type: "db2", port: 50000, user: "db2inst1", label: "IBM DB2", icon: "db2" }, - informix: { type: "informix", port: 9088, user: "informix", label: "Informix", icon: "informix" }, - dremio: { type: "jdbc", port: 31010, user: "", label: "Dremio", icon: "dremio" }, - jdbcx: { type: "jdbc", port: 0, user: "", label: "JDBCX", icon: "jdbcx" }, - neo4j: { type: "neo4j", port: 7687, user: "neo4j", label: "Neo4j", icon: "neo4j" }, - cassandra: { type: "cassandra", port: 9042, user: "cassandra", label: "Cassandra", icon: "cassandra" }, - bigquery: { - type: "bigquery", - port: 443, - user: "", - label: "BigQuery", - icon: "bigquery", - host: "https://www.googleapis.com/bigquery/v2", - }, - spanner: { type: "spanner", port: 443, user: "", label: "Cloud Spanner", icon: "spanner" }, - kylin: { type: "kylin", port: 7070, user: "ADMIN", label: "Apache Kylin", icon: "kylin" }, - ignite: { type: "ignite", port: 10800, user: "", label: "Apache Ignite", icon: "ignite" }, - ignite3: { type: "ignite3", port: 10800, user: "", label: "Apache Ignite 3", icon: "ignite" }, - sundb: { type: "sundb", port: 22000, user: "root", label: "科蓝 SUNDB", icon: "sundb" }, - oscar: { type: "oscar", port: 2003, user: "SYSDBA", label: "神通 OSCAR", icon: "oscar" }, - jdbc: { type: "jdbc", port: 0, user: "", label: "JDBC", icon: "jdbc" }, - tdengine: { type: "tdengine", port: 6041, user: "root", label: "TDengine", icon: "tdengine" }, - xugu: { type: "xugu", port: 5138, user: "", label: "虚谷 XuguDB", icon: "xugu" }, - iotdb: { type: "iotdb", port: 6667, user: "root", label: "Apache IoTDB", icon: "iotdb" }, - etcd: { type: "etcd", port: 2379, user: "", label: "etcd", icon: "etcd" }, - zookeeper: { type: "zookeeper", port: 2181, user: "", label: "Apache ZooKeeper", icon: "zookeeper" }, - mq: { type: "mq", port: 8080, user: "", label: "Apache Pulsar", icon: "pulsar", host: "127.0.0.1" }, - kafka: { type: "mq", port: 9092, user: "", label: "Apache Kafka", icon: "kafka", host: "127.0.0.1" }, - rocketmq: { type: "mq", port: 9876, user: "", label: "Apache RocketMQ", icon: "rocketmq", host: "127.0.0.1" }, - rabbitmq: { type: "mq", port: 5672, user: "", label: "RabbitMQ", icon: "rabbitmq", host: "127.0.0.1" }, - nacos: { type: "nacos", port: 8848, user: "nacos", label: "Nacos", icon: "nacos", host: "127.0.0.1" }, - consul: { type: "consul", port: 8500, user: "", label: "Consul", icon: "consul", host: "127.0.0.1" }, - mqtt: { type: "mqtt", port: 1883, user: "", label: "MQTT", icon: "mqtt", host: "127.0.0.1" }, - iris: { type: "iris", port: 1972, user: "_SYSTEM", label: "IRIS", icon: "iris" }, - influxdb: { type: "influxdb", port: 8086, user: "", label: "InfluxDB", icon: "InfluxDB" }, - victoriametrics: { type: "victoriametrics", port: 8428, user: "", label: "VictoriaMetrics", icon: "victoriametrics" }, - custom_mysql: { - type: "mysql", - port: 3306, - user: "root", - label: "Custom", - icon: "mysql", - urlParams: "", - }, - dolt: { type: "mysql", port: 3306, user: "root", label: "Dolt", icon: "dolt", urlParams: "" }, - custom_postgres: { - type: "postgres", - port: 5432, - user: "postgres", - label: "Custom", - icon: "postgres", - urlParams: "", - }, +const driverProfiles: Record = { + ...CONNECTION_PROFILES, ...jdbcProductDriverProfiles(), }; @@ -2971,259 +2751,35 @@ function isH2FileJdbcUrlLikePath(value: string): boolean { } const iconTypeMap: Record = { - mysql: "mysql", - postgres: "postgres", - cloudberry: "cloudberry", - opentenbase: "opentenbase", - sqlite: "sqlite", - rqlite: "rqlite", - turso: "turso", - "cloudflare-d1": "cloudflare-d1", - access: "access", - redis: "redis", - mongodb: "mongodb", - dynamodb: "dynamodb", - duckdb: "duckdb", - clickhouse: "clickhouse", - sqlserver: "sqlserver", - oracle: "oracle", - elasticsearch: "elasticsearch", - easysearch: "easysearch", - meilisearch: "meilisearch", - hbase: "hbase", - qdrant: "qdrant", - milvus: "milvus", - weaviate: "weaviate", - chromadb: "chromadb", - mariadb: "mariadb", - tidb: "tidb", - oceanbase: "oceanbase", - "oceanbase-oracle": "oceanbase", - goldendb: "goldendb", - databend: "databend", - tdsql: "tdsql", - polardb: "polardb", - greatsql: "greatsql", - databricks: "databricks", - saphana: "saphana", - teradata: "teradata", - vertica: "vertica", - firebird: "firebird", - exasol: "exasol", - gbase: "gbase", - opengauss: "opengauss", - gaussdb: "gaussdb", - kwdb: "kwdb", - questdb: "questdb", - kingbase: "kingbase", - highgo: "highgo", - uxdb: "uxdb", - yashandb: "yashandb", - vastbase: "vastbase", - doris: "doris", - selectdb: "selectdb", - starrocks: "starrocks", - manticoresearch: "manticoresearch", - redshift: "redshift", - cockroachdb: "cockroachdb", - tdengine: "tdengine", - xugu: "xugu", - iotdb: "iotdb", - etcd: "etcd", - zookeeper: "zookeeper", - mq: "mq", - kafka: "kafka", - rocketmq: "rocketmq", - rabbitmq: "rabbitmq", - nacos: "nacos", - consul: "consul", - mqtt: "mqtt", - dm: "dm", - h2: "h2", - snowflake: "snowflake", - trino: "trino", - prestosql: "prestosql", - hive: "hive", - kyuubi: "kyuubi", - impala: "impala", - spark: "spark", - db2: "db2", - informix: "informix", - dremio: "dremio", - jdbcx: "jdbcx", - iris: "iris", - neo4j: "neo4j", - cassandra: "cassandra", - bigquery: "bigquery", - spanner: "spanner", - kylin: "kylin", - ignite: "ignite", - ignite3: "ignite", - sundb: "sundb", - oscar: "oscar", - influxdb: "influxdb", - victoriametrics: "victoriametrics", - jdbc: "jdbc", - custom_mysql: "mysql", - dolt: "dolt", - custom_postgres: "postgres", + ...CONNECTION_PROFILE_ICONS, ...jdbcProductIconTypes(), }; -const dbOptions: DbOption[] = [ - { value: "postgres", label: "PostgreSQL" }, - { value: "cloudberry", label: "Apache Cloudberry" }, - { value: "opentenbase", label: "OpenTenBase" }, - { value: "mysql", label: "MySQL" }, - { value: "mongodb", label: "MongoDB" }, - { value: "dynamodb", label: "Amazon DynamoDB" }, - { value: "redis", label: "Redis" }, - { value: "oracle", label: "Oracle" }, - { value: "sqlite", label: "SQLite" }, - { value: "sqlserver", label: "SQL Server" }, - { value: "elasticsearch", label: "Elasticsearch" }, - { value: "easysearch", label: "Easysearch" }, - { value: "meilisearch", label: "Meilisearch" }, - { value: "hbase", label: "Apache HBase" }, - { value: "qdrant", label: "Qdrant" }, - { value: "milvus", label: "Milvus" }, - { value: "weaviate", label: "Weaviate" }, - { value: "chromadb", label: "ChromaDB" }, - { value: "dm", label: "达梦 Dameng" }, - { value: "opengauss", label: "openGauss" }, - { value: "turso", label: "Turso" }, - { value: "cloudflare-d1", label: "Cloudflare D1" }, - { value: "duckdb", label: "DuckDB" }, - { value: "rqlite", label: "RQLite" }, - { value: "access", label: "Microsoft Access" }, - { value: "mariadb", label: "MariaDB" }, - { value: "clickhouse", label: "ClickHouse" }, - { value: "gaussdb", label: "GaussDB" }, - { value: "kwdb", label: "KWDB" }, - { value: "questdb", label: "QuestDB" }, - { value: "tidb", label: "TiDB" }, - { value: "oceanbase", label: "OceanBase" }, - { value: "goldendb", label: "金篆 GoldenDB" }, - { value: "databend", label: "Databend" }, - { value: "tdsql", label: "TDSQL" }, - { value: "polardb", label: "PolarDB" }, - { value: "greatsql", label: "GreatSQL" }, - { value: "doris", label: "Doris" }, - { value: "selectdb", label: "SelectDB" }, - { value: "starrocks", label: "StarRocks" }, - { value: "tdengine", label: "TDengine" }, - { value: "databricks", label: "Databricks SQL" }, - { value: "saphana", label: "SAP HANA" }, - { value: "teradata", label: "Teradata" }, - { value: "vertica", label: "Vertica" }, - { value: "firebird", label: "Firebird" }, - { value: "exasol", label: "Exasol" }, - { value: "gbase", label: "南大通用 GBase" }, - { value: "kingbase", label: "金仓KingbaseES" }, - { value: "highgo", label: "瀚高 HighGo" }, - { value: "uxdb", label: "优炫 UXDB" }, - { value: "yashandb", label: "崖山 YashanDB" }, - { value: "vastbase", label: "海量 Vastbase" }, - { value: "redshift", label: "Redshift" }, - { value: "cockroachdb", label: "CockroachDB" }, - { value: "h2", label: "H2" }, - { value: "snowflake", label: "Snowflake" }, - { value: "trino", label: "Trino" }, - { value: "prestosql", label: "PrestoSQL" }, - { value: "hive", label: "Hive" }, - { value: "kyuubi", label: "Apache Kyuubi" }, - { value: "impala", label: "Apache Impala" }, - { value: "spark", label: "Apache Spark" }, - { value: "db2", label: "DB2" }, - { value: "informix", label: "Informix" }, - { value: "neo4j", label: "Neo4j" }, - { value: "cassandra", label: "Cassandra" }, - { value: "bigquery", label: "BigQuery" }, - { value: "spanner", label: "Cloud Spanner" }, - { value: "kylin", label: "Kylin" }, - { value: "ignite", label: "Apache Ignite" }, - { value: "ignite3", label: "Apache Ignite 3" }, - { value: "sundb", label: "科蓝 SUNDB" }, - { value: "oscar", label: "神通 OSCAR" }, - { value: "xugu", label: "虚谷 XuguDB" }, - { value: "iotdb", label: "Apache IoTDB" }, - { value: "etcd", label: "etcd" }, - { value: "zookeeper", label: "Apache ZooKeeper" }, - { value: "mq", label: "Apache Pulsar" }, - { value: "kafka", label: "Apache Kafka" }, - { value: "rocketmq", label: "Apache RocketMQ" }, - { value: "rabbitmq", label: "RabbitMQ" }, - { value: "mqtt", label: "MQTT" }, - { value: "nacos", label: "Nacos" }, - { value: "consul", label: "Consul" }, - { value: "influxdb", label: "InfluxDB" }, - { value: "victoriametrics", label: "VictoriaMetrics" }, - { value: "iris", label: "IRIS" }, - { value: "jdbcx", label: "JDBCX" }, - { value: "manticoresearch", label: "Manticore Search" }, - { value: "custom_mysql", label: "Custom (MySQL)" }, - { value: "dolt", label: "Dolt" }, - { value: "custom_postgres", label: "Custom (PostgreSQL)" }, - { value: "dremio", label: "Dremio" }, - ...jdbcProductPickerOptions(), +const dbCategoryMetadata: Array<{ key: DbCategoryKey; titleKey: string }> = [ + { key: "sql", titleKey: "connection.databaseCategorySql" }, + { key: "analytics", titleKey: "connection.databaseCategoryAnalytics" }, + { key: "domestic", titleKey: "connection.databaseCategoryDomestic" }, + { key: "lightweight", titleKey: "connection.databaseCategoryLightweight" }, + { key: "document", titleKey: "connection.databaseCategoryDocument" }, + { key: "graph_ai", titleKey: "connection.databaseCategoryGraphAi" }, + { key: "timeseries", titleKey: "connection.databaseCategoryTimeseries" }, + { key: "mq", titleKey: "connection.databaseCategoryMq" }, + { key: "registry_config", titleKey: "connection.databaseCategoryRegistryConfig" }, ]; -const dbCategoryDefinitions: Array<{ - key: DbCategoryKey; - titleKey: string; - optionValues: string[]; -}> = [ - { - key: "sql", - titleKey: "connection.databaseCategorySql", - optionValues: ["postgres", "mysql", "oracle", "sqlserver", "mariadb", "cockroachdb", "db2", "informix", "firebird", "iris", "spanner", "jdbcx", "custom_mysql", "custom_postgres", "dolt"], - }, - { - key: "analytics", - titleKey: "connection.databaseCategoryAnalytics", - optionValues: ["cloudberry", "clickhouse", "doris", "starrocks", "databend", "selectdb", "databricks", "saphana", "teradata", "vertica", "exasol", "redshift", "snowflake", "trino", "prestosql", "hive", "kyuubi", "impala", "spark", "bigquery", "kylin", "ignite", "ignite3", "dremio"], - }, - { - key: "domestic", - titleKey: "connection.databaseCategoryDomestic", - optionValues: ["dm", "opengauss", "opentenbase", "gaussdb", "kwdb", "tidb", "oceanbase", "goldendb", "tdsql", "polardb", "greatsql", "gbase", "kingbase", "highgo", "uxdb", "yashandb", "vastbase", "sundb", "oscar", "xugu"], - }, - { - key: "lightweight", - titleKey: "connection.databaseCategoryLightweight", - optionValues: ["sqlite", "turso", "cloudflare-d1", "duckdb", "rqlite", "access", "h2"], - }, - { - key: "document", - titleKey: "connection.databaseCategoryDocument", - optionValues: ["mongodb", "dynamodb", "redis", "elasticsearch", "easysearch", "meilisearch", "hbase", "manticoresearch", "cassandra"], - }, - { - key: "graph_ai", - titleKey: "connection.databaseCategoryGraphAi", - optionValues: ["neo4j", "qdrant", "milvus", "weaviate", "chromadb"], - }, - { - key: "timeseries", - titleKey: "connection.databaseCategoryTimeseries", - optionValues: ["questdb", "tdengine", "iotdb", "influxdb", "victoriametrics"], - }, - { - key: "mq", - titleKey: "connection.databaseCategoryMq", - optionValues: ["mq", "kafka", "rocketmq", "rabbitmq", "mqtt"], - }, - { - key: "registry_config", - titleKey: "connection.databaseCategoryRegistryConfig", - optionValues: ["etcd", "zookeeper", "nacos", "consul"], - }, -]; - -for (const category of dbCategoryDefinitions) { - category.optionValues.push(...jdbcProductProfileIdsForCategory(category.key)); +function jdbcProductCategory(profileId: string): DbCategoryKey { + const category = dbCategoryMetadata.find(({ key }) => jdbcProductProfileIdsForCategory(key).includes(profileId))?.key; + if (!category) throw new Error(`JDBC product profile ${profileId} has no connection picker category`); + return category; } +const dbOptions: DbOption[] = [...CONNECTION_PICKER_OPTIONS, ...jdbcProductPickerOptions().map((option) => ({ ...option, category: jdbcProductCategory(option.value) }))]; + +const dbCategoryDefinitions = dbCategoryMetadata.map((category) => ({ + ...category, + optionValues: dbOptions.filter((option) => option.category === category.key).map((option) => option.value), +})); + // Keep the picker exhaustive as database drivers are added or reorganized. assertCompleteDatabaseCategories( dbOptions.map((option) => option.value), @@ -3298,7 +2854,8 @@ function supportsNativeAgentJdbcDriverConfigType(dbType: DatabaseType): boolean } const jdbcBackedDatabaseTypes = new Set(["jdbc", "prestosql", "bigquery"]); -const isJdbcConnection = computed(() => form.value.db_type === "jdbc"); +const connectionFormKind = computed(() => databaseConnectionFormKind(form.value.db_type)); +const isJdbcConnection = computed(() => connectionFormKind.value === "jdbc"); const isJdbcxConnection = computed(() => isJdbcConnection.value && form.value.driver_profile === JDBCX_DRIVER_PROFILE); const isJdbcProductConnection = computed(() => Boolean(activeJdbcProductProfile.value)); const jdbcxHighPrivilegeExtensionsAllowed = computed({ diff --git a/apps/desktop/src/lib/__tests__/connection/h2ConnectionDialog.spec.ts b/apps/desktop/src/lib/__tests__/connection/h2ConnectionDialog.spec.ts index 0914f99ade..22ac19e954 100644 --- a/apps/desktop/src/lib/__tests__/connection/h2ConnectionDialog.spec.ts +++ b/apps/desktop/src/lib/__tests__/connection/h2ConnectionDialog.spec.ts @@ -1,8 +1,8 @@ import { readFileSync } from "node:fs"; import { describe, expect, it } from "vitest"; +import { CONNECTION_PICKER_OPTIONS, CONNECTION_PROFILES } from "@/types/generated/connectionProfiles"; const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8"); -const categoriesSource = readFileSync(new URL("../../connection/driver-category-definitions.ts", import.meta.url), "utf8"); describe("H2 connection dialog driver profiles", () => { it("offers auto, bundled compatibility ranges, and a custom JAR fallback", () => { @@ -35,8 +35,8 @@ describe("H2 connection dialog driver profiles", () => { }); it("keeps legacy profile hydration without exposing a second H2 catalog entry", () => { - expect(dialogSource).toContain('"h2-legacy": { type: "h2"'); - expect(categoriesSource).toContain('h2: "lightweight"'); - expect(categoriesSource).not.toContain('"h2-legacy": "lightweight"'); + expect(CONNECTION_PROFILES["h2-legacy"]).toMatchObject({ type: "h2", port: 9092, user: "sa" }); + expect(CONNECTION_PICKER_OPTIONS.find((option) => option.value === "h2")?.category).toBe("lightweight"); + expect(CONNECTION_PICKER_OPTIONS.some((option) => option.value === "h2-legacy")).toBe(false); }); }); diff --git a/apps/desktop/src/lib/__tests__/connection/spannerConnectionDialog.spec.ts b/apps/desktop/src/lib/__tests__/connection/spannerConnectionDialog.spec.ts index 13fcdf04f6..5b9f16b87c 100644 --- a/apps/desktop/src/lib/__tests__/connection/spannerConnectionDialog.spec.ts +++ b/apps/desktop/src/lib/__tests__/connection/spannerConnectionDialog.spec.ts @@ -1,21 +1,14 @@ import { readFileSync } from "node:fs"; import { describe, expect, it } from "vitest"; +import { CONNECTION_PICKER_OPTIONS, CONNECTION_PROFILES } from "@/types/generated/connectionProfiles"; const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8"); const fieldsSource = readFileSync(new URL("../../../components/connection/SpannerConnectionFields.vue", import.meta.url), "utf8"); describe("Cloud Spanner connection dialog", () => { it("registers the bundled agent profile in the SQL category", () => { - expect(dialogSource).toContain('spanner: { type: "spanner", port: 443, user: "", label: "Cloud Spanner", icon: "spanner" }'); - expect(dialogSource).toContain('{ value: "spanner", label: "Cloud Spanner" }'); - expect(dialogSource).toContain('spanner: "spanner",'); - - // Cloud Spanner is an OLTP relational database, so it belongs to the SQL - // category rather than the analytics one. - const sqlCategory = dialogSource.match(/key: "sql",\s*\n\s*titleKey: "connection\.databaseCategorySql",\s*\n\s*optionValues: \[([\s\S]*?)\]/)?.[1] ?? ""; - const analyticsCategory = dialogSource.match(/key: "analytics",[\s\S]*?optionValues: \[([\s\S]*?)\]/)?.[1] ?? ""; - expect(sqlCategory).toContain('"spanner"'); - expect(analyticsCategory).not.toContain('"spanner"'); + expect(CONNECTION_PROFILES.spanner).toMatchObject({ type: "spanner", port: 443, user: "", label: "Cloud Spanner", icon: "spanner" }); + expect(CONNECTION_PICKER_OPTIONS.find((option) => option.value === "spanner")).toEqual({ value: "spanner", label: "Cloud Spanner", category: "sql" }); }); it("does not expose external JDBC driver configuration because the driver is bundled", () => { diff --git a/apps/desktop/src/lib/__tests__/database/connectionProfiles.spec.ts b/apps/desktop/src/lib/__tests__/database/connectionProfiles.spec.ts new file mode 100644 index 0000000000..f35ed2073b --- /dev/null +++ b/apps/desktop/src/lib/__tests__/database/connectionProfiles.spec.ts @@ -0,0 +1,29 @@ +import { describe, expect, it } from "vitest"; +import { CONNECTION_PICKER_OPTIONS, CONNECTION_PROFILES, CONNECTION_PROFILE_ICONS } from "@/types/generated/connectionProfiles"; + +describe("generated connection profiles", () => { + it("keeps picker options unique and backed by profiles", () => { + const optionIds = CONNECTION_PICKER_OPTIONS.map((option) => option.value); + expect(new Set(optionIds).size).toBe(optionIds.length); + expect(optionIds.every((id) => id in CONNECTION_PROFILES)).toBe(true); + }); + + it("preserves compatible products and specialized protocol defaults", () => { + expect(CONNECTION_PROFILES.mariadb).toMatchObject({ type: "mysql", port: 3306, user: "root" }); + expect(CONNECTION_PROFILES.rabbitmq).toMatchObject({ type: "mq", port: 5672, host: "127.0.0.1" }); + expect(CONNECTION_PROFILES.nacos).toMatchObject({ type: "nacos", port: 8848, user: "nacos" }); + }); + + it("keeps internal variants out of the main picker", () => { + const optionIds = new Set(CONNECTION_PICKER_OPTIONS.map((option) => option.value)); + expect(optionIds.has("mongodb-legacy")).toBe(false); + expect(optionIds.has("oceanbase-oracle")).toBe(false); + expect(optionIds.has("h2-legacy")).toBe(false); + }); + + it("preserves picker-specific icon overrides", () => { + expect(CONNECTION_PROFILE_ICONS.mq).toBe("mq"); + expect(CONNECTION_PROFILE_ICONS.prestosql).toBe("prestosql"); + expect(CONNECTION_PROFILE_ICONS.influxdb).toBe("influxdb"); + }); +}); diff --git a/apps/desktop/src/lib/__tests__/database/databaseDriverManifest.spec.ts b/apps/desktop/src/lib/__tests__/database/databaseDriverManifest.spec.ts index e313f9d260..02368fc862 100644 --- a/apps/desktop/src/lib/__tests__/database/databaseDriverManifest.spec.ts +++ b/apps/desktop/src/lib/__tests__/database/databaseDriverManifest.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { databaseRuntimeMode, usesAgentCursorForQuery } from "@/lib/database/databaseDriverManifest"; +import { databaseConnectionFormKind, databaseDefaultPort, databaseManifestEntry, databaseRuntimeMode, usesAgentCursorForQuery } from "@/lib/database/databaseDriverManifest"; describe("databaseDriverManifest", () => { it("uses agent cursor only for agent or external runtimes", () => { @@ -13,4 +13,23 @@ describe("databaseDriverManifest", () => { expect(usesAgentCursorForQuery("jdbc")).toBe(true); expect(usesAgentCursorForQuery("prestosql")).toBe(true); }); + + it("exposes connection defaults from the shared manifest", () => { + expect(databaseDefaultPort("mysql")).toBe(3306); + expect(databaseManifestEntry("h2")).toMatchObject({ + dbType: "h2", + runtimeMode: "agent", + agentKey: "h2", + skipTcpProbe: true, + localFile: true, + }); + }); + + it("routes only specialized connection forms explicitly", () => { + expect(databaseConnectionFormKind("mysql")).toBe("standard"); + expect(databaseConnectionFormKind("jdbc")).toBe("jdbc"); + expect(databaseConnectionFormKind("mq")).toBe("mq"); + expect(databaseConnectionFormKind("mqtt")).toBe("mqtt"); + expect(databaseConnectionFormKind("nacos")).toBe("nacos"); + }); }); diff --git a/apps/desktop/src/lib/connection/connectionFile.ts b/apps/desktop/src/lib/connection/connectionFile.ts index c3af15e002..affd2c264e 100644 --- a/apps/desktop/src/lib/connection/connectionFile.ts +++ b/apps/desktop/src/lib/connection/connectionFile.ts @@ -1,5 +1,6 @@ import type { ConnectionConfig, DatabaseType } from "@/types/database"; import { h2FilePathFromJdbcUrl } from "@/lib/database/h2Connection"; +import { isKnownDatabaseType, isLocalFileDatabaseType } from "@/lib/database/databaseDriverManifest"; /** * Whether the database type is one that (potentially) backs onto a local file. @@ -9,7 +10,7 @@ import { h2FilePathFromJdbcUrl } from "@/lib/database/h2Connection"; * available. */ export function isLocalFileTypeDb(dbType: DatabaseType | string): boolean { - return dbType === "sqlite" || dbType === "duckdb" || dbType === "access" || dbType === "h2"; + return isKnownDatabaseType(dbType) && isLocalFileDatabaseType(dbType); } /** diff --git a/apps/desktop/src/lib/connection/connectionPresentation.ts b/apps/desktop/src/lib/connection/connectionPresentation.ts index fd519e2481..b1a0badcbb 100644 --- a/apps/desktop/src/lib/connection/connectionPresentation.ts +++ b/apps/desktop/src/lib/connection/connectionPresentation.ts @@ -1,12 +1,12 @@ import type { ConnectionConfig, DatabaseType } from "@/types/database"; import { GAUSSDB_M_JDBC_DRIVER_PROFILE } from "@/lib/database/jdbcDialect"; +import { isLocalFileDatabaseType } from "@/lib/database/databaseDriverManifest"; import { parseGaussdbHosts, serializeGaussdbHosts } from "@/lib/connection/gaussdbHosts"; import { spannerDisplayDatabase } from "@/lib/connection/spannerResourcePath"; type ConnectionPresentationConfig = Pick; type ConnectionNamePresentationConfig = ConnectionPresentationConfig & Pick; -const LOCAL_DATABASE_TYPES = new Set(["sqlite", "duckdb", "access"]); const REDACTED_HOST_SEGMENT = "***"; const REDACTED_PORT = "****"; @@ -24,7 +24,7 @@ export function connectionEndpointLabel(connection?: ConnectionPresentationConfi // Cloud Spanner stores the whole resource path in `database`; only the trailing // database ID is short enough for a subtitle, and the host is empty on Google Cloud. if (connection.db_type === "spanner") return connection.host ? `${connection.host}:${connection.port}` : spannerDisplayDatabase(connection.database); - if (LOCAL_DATABASE_TYPES.has(connection.db_type) || (connection.db_type === "h2" && connection.port === 0)) { + if (isLocalFilePresentationConnection(connection)) { return connection.host || connection.database || "local"; } const endpoint = normalizedPresentationEndpoint(connection); @@ -88,7 +88,7 @@ export function connectionRedactedEndpointLabel(connection?: ConnectionPresentat // no more than any other database name; without this branch the fallback below // would print the full `projects/.../databases/...` path. if (connection.db_type === "spanner") return connection.host ? `${redactConnectionHost(connection.host)}:${REDACTED_PORT}` : spannerDisplayDatabase(connection.database); - if (LOCAL_DATABASE_TYPES.has(connection.db_type) || (connection.db_type === "h2" && connection.port === 0)) { + if (isLocalFilePresentationConnection(connection)) { return connectionEndpointLabel(connection); } @@ -106,7 +106,7 @@ export function connectionRedactedEndpointLabel(connection?: ConnectionPresentat export function connectionRedactedNameLabel(connection?: ConnectionNamePresentationConfig): string { const name = connection?.name.trim() || ""; - if (!connection || !name || LOCAL_DATABASE_TYPES.has(connection.db_type) || (connection.db_type === "h2" && connection.port === 0)) return name; + if (!connection || !name || isLocalFilePresentationConnection(connection)) return name; const host = connection.host.trim(); if (!host) return name; @@ -123,6 +123,10 @@ export function connectionRedactedNameLabel(connection?: ConnectionNamePresentat return hostNames.has(name) ? connectionRedactedEndpointLabel(connection) : name; } +function isLocalFilePresentationConnection(connection: Pick): boolean { + return isLocalFileDatabaseType(connection.db_type) && (connection.db_type !== "h2" || connection.port === 0); +} + export function connectionDisplayUrlScheme(connection: Pick & Partial>): string { switch (connection.db_type) { case "postgres": diff --git a/apps/desktop/src/lib/database/__tests__/transferObjectKinds.spec.ts b/apps/desktop/src/lib/database/__tests__/transferObjectKinds.spec.ts index 76a343dbc1..62cc19cc8f 100644 --- a/apps/desktop/src/lib/database/__tests__/transferObjectKinds.spec.ts +++ b/apps/desktop/src/lib/database/__tests__/transferObjectKinds.spec.ts @@ -4,7 +4,7 @@ import { manifestDatabaseTypes } from "@/lib/database/databaseDriverManifest"; import { supportsTransfer } from "@/lib/database/databaseFeatureSupport"; import type { DatabaseType } from "@/types/database"; -const TABLE_ONLY_TRANSFER_DATABASES: DatabaseType[] = ["sqlite", "rqlite", "cloudflare-d1", "duckdb", "clickhouse", "mongodb", "goldendb", "questdb", "hive", "kyuubi", "impala", "spark"]; +const TABLE_ONLY_TRANSFER_DATABASES: DatabaseType[] = ["sqlite", "rqlite", "turso", "cloudflare-d1", "duckdb", "clickhouse", "mongodb", "goldendb", "questdb", "hive", "kyuubi", "impala", "spark"]; describe("transferObjectKinds", () => { it("groups databases into transfer families", () => { diff --git a/apps/desktop/src/lib/database/databaseCapabilitySets.ts b/apps/desktop/src/lib/database/databaseCapabilitySets.ts index e0633a5964..c65c511c72 100644 --- a/apps/desktop/src/lib/database/databaseCapabilitySets.ts +++ b/apps/desktop/src/lib/database/databaseCapabilitySets.ts @@ -1,104 +1,24 @@ -import type { DatabaseType } from "@/types/database"; +import { databaseTypesWithTrait } from "@/lib/database/databaseDriverManifest"; -export const SCHEMA_AWARE_TYPES = new Set([ - "postgres", - // Cloud Spanner supports named schemas; GoogleSQL's default schema is the empty string, which - // `spannerObjectTreeSchema` keeps intact through the `schema || database` fallbacks. - "spanner", - "sqlserver", - "oracle", - "redshift", - "dameng", - "gaussdb", - "kwdb", - "kingbase", - "highgo", - "uxdb", - "vastbase", - "yashandb", - "databricks", - "saphana", - "teradata", - "vertica", - "exasol", - "opengauss", - "oceanbase-oracle", - "gbase", - "jdbc", - "h2", - "ignite", - "ignite3", - "snowflake", - "trino", - "prestosql", - "hive", - "kyuubi", - "impala", - "spark", - "databend", - "db2", - "informix", - "xugu", - "oscar", - "iotdb", - "iris", - "duckdb", -]); +export const SCHEMA_AWARE_TYPES = databaseTypesWithTrait("schemaAware"); // Engines where an object can be addressed as database/catalog.schema.table. // Keep this narrower than SCHEMA_AWARE_TYPES: PostgreSQL, for example, cannot // query another database through a three-part name on the same connection. -export const DATABASE_SCHEMA_QUALIFIED_TYPES = new Set(["sqlserver", "trino", "prestosql"]); +export const DATABASE_SCHEMA_QUALIFIED_TYPES = databaseTypesWithTrait("databaseSchemaQualified"); -export const SINGLE_DATABASE_TYPES = new Set(["oracle", "dameng", "firebird", "oceanbase-oracle", "access", "questdb", "victoriametrics"]); +export const SINGLE_DATABASE_TYPES = databaseTypesWithTrait("singleDatabase"); -export const CLEARABLE_QUERY_SCHEMA_TYPES = new Set(["oracle", "dameng", "gaussdb", "oceanbase-oracle"]); +export const CLEARABLE_QUERY_SCHEMA_TYPES = databaseTypesWithTrait("clearableQuerySchema"); -export const FETCH_FIRST_TYPES = new Set(["oracle", "dameng"]); +export const FETCH_FIRST_TYPES = databaseTypesWithTrait("fetchFirst"); -export const TREE_SCHEMA_TYPES = new Set([ - "postgres", - // Cloud Spanner needs the schema level for the same reason it is in SCHEMA_AWARE_TYPES: named - // schemas exist and are queryable, so the tree has to expose them. Membership here is what makes - // a database node load schemas instead of tables; SCHEMA_AWARE_TYPES alone only reaches the - // schema pickers in dialogs. The sites gated on `database === ""` stay unreachable because a - // Spanner database is always the resource path. - "spanner", - "redshift", - "sqlserver", - "db2", - "gaussdb", - "kwdb", - "kingbase", - "highgo", - "uxdb", - "vastbase", - "yashandb", - "databricks", - "saphana", - "teradata", - "vertica", - "exasol", - "opengauss", - "oceanbase-oracle", - "gbase", - "jdbc", - "trino", - "prestosql", - "h2", - "ignite", - "ignite3", - "informix", - "xugu", - "oscar", - "iris", - "duckdb", -]); +export const TREE_SCHEMA_TYPES = databaseTypesWithTrait("treeSchema"); -export const DATABASE_OBJECT_TREE_TYPES = new Set(["jdbc"]); +export const DATABASE_OBJECT_TREE_TYPES = databaseTypesWithTrait("databaseObjectTree"); -export const PG_VACUUM_TYPES = new Set(["postgres", "gaussdb", "kwdb", "kingbase", "highgo", "uxdb", "vastbase", "opengauss"]); +export const PG_VACUUM_TYPES = databaseTypesWithTrait("pgVacuum"); -export const PG_LIKE_STRUCTURE_TYPES = new Set(["postgres", "redshift", "gaussdb", "kwdb", "opengauss", "questdb"]); +export const PG_LIKE_STRUCTURE_TYPES = databaseTypesWithTrait("pgLikeStructure"); -export const DIAGRAM_SQL_TYPES = new Set(["mysql", "postgres", "sqlite", "rqlite", "turso", "cloudflare-d1", "sqlserver", "oracle", "redshift", "dameng", "gaussdb", "kwdb", "opengauss", "questdb", "oceanbase-oracle"]); +export const DIAGRAM_SQL_TYPES = databaseTypesWithTrait("diagramSql"); diff --git a/apps/desktop/src/lib/database/databaseDriverManifest.ts b/apps/desktop/src/lib/database/databaseDriverManifest.ts index 37b2f85edd..fd2556230f 100644 --- a/apps/desktop/src/lib/database/databaseDriverManifest.ts +++ b/apps/desktop/src/lib/database/databaseDriverManifest.ts @@ -3,6 +3,7 @@ import driverManifest from "../../../../../crates/dbx-core/assets/database-drive export type DatabaseSupportLevel = "connect" | "browse" | "understand" | "operate"; export type DatabaseRuntimeMode = "native" | "file" | "agent" | "external"; +export type ConnectionFormKind = "standard" | "jdbc" | "mq" | "mqtt" | "nacos"; export const DATABASE_PRODUCT_CAPABILITY_KEYS = [ "queryExecution", @@ -26,9 +27,46 @@ export const DATABASE_PRODUCT_CAPABILITY_KEYS = [ export type DatabaseProductCapability = (typeof DATABASE_PRODUCT_CAPABILITY_KEYS)[number]; export type DatabaseProductCapabilities = Record; -interface DatabaseDriverManifestEntry { +export const DATABASE_BEHAVIOR_TRAIT_KEYS = ["schemaAware", "databaseSchemaQualified", "singleDatabase", "clearableQuerySchema", "fetchFirst", "treeSchema", "databaseObjectTree", "pgVacuum", "pgLikeStructure", "diagramSql"] as const; + +export type DatabaseBehaviorTrait = (typeof DATABASE_BEHAVIOR_TRAIT_KEYS)[number]; +export type DatabaseBehaviorTraits = Partial>; + +export interface DatabaseDriverProfile { + profile: string; + agentKey: string; + packageKey?: string; + label: string; + storeVisible: boolean; + storeOrder?: number; +} + +export interface ManagedDatabaseDriver { + key: string; + label: string; + storeVisible: boolean; + storeOrder?: number; +} + +export interface DatabaseDriverManifestEntry { dbType: DatabaseType; + label: string; + dialect?: string; runtimeMode: DatabaseRuntimeMode; + mcpMode: "direct" | "bridge" | "unsupported"; + agentKey?: string; + driverStoreVisible?: boolean; + driverStoreOrder?: number; + driverProfiles?: DatabaseDriverProfile[]; + managedDrivers?: ManagedDatabaseDriver[]; + singleConnectionPool: boolean; + metadataConnectionScoped: boolean; + skipTcpProbe: boolean; + defaultPort?: number; + localFile?: boolean; + specializedSurface?: boolean; + formKind?: ConnectionFormKind; + traits?: DatabaseBehaviorTraits; supportLevel: DatabaseSupportLevel; capabilities: Partial; } @@ -74,6 +112,30 @@ export function databaseSupportLevel(dbType?: DatabaseType): DatabaseSupportLeve return dbType ? DATABASE_DRIVER_BY_TYPE.get(dbType)?.supportLevel : undefined; } +export function databaseManifestEntry(dbType?: DatabaseType): DatabaseDriverManifestEntry | undefined { + return dbType ? DATABASE_DRIVER_BY_TYPE.get(dbType) : undefined; +} + +export function databaseDefaultPort(dbType?: DatabaseType): number | undefined { + return databaseManifestEntry(dbType)?.defaultPort; +} + +export function databaseConnectionFormKind(dbType?: DatabaseType): ConnectionFormKind { + return databaseManifestEntry(dbType)?.formKind ?? "standard"; +} + +export function isKnownDatabaseType(value: string): value is DatabaseType { + return DATABASE_DRIVER_BY_TYPE.has(value as DatabaseType); +} + +export function isLocalFileDatabaseType(dbType?: DatabaseType): boolean { + return databaseManifestEntry(dbType)?.localFile === true; +} + +export function databaseTypesWithTrait(trait: DatabaseBehaviorTrait): Set { + return new Set(DATABASE_DRIVER_ENTRIES.filter((entry) => entry.traits?.[trait] === true).map((entry) => entry.dbType)); +} + export function databaseRuntimeMode(dbType?: DatabaseType): DatabaseRuntimeMode | undefined { return dbType ? DATABASE_DRIVER_BY_TYPE.get(dbType)?.runtimeMode : undefined; } diff --git a/apps/desktop/src/types/database.ts b/apps/desktop/src/types/database.ts index 038434fb8f..0e30558cdb 100644 --- a/apps/desktop/src/types/database.ts +++ b/apps/desktop/src/types/database.ts @@ -1,86 +1,9 @@ import type { BackendError } from "@/lib/backend/errorUtils"; import type { TransferContent, TransferMode, TransferObjectKind, TransferTableNameCase } from "@/lib/backend/tauri"; import type { MultiDbExecutionTarget, MultiDbResultRunExecution } from "@/types/sqlExecution"; +import type { DatabaseType } from "@/types/generated/databaseTypes"; -export type DatabaseType = - | "mysql" - | "postgres" - | "sqlite" - | "rqlite" - | "turso" - | "cloudflare-d1" - | "redis" - | "duckdb" - | "clickhouse" - | "sqlserver" - | "mongodb" - | "dynamodb" - | "oracle" - | "elasticsearch" - | "easysearch" - | "meilisearch" - | "hbase" - | "qdrant" - | "milvus" - | "weaviate" - | "chromadb" - | "doris" - | "starrocks" - | "manticoresearch" - | "databend" - | "redshift" - | "dameng" - | "gaussdb" - | "kingbase" - | "highgo" - | "uxdb" - | "vastbase" - | "goldendb" - | "kwdb" - | "yashandb" - | "databricks" - | "saphana" - | "teradata" - | "vertica" - | "firebird" - | "exasol" - | "opengauss" - | "oceanbase-oracle" - | "questdb" - | "gbase" - | "access" - | "h2" - | "snowflake" - | "trino" - | "prestosql" - | "hive" - | "kyuubi" - | "impala" - | "spark" - | "db2" - | "informix" - | "neo4j" - | "cassandra" - | "bigquery" - | "spanner" - | "kylin" - | "ignite" - | "ignite3" - | "sundb" - | "oscar" - | "tdengine" - | "xugu" - | "iotdb" - | "etcd" - | "zookeeper" - | "iris" - | "influxdb" - | "victoriametrics" - | "jdbc" - | "mq" - | "mqtt" - | "nacos" - | "consul"; +export type { DatabaseType } from "@/types/generated/databaseTypes"; export function isElasticsearchCompatibleDatabaseType(dbType?: DatabaseType): boolean { return dbType === "elasticsearch" || dbType === "easysearch"; diff --git a/apps/desktop/src/types/generated/connectionProfiles.ts b/apps/desktop/src/types/generated/connectionProfiles.ts new file mode 100644 index 0000000000..e36a927d36 --- /dev/null +++ b/apps/desktop/src/types/generated/connectionProfiles.ts @@ -0,0 +1,323 @@ +// Generated by scripts/sync-connection-types.mjs. Do not edit manually. +import type { DatabaseType } from "./databaseTypes"; + +export type ConnectionProfileCategory = "sql" | "analytics" | "domestic" | "lightweight" | "document" | "graph_ai" | "timeseries" | "mq" | "registry_config"; + +export interface ConnectionProfileDefinition { + type: DatabaseType; + port: number; + user: string; + label: string; + icon: string; + host?: string; + urlParams?: string; +} + +export interface ConnectionPickerOption { + value: string; + label: string; + category: ConnectionProfileCategory; +} + +export const CONNECTION_PROFILES = { + mysql: { type: "mysql", port: 3306, user: "root", label: "MySQL", icon: "mysql", urlParams: "" }, + postgres: { type: "postgres", port: 5432, user: "postgres", label: "PostgreSQL", icon: "postgres", urlParams: "" }, + cloudberry: { type: "postgres", port: 5432, user: "postgres", label: "Apache Cloudberry", icon: "cloudberry", urlParams: "" }, + opentenbase: { type: "postgres", port: 11000, user: "opentenbase", label: "OpenTenBase", icon: "opentenbase", urlParams: "" }, + redis: { type: "redis", port: 6379, user: "", label: "Redis", icon: "redis" }, + sqlite: { type: "sqlite", port: 0, user: "", label: "SQLite", icon: "sqlite" }, + rqlite: { type: "rqlite", port: 4001, user: "", label: "RQLite", icon: "rqlite" }, + turso: { type: "turso", port: 443, user: "", label: "Turso", icon: "turso" }, + "cloudflare-d1": { type: "cloudflare-d1", port: 443, user: "", label: "Cloudflare D1", icon: "cloudflare-d1" }, + duckdb: { type: "duckdb", port: 0, user: "", label: "DuckDB", icon: "duckdb" }, + access: { type: "access", port: 0, user: "", label: "Microsoft Access", icon: "access" }, + mongodb: { type: "mongodb", port: 27017, user: "", label: "MongoDB", icon: "mongodb" }, + "mongodb-legacy": { type: "mongodb", port: 27017, user: "", label: "MongoDB (Legacy)", icon: "mongodb" }, + dynamodb: { type: "dynamodb", port: 443, user: "", label: "Amazon DynamoDB", icon: "dynamodb", host: "dynamodb.us-east-1.amazonaws.com" }, + clickhouse: { type: "clickhouse", port: 8123, user: "default", label: "ClickHouse", icon: "clickhouse" }, + sqlserver: { type: "sqlserver", port: 1433, user: "sa", label: "SQL Server", icon: "sqlserver" }, + oracle: { type: "oracle", port: 1521, user: "system", label: "Oracle", icon: "oracle" }, + elasticsearch: { type: "elasticsearch", port: 9200, user: "", label: "Elasticsearch", icon: "elasticsearch" }, + easysearch: { type: "easysearch", port: 9200, user: "", label: "Easysearch", icon: "easysearch" }, + meilisearch: { type: "meilisearch", port: 7700, user: "", label: "Meilisearch", icon: "meilisearch" }, + hbase: { type: "hbase", port: 8080, user: "", label: "Apache HBase", icon: "hbase" }, + qdrant: { type: "qdrant", port: 6333, user: "", label: "Qdrant", icon: "qdrant" }, + milvus: { type: "milvus", port: 19530, user: "root", label: "Milvus", icon: "milvus" }, + weaviate: { type: "weaviate", port: 8080, user: "", label: "Weaviate", icon: "weaviate" }, + chromadb: { type: "chromadb", port: 8000, user: "", label: "ChromaDB", icon: "chromadb" }, + mariadb: { type: "mysql", port: 3306, user: "root", label: "MariaDB", icon: "mariadb" }, + tidb: { type: "mysql", port: 4000, user: "root", label: "TiDB", icon: "tidb" }, + oceanbase: { type: "mysql", port: 2883, user: "root", label: "OceanBase", icon: "oceanbase" }, + "oceanbase-oracle": { type: "oceanbase-oracle", port: 2883, user: "SYS", label: "OceanBase Oracle Mode", icon: "oceanbase" }, + goldendb: { type: "goldendb", port: 3306, user: "root", label: "金篆 GoldenDB", icon: "goldendb" }, + databend: { type: "databend", port: 8000, user: "databend", label: "Databend", icon: "databend" }, + tdsql: { type: "mysql", port: 3306, user: "root", label: "TDSQL", icon: "tdsql" }, + polardb: { type: "mysql", port: 3306, user: "root", label: "PolarDB", icon: "polardb" }, + greatsql: { type: "mysql", port: 3306, user: "root", label: "GreatSQL", icon: "greatsql" }, + databricks: { type: "databricks", port: 443, user: "token", label: "Databricks SQL", icon: "databricks" }, + saphana: { type: "saphana", port: 30015, user: "SYSTEM", label: "SAP HANA", icon: "saphana" }, + teradata: { type: "teradata", port: 1025, user: "", label: "Teradata", icon: "teradata" }, + vertica: { type: "vertica", port: 5433, user: "dbadmin", label: "Vertica", icon: "vertica" }, + firebird: { type: "firebird", port: 3050, user: "SYSDBA", label: "Firebird", icon: "firebird" }, + exasol: { type: "exasol", port: 8563, user: "sys", label: "Exasol", icon: "exasol" }, + gbase: { type: "gbase", port: 5258, user: "gbasedbt", label: "南大通用 GBase 8a", icon: "gbase" }, + gbase8a: { type: "gbase", port: 5258, user: "gbasedbt", label: "南大通用 GBase 8a", icon: "gbase" }, + gbase8s: { type: "gbase", port: 9088, user: "gbasedbt", label: "南大通用 GBase 8s", icon: "gbase" }, + opengauss: { type: "opengauss", port: 5432, user: "gaussdb", label: "openGauss", icon: "opengauss" }, + gaussdb: { type: "gaussdb", port: 5432, user: "gaussdb", label: "GaussDB", icon: "gaussdb" }, + kwdb: { type: "kwdb", port: 26257, user: "root", label: "KWDB", icon: "kwdb" }, + questdb: { type: "questdb", port: 8812, user: "questdb", label: "QuestDB", icon: "questdb" }, + kingbase: { type: "kingbase", port: 54321, user: "system", label: "金仓KingbaseES", icon: "kingbase" }, + highgo: { type: "highgo", port: 5866, user: "highgo", label: "瀚高 HighGo", icon: "highgo" }, + uxdb: { type: "uxdb", port: 52025, user: "uxdb", label: "优炫 UXDB", icon: "uxdb" }, + yashandb: { type: "yashandb", port: 1688, user: "sys", label: "崖山 YashanDB", icon: "yashandb" }, + vastbase: { type: "vastbase", port: 5432, user: "vastbase", label: "海量 Vastbase", icon: "vastbase" }, + doris: { type: "mysql", port: 9030, user: "root", label: "Doris", icon: "doris", urlParams: "" }, + selectdb: { type: "mysql", port: 9030, user: "root", label: "SelectDB", icon: "selectdb", urlParams: "" }, + starrocks: { type: "mysql", port: 9030, user: "root", label: "StarRocks", 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", port: 26257, user: "root", label: "CockroachDB", icon: "cockroachdb" }, + dm: { type: "dameng", port: 5236, user: "SYSDBA", label: "达梦 Dameng", icon: "dm" }, + h2: { type: "h2", port: 9092, user: "sa", label: "H2", icon: "h2" }, + "h2-legacy": { type: "h2", port: 9092, user: "sa", label: "H2 2.1 Legacy", icon: "h2" }, + snowflake: { type: "snowflake", port: 443, user: "", label: "Snowflake", icon: "snowflake" }, + trino: { type: "trino", port: 8080, user: "", label: "Trino", icon: "trino" }, + prestosql: { type: "prestosql", port: 8080, user: "", label: "PrestoSQL", icon: "presto" }, + hive: { type: "hive", port: 10000, user: "", label: "Apache Hive", icon: "hive" }, + kyuubi: { type: "kyuubi", port: 10009, user: "", label: "Apache Kyuubi", icon: "kyuubi", urlParams: "auth=NONE" }, + impala: { type: "impala", port: 21050, user: "", label: "Apache Impala", icon: "impala", urlParams: "auth=noSasl" }, + spark: { type: "spark", port: 10015, user: "", label: "Apache Spark", icon: "spark" }, + db2: { type: "db2", port: 50000, user: "db2inst1", label: "IBM DB2", icon: "db2" }, + informix: { type: "informix", port: 9088, user: "informix", label: "Informix", icon: "informix" }, + dremio: { type: "jdbc", port: 31010, user: "", label: "Dremio", icon: "dremio" }, + jdbcx: { type: "jdbc", port: 0, user: "", label: "JDBCX", icon: "jdbcx" }, + neo4j: { type: "neo4j", port: 7687, user: "neo4j", label: "Neo4j", icon: "neo4j" }, + cassandra: { type: "cassandra", port: 9042, user: "cassandra", label: "Cassandra", icon: "cassandra" }, + bigquery: { type: "bigquery", port: 443, user: "", label: "BigQuery", icon: "bigquery", host: "https://www.googleapis.com/bigquery/v2" }, + spanner: { type: "spanner", port: 443, user: "", label: "Cloud Spanner", icon: "spanner" }, + kylin: { type: "kylin", port: 7070, user: "ADMIN", label: "Apache Kylin", icon: "kylin" }, + ignite: { type: "ignite", port: 10800, user: "", label: "Apache Ignite", icon: "ignite" }, + ignite3: { type: "ignite3", port: 10800, user: "", label: "Apache Ignite 3", icon: "ignite" }, + sundb: { type: "sundb", port: 22000, user: "root", label: "科蓝 SUNDB", icon: "sundb" }, + oscar: { type: "oscar", port: 2003, user: "SYSDBA", label: "神通 OSCAR", icon: "oscar" }, + jdbc: { type: "jdbc", port: 0, user: "", label: "JDBC", icon: "jdbc" }, + tdengine: { type: "tdengine", port: 6041, user: "root", label: "TDengine", icon: "tdengine" }, + xugu: { type: "xugu", port: 5138, user: "", label: "虚谷 XuguDB", icon: "xugu" }, + iotdb: { type: "iotdb", port: 6667, user: "root", label: "Apache IoTDB", icon: "iotdb" }, + etcd: { type: "etcd", port: 2379, user: "", label: "etcd", icon: "etcd" }, + zookeeper: { type: "zookeeper", port: 2181, user: "", label: "Apache ZooKeeper", icon: "zookeeper" }, + mq: { type: "mq", port: 8080, user: "", label: "Apache Pulsar", icon: "pulsar", host: "127.0.0.1" }, + kafka: { type: "mq", port: 9092, user: "", label: "Apache Kafka", icon: "kafka", host: "127.0.0.1" }, + rocketmq: { type: "mq", port: 9876, user: "", label: "Apache RocketMQ", icon: "rocketmq", host: "127.0.0.1" }, + rabbitmq: { type: "mq", port: 5672, user: "", label: "RabbitMQ", icon: "rabbitmq", host: "127.0.0.1" }, + nacos: { type: "nacos", port: 8848, user: "nacos", label: "Nacos", icon: "nacos", host: "127.0.0.1" }, + consul: { type: "consul", port: 8500, user: "", label: "Consul", icon: "consul", host: "127.0.0.1" }, + mqtt: { type: "mqtt", port: 1883, user: "", label: "MQTT", icon: "mqtt", host: "127.0.0.1" }, + iris: { type: "iris", port: 1972, user: "_SYSTEM", label: "IRIS", icon: "iris" }, + influxdb: { type: "influxdb", port: 8086, user: "", label: "InfluxDB", icon: "InfluxDB" }, + victoriametrics: { type: "victoriametrics", port: 8428, user: "", label: "VictoriaMetrics", icon: "victoriametrics" }, + custom_mysql: { type: "mysql", port: 3306, user: "root", label: "Custom", icon: "mysql", urlParams: "" }, + dolt: { type: "mysql", port: 3306, user: "root", label: "Dolt", icon: "dolt", urlParams: "" }, + custom_postgres: { type: "postgres", port: 5432, user: "postgres", label: "Custom", icon: "postgres", urlParams: "" }, +} as const satisfies Record; + +export const CONNECTION_PROFILE_ICONS = { + mysql: "mysql", + postgres: "postgres", + cloudberry: "cloudberry", + opentenbase: "opentenbase", + redis: "redis", + sqlite: "sqlite", + rqlite: "rqlite", + turso: "turso", + "cloudflare-d1": "cloudflare-d1", + duckdb: "duckdb", + access: "access", + mongodb: "mongodb", + "mongodb-legacy": "mongodb", + dynamodb: "dynamodb", + clickhouse: "clickhouse", + sqlserver: "sqlserver", + oracle: "oracle", + elasticsearch: "elasticsearch", + easysearch: "easysearch", + meilisearch: "meilisearch", + hbase: "hbase", + qdrant: "qdrant", + milvus: "milvus", + weaviate: "weaviate", + chromadb: "chromadb", + mariadb: "mariadb", + tidb: "tidb", + oceanbase: "oceanbase", + "oceanbase-oracle": "oceanbase", + goldendb: "goldendb", + databend: "databend", + tdsql: "tdsql", + polardb: "polardb", + greatsql: "greatsql", + databricks: "databricks", + saphana: "saphana", + teradata: "teradata", + vertica: "vertica", + firebird: "firebird", + exasol: "exasol", + gbase: "gbase", + gbase8a: "gbase", + gbase8s: "gbase", + opengauss: "opengauss", + gaussdb: "gaussdb", + kwdb: "kwdb", + questdb: "questdb", + kingbase: "kingbase", + highgo: "highgo", + uxdb: "uxdb", + yashandb: "yashandb", + vastbase: "vastbase", + doris: "doris", + selectdb: "selectdb", + starrocks: "starrocks", + manticoresearch: "manticoresearch", + redshift: "redshift", + cockroachdb: "cockroachdb", + dm: "dm", + h2: "h2", + "h2-legacy": "h2", + snowflake: "snowflake", + trino: "trino", + prestosql: "prestosql", + hive: "hive", + kyuubi: "kyuubi", + impala: "impala", + spark: "spark", + db2: "db2", + informix: "informix", + dremio: "dremio", + jdbcx: "jdbcx", + neo4j: "neo4j", + cassandra: "cassandra", + bigquery: "bigquery", + spanner: "spanner", + kylin: "kylin", + ignite: "ignite", + ignite3: "ignite", + sundb: "sundb", + oscar: "oscar", + jdbc: "jdbc", + tdengine: "tdengine", + xugu: "xugu", + iotdb: "iotdb", + etcd: "etcd", + zookeeper: "zookeeper", + mq: "mq", + kafka: "kafka", + rocketmq: "rocketmq", + rabbitmq: "rabbitmq", + nacos: "nacos", + consul: "consul", + mqtt: "mqtt", + iris: "iris", + influxdb: "influxdb", + victoriametrics: "victoriametrics", + custom_mysql: "mysql", + dolt: "dolt", + custom_postgres: "postgres", +} as const satisfies Record; + +export const CONNECTION_PICKER_OPTIONS = [ + { value: "mysql", label: "MySQL", category: "sql" }, + { value: "postgres", label: "PostgreSQL", category: "sql" }, + { value: "cloudberry", label: "Apache Cloudberry", category: "analytics" }, + { value: "opentenbase", label: "OpenTenBase", category: "domestic" }, + { value: "redis", label: "Redis", category: "document" }, + { value: "sqlite", label: "SQLite", category: "lightweight" }, + { value: "rqlite", label: "RQLite", category: "lightweight" }, + { value: "turso", label: "Turso", category: "lightweight" }, + { value: "cloudflare-d1", label: "Cloudflare D1", category: "lightweight" }, + { value: "duckdb", label: "DuckDB", category: "lightweight" }, + { value: "access", label: "Microsoft Access", category: "lightweight" }, + { value: "mongodb", label: "MongoDB", category: "document" }, + { value: "dynamodb", label: "Amazon DynamoDB", category: "document" }, + { value: "clickhouse", label: "ClickHouse", category: "analytics" }, + { value: "sqlserver", label: "SQL Server", category: "sql" }, + { value: "oracle", label: "Oracle", category: "sql" }, + { value: "elasticsearch", label: "Elasticsearch", category: "document" }, + { value: "easysearch", label: "Easysearch", category: "document" }, + { value: "meilisearch", label: "Meilisearch", category: "document" }, + { value: "hbase", label: "Apache HBase", category: "document" }, + { value: "qdrant", label: "Qdrant", category: "graph_ai" }, + { value: "milvus", label: "Milvus", category: "graph_ai" }, + { value: "weaviate", label: "Weaviate", category: "graph_ai" }, + { value: "chromadb", label: "ChromaDB", category: "graph_ai" }, + { value: "mariadb", label: "MariaDB", category: "sql" }, + { value: "tidb", label: "TiDB", category: "domestic" }, + { value: "oceanbase", label: "OceanBase", category: "domestic" }, + { value: "goldendb", label: "金篆 GoldenDB", category: "domestic" }, + { value: "databend", label: "Databend", category: "analytics" }, + { value: "tdsql", label: "TDSQL", category: "domestic" }, + { value: "polardb", label: "PolarDB", category: "domestic" }, + { value: "greatsql", label: "GreatSQL", category: "domestic" }, + { value: "databricks", label: "Databricks SQL", category: "analytics" }, + { value: "saphana", label: "SAP HANA", category: "analytics" }, + { value: "teradata", label: "Teradata", category: "analytics" }, + { value: "vertica", label: "Vertica", category: "analytics" }, + { value: "firebird", label: "Firebird", category: "sql" }, + { value: "exasol", label: "Exasol", category: "analytics" }, + { value: "gbase", label: "南大通用 GBase", category: "domestic" }, + { value: "opengauss", label: "openGauss", category: "domestic" }, + { value: "gaussdb", label: "GaussDB", category: "domestic" }, + { value: "kwdb", label: "KWDB", category: "domestic" }, + { value: "questdb", label: "QuestDB", category: "timeseries" }, + { value: "kingbase", label: "金仓KingbaseES", category: "domestic" }, + { value: "highgo", label: "瀚高 HighGo", category: "domestic" }, + { value: "uxdb", label: "优炫 UXDB", category: "domestic" }, + { value: "yashandb", label: "崖山 YashanDB", category: "domestic" }, + { value: "vastbase", label: "海量 Vastbase", category: "domestic" }, + { value: "doris", label: "Doris", category: "analytics" }, + { value: "selectdb", label: "SelectDB", category: "analytics" }, + { value: "starrocks", label: "StarRocks", category: "analytics" }, + { value: "manticoresearch", label: "Manticore Search", category: "document" }, + { value: "redshift", label: "Redshift", category: "analytics" }, + { value: "cockroachdb", label: "CockroachDB", category: "sql" }, + { value: "dm", label: "达梦 Dameng", category: "domestic" }, + { value: "h2", label: "H2", category: "lightweight" }, + { value: "snowflake", label: "Snowflake", category: "analytics" }, + { value: "trino", label: "Trino", category: "analytics" }, + { value: "prestosql", label: "PrestoSQL", category: "analytics" }, + { value: "hive", label: "Hive", category: "analytics" }, + { value: "kyuubi", label: "Apache Kyuubi", category: "analytics" }, + { value: "impala", label: "Apache Impala", category: "analytics" }, + { value: "spark", label: "Apache Spark", category: "analytics" }, + { value: "db2", label: "DB2", category: "sql" }, + { value: "informix", label: "Informix", category: "sql" }, + { value: "dremio", label: "Dremio", category: "analytics" }, + { value: "jdbcx", label: "JDBCX", category: "sql" }, + { value: "neo4j", label: "Neo4j", category: "graph_ai" }, + { value: "cassandra", label: "Cassandra", category: "document" }, + { value: "bigquery", label: "BigQuery", category: "analytics" }, + { value: "spanner", label: "Cloud Spanner", category: "sql" }, + { value: "kylin", label: "Kylin", category: "analytics" }, + { value: "ignite", label: "Apache Ignite", category: "analytics" }, + { value: "ignite3", label: "Apache Ignite 3", category: "analytics" }, + { value: "sundb", label: "科蓝 SUNDB", category: "domestic" }, + { value: "oscar", label: "神通 OSCAR", category: "domestic" }, + { value: "tdengine", label: "TDengine", category: "timeseries" }, + { value: "xugu", label: "虚谷 XuguDB", category: "domestic" }, + { value: "iotdb", label: "Apache IoTDB", category: "timeseries" }, + { value: "etcd", label: "etcd", category: "registry_config" }, + { value: "zookeeper", label: "Apache ZooKeeper", category: "registry_config" }, + { value: "mq", label: "Apache Pulsar", category: "mq" }, + { value: "kafka", label: "Apache Kafka", category: "mq" }, + { value: "rocketmq", label: "Apache RocketMQ", category: "mq" }, + { value: "rabbitmq", label: "RabbitMQ", category: "mq" }, + { value: "nacos", label: "Nacos", category: "registry_config" }, + { value: "consul", label: "Consul", category: "registry_config" }, + { value: "mqtt", label: "MQTT", category: "mq" }, + { value: "iris", label: "IRIS", category: "sql" }, + { value: "influxdb", label: "InfluxDB", category: "timeseries" }, + { value: "victoriametrics", label: "VictoriaMetrics", category: "timeseries" }, + { value: "custom_mysql", label: "Custom (MySQL)", category: "sql" }, + { value: "dolt", label: "Dolt", category: "sql" }, + { value: "custom_postgres", label: "Custom (PostgreSQL)", category: "sql" }, +] as const satisfies readonly ConnectionPickerOption[]; diff --git a/apps/desktop/src/types/generated/databaseTypes.ts b/apps/desktop/src/types/generated/databaseTypes.ts new file mode 100644 index 0000000000..dc99c2bdf6 --- /dev/null +++ b/apps/desktop/src/types/generated/databaseTypes.ts @@ -0,0 +1,83 @@ +// Generated by scripts/sync-connection-types.mjs. Do not edit manually. +export const DATABASE_TYPES = [ + "mysql", + "postgres", + "sqlite", + "rqlite", + "turso", + "cloudflare-d1", + "redis", + "duckdb", + "clickhouse", + "sqlserver", + "mongodb", + "dynamodb", + "oracle", + "elasticsearch", + "easysearch", + "meilisearch", + "hbase", + "qdrant", + "chromadb", + "milvus", + "weaviate", + "doris", + "starrocks", + "manticoresearch", + "redshift", + "dameng", + "kingbase", + "highgo", + "uxdb", + "vastbase", + "goldendb", + "databend", + "gaussdb", + "kwdb", + "yashandb", + "databricks", + "saphana", + "teradata", + "vertica", + "firebird", + "exasol", + "opengauss", + "questdb", + "oceanbase-oracle", + "gbase", + "access", + "h2", + "snowflake", + "trino", + "prestosql", + "hive", + "kyuubi", + "impala", + "db2", + "informix", + "neo4j", + "cassandra", + "bigquery", + "spanner", + "kylin", + "ignite", + "ignite3", + "sundb", + "oscar", + "tdengine", + "xugu", + "etcd", + "zookeeper", + "nacos", + "consul", + "mq", + "mqtt", + "iotdb", + "iris", + "influxdb", + "victoriametrics", + "jdbc", + "spark", +] as const; + +export type DatabaseType = (typeof DATABASE_TYPES)[number]; diff --git a/apps/desktop/vite.config.ts b/apps/desktop/vite.config.ts index 9d86f534f0..fea4337f6e 100644 --- a/apps/desktop/vite.config.ts +++ b/apps/desktop/vite.config.ts @@ -3,6 +3,7 @@ import vue from "@vitejs/plugin-vue"; import tailwindcss from "@tailwindcss/vite"; import path from "path"; import { publicBasePathRedirectPlugin } from "./vitePublicBasePathRedirect"; +import { connectionTypesPlugin } from "./viteConnectionTypesPlugin.ts"; const host = process.env.TAURI_DEV_HOST; const isTauri = !!host || !!process.env.TAURI_ENV_ARCH; @@ -64,7 +65,7 @@ const backendUrl = process.env.DBX_BACKEND_URL || "http://localhost:4224"; export default defineConfig(async () => ({ root: import.meta.dirname, base: viteBase, - plugins: [publicBasePathRedirectPlugin(publicBasePath), vue(), tailwindcss()], + plugins: [connectionTypesPlugin(), publicBasePathRedirectPlugin(publicBasePath), vue(), tailwindcss()], resolve: { alias: { "@": path.resolve(import.meta.dirname, "./src"), diff --git a/apps/desktop/vite.docs-export.config.ts b/apps/desktop/vite.docs-export.config.ts index 5c173d1be1..02da55487c 100644 --- a/apps/desktop/vite.docs-export.config.ts +++ b/apps/desktop/vite.docs-export.config.ts @@ -4,6 +4,7 @@ import path from "node:path"; import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import tailwindcss from "@tailwindcss/vite"; +import { connectionTypesPlugin } from "./viteConnectionTypesPlugin.ts"; const repoRoot = path.resolve(__dirname, "../.."); const assetsDir = path.join(repoRoot, "crates/dbx-core/assets"); @@ -128,10 +129,7 @@ function exportBundlePlugin() { if (name.endsWith(".css") && typeof chunk.source === "string") chunk.source = fontFace + chunk.source; } - writeFileSync( - path.join(assetsDir, "docs-export.manifest.json"), - `${JSON.stringify({ sources: Object.fromEntries(Object.entries(sources).sort()), deps: Object.fromEntries(Object.entries(deps).sort()) }, null, 2)}\n`, - ); + writeFileSync(path.join(assetsDir, "docs-export.manifest.json"), `${JSON.stringify({ sources: Object.fromEntries(Object.entries(sources).sort()), deps: Object.fromEntries(Object.entries(deps).sort()) }, null, 2)}\n`); }, }; } @@ -141,7 +139,7 @@ export default defineConfig({ // The app's public/ holds the font files this build inlines. Left on, Vite // would copy all of them into crates/dbx-core/assets beside the bundle. publicDir: false, - plugins: [vue(), tailwindcss(), exportBundlePlugin()], + plugins: [connectionTypesPlugin(), vue(), tailwindcss(), exportBundlePlugin()], resolve: { alias: { "@": path.resolve(__dirname, "src") } }, build: { outDir: assetsDir, diff --git a/apps/desktop/viteConnectionTypesPlugin.ts b/apps/desktop/viteConnectionTypesPlugin.ts new file mode 100644 index 0000000000..1073c367ec --- /dev/null +++ b/apps/desktop/viteConnectionTypesPlugin.ts @@ -0,0 +1,43 @@ +import { execFileSync } from "node:child_process"; +import { extname, relative, resolve } from "node:path"; +import type { Plugin, ViteDevServer } from "vite"; + +const repoRoot = resolve(import.meta.dirname, "../.."); +const connectionTypesDirectory = resolve(repoRoot, "plugins/connection-types"); +const generator = resolve(repoRoot, "scripts/sync-connection-types.mjs"); + +function syncConnectionTypes() { + execFileSync(process.execPath, [generator], { cwd: repoRoot, stdio: "inherit" }); +} + +function isConnectionTypeDescriptor(path: string): boolean { + const relativePath = relative(connectionTypesDirectory, path); + return relativePath !== "" && !relativePath.startsWith("..") && [".yaml", ".yml"].includes(extname(path)); +} + +function watchConnectionTypes(server: ViteDevServer) { + let timer: ReturnType | undefined; + server.watcher.add(connectionTypesDirectory); + server.watcher.on("all", (_event, path) => { + if (!isConnectionTypeDescriptor(path)) return; + if (timer) clearTimeout(timer); + timer = setTimeout(() => { + try { + syncConnectionTypes(); + } catch (error) { + server.config.logger.error(error instanceof Error ? error.message : String(error)); + } + }, 50); + }); + server.httpServer?.once("close", () => { + if (timer) clearTimeout(timer); + }); +} + +export function connectionTypesPlugin(): Plugin { + return { + name: "dbx-connection-types", + configResolved: syncConnectionTypes, + configureServer: watchConnectionTypes, + }; +} diff --git a/crates/dbx-core/Cargo.toml b/crates/dbx-core/Cargo.toml index 6d23e7b738..9604a6d4bd 100644 --- a/crates/dbx-core/Cargo.toml +++ b/crates/dbx-core/Cargo.toml @@ -94,3 +94,8 @@ windows-sys = { version = "0.61", features = ["Win32_Storage_FileSystem", "Win32 mysql_common = { git = "https://github.com/t8y2/rust_mysql_common.git", rev = "47740d85a8277167a5717afac785d37b46a36296", default-features = false } tokio = { version = "1", features = ["test-util"] } tokio-openssl = "0.6" + +[build-dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +serde_yaml_ng = "0.10" diff --git a/crates/dbx-core/assets/database-drivers.manifest.json b/crates/dbx-core/assets/database-drivers.manifest.json index 35a9d57954..7bbf9ac1bf 100644 --- a/crates/dbx-core/assets/database-drivers.manifest.json +++ b/crates/dbx-core/assets/database-drivers.manifest.json @@ -4,12 +4,16 @@ { "dbType": "mysql", "label": "MySQL", + "dialect": "MySQL", "runtimeMode": "native", "mcpMode": "direct", "singleConnectionPool": false, "metadataConnectionScoped": true, "skipTcpProbe": false, "defaultPort": 3306, + "traits": { + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -33,12 +37,20 @@ { "dbType": "postgres", "label": "PostgreSQL", + "dialect": "PostgreSQL", "runtimeMode": "native", "mcpMode": "direct", "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": false, "defaultPort": 5432, + "traits": { + "schemaAware": true, + "treeSchema": true, + "pgVacuum": true, + "pgLikeStructure": true, + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -62,11 +74,16 @@ { "dbType": "sqlite", "label": "SQLite", + "dialect": "SQLite", "runtimeMode": "file", "mcpMode": "direct", "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, + "localFile": true, + "traits": { + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -90,12 +107,16 @@ { "dbType": "rqlite", "label": "RQLite", + "dialect": "Rqlite", "runtimeMode": "native", "mcpMode": "direct", "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": false, "defaultPort": 4001, + "traits": { + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -116,15 +137,52 @@ "driverManagement": false } }, + { + "dbType": "turso", + "label": "Turso", + "dialect": "Turso", + "runtimeMode": "native", + "mcpMode": "direct", + "singleConnectionPool": true, + "metadataConnectionScoped": false, + "skipTcpProbe": true, + "defaultPort": 443, + "traits": { + "diagramSql": true + }, + "supportLevel": "operate", + "capabilities": { + "queryExecution": true, + "metadataBrowse": true, + "objectBrowser": true, + "objectSource": true, + "schemaSearch": true, + "diagram": true, + "tableDataEdit": true, + "tableStructureEdit": true, + "tableImport": true, + "dataTransfer": true, + "sqlFileExecution": true, + "databaseCreate": false, + "fieldLineage": true, + "sqlExplain": false, + "userAdmin": false, + "driverManagement": false + } + }, { "dbType": "cloudflare-d1", "label": "Cloudflare D1", + "dialect": "SQLite", "runtimeMode": "native", "mcpMode": "bridge", "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 443, + "traits": { + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -177,11 +235,25 @@ { "dbType": "duckdb", "label": "DuckDB", + "dialect": "DuckDB", "runtimeMode": "file", "mcpMode": "bridge", + "managedDrivers": [ + { + "key": "duckdb", + "label": "DuckDB", + "storeVisible": true, + "storeOrder": 43 + } + ], "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, + "localFile": true, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -205,6 +277,7 @@ { "dbType": "clickhouse", "label": "ClickHouse", + "dialect": "ClickHouse", "runtimeMode": "native", "mcpMode": "bridge", "singleConnectionPool": false, @@ -234,19 +307,29 @@ { "dbType": "sqlserver", "label": "SQL Server", + "dialect": "SQL Server", "runtimeMode": "native", "mcpMode": "bridge", + "driverProfiles": [ + { + "profile": "sqlserver-legacy", + "agentKey": "sqlserver-legacy", + "label": "SQL Server legacy compatibility component", + "storeVisible": true, + "storeOrder": 47 + } + ], "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": false, "defaultPort": 1433, + "traits": { + "schemaAware": true, + "databaseSchemaQualified": true, + "treeSchema": true, + "diagramSql": true + }, "supportLevel": "operate", - "driverProfiles": [ - { - "profile": "sqlserver-legacy", - "agentKey": "sqlserver-legacy" - } - ], "capabilities": { "queryExecution": true, "metadataBrowse": true, @@ -272,6 +355,16 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "mongodb", + "driverStoreVisible": true, + "driverStoreOrder": 41, + "driverProfiles": [ + { + "profile": "mongodb-legacy", + "agentKey": "mongodb", + "label": "MongoDB (Legacy)", + "storeVisible": false + } + ], "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, @@ -328,13 +421,37 @@ { "dbType": "oracle", "label": "Oracle", + "dialect": "Oracle", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "oracle", + "driverStoreVisible": true, + "driverStoreOrder": 18, + "driverProfiles": [ + { + "profile": "oracle-legacy", + "agentKey": "oracle", + "label": "Oracle", + "storeVisible": false + }, + { + "profile": "oracle-10g", + "agentKey": "oracle", + "label": "Oracle", + "storeVisible": false + } + ], "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 1521, + "traits": { + "schemaAware": true, + "singleDatabase": true, + "clearableQuerySchema": true, + "fetchFirst": true, + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -590,6 +707,7 @@ { "dbType": "doris", "label": "Doris", + "dialect": "Doris", "runtimeMode": "native", "mcpMode": "direct", "singleConnectionPool": false, @@ -619,6 +737,7 @@ { "dbType": "starrocks", "label": "StarRocks", + "dialect": "StarRocks", "runtimeMode": "native", "mcpMode": "direct", "singleConnectionPool": false, @@ -648,6 +767,7 @@ { "dbType": "manticoresearch", "label": "Manticore Search", + "dialect": "ManticoreSearch", "runtimeMode": "native", "mcpMode": "direct", "singleConnectionPool": false, @@ -677,12 +797,19 @@ { "dbType": "redshift", "label": "Redshift", + "dialect": "Redshift", "runtimeMode": "native", "mcpMode": "direct", "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": false, "defaultPort": 5439, + "traits": { + "schemaAware": true, + "treeSchema": true, + "pgLikeStructure": true, + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -706,13 +833,23 @@ { "dbType": "dameng", "label": "达梦 DM8", + "dialect": "Dameng", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "dameng", + "driverStoreVisible": true, + "driverStoreOrder": 1, "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 5236, + "traits": { + "schemaAware": true, + "singleDatabase": true, + "clearableQuerySchema": true, + "fetchFirst": true, + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -736,13 +873,21 @@ { "dbType": "kingbase", "label": "金仓KingbaseES", + "dialect": "Kingbase", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "kingbase", + "driverStoreVisible": true, + "driverStoreOrder": 2, "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 54321, + "traits": { + "schemaAware": true, + "treeSchema": true, + "pgVacuum": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -766,13 +911,21 @@ { "dbType": "highgo", "label": "瀚高 HighGo", + "dialect": "HighGo", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "highgo", + "driverStoreVisible": true, + "driverStoreOrder": 3, "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 5866, + "traits": { + "schemaAware": true, + "treeSchema": true, + "pgVacuum": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -796,13 +949,21 @@ { "dbType": "uxdb", "label": "优炫 UXDB", + "dialect": "PostgreSQL", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "uxdb", + "driverStoreVisible": true, + "driverStoreOrder": 4, "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 52025, + "traits": { + "schemaAware": true, + "treeSchema": true, + "pgVacuum": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -826,13 +987,21 @@ { "dbType": "vastbase", "label": "海量 Vastbase", + "dialect": "Vastbase", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "vastbase", + "driverStoreVisible": true, + "driverStoreOrder": 5, "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 5432, + "traits": { + "schemaAware": true, + "treeSchema": true, + "pgVacuum": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -856,9 +1025,12 @@ { "dbType": "goldendb", "label": "金篆 GoldenDB", + "dialect": "GoldenDB", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "goldendb", + "driverStoreVisible": true, + "driverStoreOrder": 6, "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, @@ -886,13 +1058,19 @@ { "dbType": "databend", "label": "Databend", + "dialect": "Databend", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "databend", + "driverStoreVisible": true, + "driverStoreOrder": 7, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 8000, + "traits": { + "schemaAware": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -916,12 +1094,21 @@ { "dbType": "gaussdb", "label": "GaussDB", + "dialect": "GaussDB", "runtimeMode": "native", "mcpMode": "bridge", "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": false, - "defaultPort": 8000, + "defaultPort": 5432, + "traits": { + "schemaAware": true, + "clearableQuerySchema": true, + "treeSchema": true, + "pgVacuum": true, + "pgLikeStructure": true, + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -945,12 +1132,20 @@ { "dbType": "kwdb", "label": "KWDB", + "dialect": "KwDB", "runtimeMode": "native", "mcpMode": "direct", "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": false, "defaultPort": 26257, + "traits": { + "schemaAware": true, + "treeSchema": true, + "pgVacuum": true, + "pgLikeStructure": true, + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -974,13 +1169,20 @@ { "dbType": "yashandb", "label": "崖山 YashanDB", + "dialect": "YashanDB", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "yashandb", + "driverStoreVisible": true, + "driverStoreOrder": 35, "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 1688, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1007,10 +1209,16 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "databricks", + "driverStoreVisible": true, + "driverStoreOrder": 8, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 443, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1037,10 +1245,16 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "saphana", + "driverStoreVisible": true, + "driverStoreOrder": 9, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 30015, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1067,10 +1281,16 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "teradata", + "driverStoreVisible": true, + "driverStoreOrder": 10, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 1025, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1094,13 +1314,20 @@ { "dbType": "vertica", "label": "Vertica", + "dialect": "Vertica", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "vertica", + "driverStoreVisible": true, + "driverStoreOrder": 11, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 5433, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1124,13 +1351,19 @@ { "dbType": "firebird", "label": "Firebird", + "dialect": "Firebird", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "firebird", + "driverStoreVisible": true, + "driverStoreOrder": 12, "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 3050, + "traits": { + "singleDatabase": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1154,13 +1387,20 @@ { "dbType": "exasol", "label": "Exasol", + "dialect": "Exasol", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "exasol", + "driverStoreVisible": true, + "driverStoreOrder": 13, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 8563, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1184,12 +1424,20 @@ { "dbType": "opengauss", "label": "openGauss", + "dialect": "openGauss", "runtimeMode": "native", "mcpMode": "bridge", "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": false, "defaultPort": 5432, + "traits": { + "schemaAware": true, + "treeSchema": true, + "pgVacuum": true, + "pgLikeStructure": true, + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1213,12 +1461,18 @@ { "dbType": "questdb", "label": "QuestDB", + "dialect": "QuestDB", "runtimeMode": "native", "mcpMode": "direct", "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": false, "defaultPort": 8812, + "traits": { + "singleDatabase": true, + "pgLikeStructure": true, + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1242,13 +1496,23 @@ { "dbType": "oceanbase-oracle", "label": "OceanBase Oracle Mode", + "dialect": "OceanBase", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "oceanbase-oracle", + "driverStoreVisible": true, + "driverStoreOrder": 14, "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 2883, + "traits": { + "schemaAware": true, + "singleDatabase": true, + "clearableQuerySchema": true, + "treeSchema": true, + "diagramSql": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1272,25 +1536,36 @@ { "dbType": "gbase", "label": "南大通用 GBase 8a", + "dialect": "GBase", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "gbase8a", + "driverStoreVisible": true, + "driverStoreOrder": 15, + "driverProfiles": [ + { + "profile": "gbase8s", + "agentKey": "gbase8s", + "label": "南大通用 GBase 8s", + "storeVisible": true, + "storeOrder": 16 + }, + { + "profile": "gbase8a", + "agentKey": "gbase8a", + "label": "南大通用 GBase 8a", + "storeVisible": true, + "storeOrder": 15 + } + ], "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 5258, - "driverProfiles": [ - { - "profile": "gbase8s", - "label": "南大通用 GBase 8s", - "agentKey": "gbase8s" - }, - { - "profile": "gbase8a", - "label": "南大通用 GBase 8a", - "agentKey": "gbase8a" - } - ], + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1314,12 +1589,19 @@ { "dbType": "access", "label": "Microsoft Access", + "dialect": "Access", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "access", + "driverStoreVisible": true, + "driverStoreOrder": 17, "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, + "localFile": true, + "traits": { + "singleDatabase": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1343,13 +1625,54 @@ { "dbType": "h2", "label": "H2", + "dialect": "H2", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "h2", + "driverStoreVisible": true, + "driverStoreOrder": 19, + "driverProfiles": [ + { + "profile": "h2-legacy", + "agentKey": "h2", + "packageKey": "h2-legacy", + "label": "H2 2.1 Legacy", + "storeVisible": false + }, + { + "profile": "h2-v1", + "agentKey": "h2", + "label": "H2 1.x", + "storeVisible": false + }, + { + "profile": "h2-v2", + "agentKey": "h2", + "label": "H2 2.0–2.1", + "storeVisible": false + }, + { + "profile": "h2-v3", + "agentKey": "h2", + "label": "H2 2.2+", + "storeVisible": false + }, + { + "profile": "h2-custom", + "agentKey": "h2", + "label": "H2 Custom JAR", + "storeVisible": false + } + ], "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, + "localFile": true, "defaultPort": 9092, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1376,10 +1699,15 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "snowflake", + "driverStoreVisible": true, + "driverStoreOrder": 20, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 443, + "traits": { + "schemaAware": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1406,10 +1734,17 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "trino", + "driverStoreVisible": true, + "driverStoreOrder": 21, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 8080, + "traits": { + "schemaAware": true, + "databaseSchemaQualified": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1439,6 +1774,11 @@ "metadataConnectionScoped": false, "skipTcpProbe": false, "defaultPort": 8080, + "traits": { + "schemaAware": true, + "databaseSchemaQualified": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1465,10 +1805,15 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "hive", + "driverStoreVisible": true, + "driverStoreOrder": 22, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 10000, + "traits": { + "schemaAware": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1495,10 +1840,14 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "hive", + "driverStoreVisible": false, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 10009, + "traits": { + "schemaAware": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1525,10 +1874,14 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "hive", + "driverStoreVisible": false, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 21050, + "traits": { + "schemaAware": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1555,10 +1908,16 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "db2", + "driverStoreVisible": true, + "driverStoreOrder": 24, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 50000, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1582,13 +1941,20 @@ { "dbType": "informix", "label": "IBM Informix", + "dialect": "Informix", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "informix", + "driverStoreVisible": true, + "driverStoreOrder": 25, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 9088, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1615,6 +1981,8 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "neo4j", + "driverStoreVisible": true, + "driverStoreOrder": 26, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, @@ -1645,6 +2013,8 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "cassandra", + "driverStoreVisible": true, + "driverStoreOrder": 27, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, @@ -1675,6 +2045,8 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "bigquery", + "driverStoreVisible": true, + "driverStoreOrder": 28, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, @@ -1704,10 +2076,16 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "spanner", + "driverStoreVisible": true, + "driverStoreOrder": 29, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 443, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1734,6 +2112,8 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "kylin", + "driverStoreVisible": true, + "driverStoreOrder": 30, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, @@ -1764,10 +2144,16 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "ignite", + "driverStoreVisible": true, + "driverStoreOrder": 31, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 10800, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "understand", "capabilities": { "queryExecution": true, @@ -1794,10 +2180,16 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "ignite3", + "driverStoreVisible": true, + "driverStoreOrder": 32, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 10800, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "understand", "capabilities": { "queryExecution": true, @@ -1821,9 +2213,12 @@ { "dbType": "sundb", "label": "科蓝 SUNDB", + "dialect": "SunDB", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "sundb", + "driverStoreVisible": true, + "driverStoreOrder": 33, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, @@ -1854,10 +2249,16 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "oscar", + "driverStoreVisible": true, + "driverStoreOrder": 34, "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 2003, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "browse", "capabilities": { "queryExecution": true, @@ -1884,6 +2285,8 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "tdengine", + "driverStoreVisible": true, + "driverStoreOrder": 36, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, @@ -1911,13 +2314,20 @@ { "dbType": "xugu", "label": "虚谷 XuguDB", + "dialect": "Xugu", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "xugu", + "driverStoreVisible": true, + "driverStoreOrder": 37, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 5138, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -1944,6 +2354,8 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "etcd", + "driverStoreVisible": true, + "driverStoreOrder": 39, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, @@ -1974,6 +2386,8 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "zookeeper", + "driverStoreVisible": true, + "driverStoreOrder": 40, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, @@ -1998,6 +2412,67 @@ "driverManagement": true } }, + { + "dbType": "nacos", + "label": "Nacos", + "runtimeMode": "native", + "mcpMode": "unsupported", + "singleConnectionPool": false, + "metadataConnectionScoped": false, + "skipTcpProbe": false, + "defaultPort": 8848, + "formKind": "nacos", + "supportLevel": "connect", + "specializedSurface": true, + "capabilities": { + "queryExecution": false, + "metadataBrowse": false, + "objectBrowser": false, + "objectSource": false, + "schemaSearch": false, + "diagram": false, + "tableDataEdit": false, + "tableStructureEdit": false, + "tableImport": false, + "dataTransfer": false, + "sqlFileExecution": false, + "databaseCreate": false, + "fieldLineage": false, + "sqlExplain": false, + "userAdmin": false, + "driverManagement": false + } + }, + { + "dbType": "consul", + "label": "Consul", + "runtimeMode": "native", + "mcpMode": "unsupported", + "singleConnectionPool": false, + "metadataConnectionScoped": false, + "skipTcpProbe": false, + "defaultPort": 8500, + "supportLevel": "connect", + "specializedSurface": true, + "capabilities": { + "queryExecution": false, + "metadataBrowse": false, + "objectBrowser": false, + "objectSource": false, + "schemaSearch": false, + "diagram": false, + "tableDataEdit": false, + "tableStructureEdit": false, + "tableImport": false, + "dataTransfer": false, + "sqlFileExecution": false, + "databaseCreate": false, + "fieldLineage": false, + "sqlExplain": false, + "userAdmin": false, + "driverManagement": false + } + }, { "dbType": "mq", "label": "Message Queue", @@ -2007,21 +2482,28 @@ "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 8080, + "formKind": "mq", "driverProfiles": [ { "profile": "kafka", "label": "Apache Kafka", - "agentKey": "kafka" + "agentKey": "kafka", + "storeVisible": true, + "storeOrder": 44 }, { "profile": "rocketmq", "label": "Apache RocketMQ", - "agentKey": "rocketmq" + "agentKey": "rocketmq", + "storeVisible": true, + "storeOrder": 45 }, { "profile": "rabbitmq", "label": "RabbitMQ", - "agentKey": "rabbitmq" + "agentKey": "rabbitmq", + "storeVisible": true, + "storeOrder": 46 } ], "supportLevel": "connect", @@ -2044,16 +2526,52 @@ "driverManagement": true } }, + { + "dbType": "mqtt", + "label": "MQTT", + "runtimeMode": "native", + "mcpMode": "unsupported", + "singleConnectionPool": false, + "metadataConnectionScoped": false, + "skipTcpProbe": true, + "defaultPort": 1883, + "formKind": "mqtt", + "supportLevel": "connect", + "specializedSurface": true, + "capabilities": { + "queryExecution": false, + "metadataBrowse": false, + "objectBrowser": false, + "objectSource": false, + "schemaSearch": false, + "diagram": false, + "tableDataEdit": false, + "tableStructureEdit": false, + "tableImport": false, + "dataTransfer": false, + "sqlFileExecution": false, + "databaseCreate": false, + "fieldLineage": false, + "sqlExplain": false, + "userAdmin": false, + "driverManagement": false + } + }, { "dbType": "iotdb", "label": "Apache IoTDB", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "iotdb", + "driverStoreVisible": true, + "driverStoreOrder": 38, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 6667, + "traits": { + "schemaAware": true + }, "supportLevel": "understand", "capabilities": { "queryExecution": true, @@ -2077,13 +2595,20 @@ { "dbType": "iris", "label": "InterSystems IRIS", + "dialect": "Iris", "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "iris", + "driverStoreVisible": true, + "driverStoreOrder": 42, "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 1972, + "traits": { + "schemaAware": true, + "treeSchema": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, @@ -2110,6 +2635,7 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "influxdb", + "driverStoreVisible": false, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, @@ -2143,6 +2669,9 @@ "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 8428, + "traits": { + "singleDatabase": true + }, "supportLevel": "browse", "capabilities": { "queryExecution": true, @@ -2171,6 +2700,12 @@ "singleConnectionPool": true, "metadataConnectionScoped": false, "skipTcpProbe": true, + "formKind": "jdbc", + "traits": { + "schemaAware": true, + "treeSchema": true, + "databaseObjectTree": true + }, "supportLevel": "browse", "capabilities": { "queryExecution": true, @@ -2197,10 +2732,15 @@ "runtimeMode": "agent", "mcpMode": "bridge", "agentKey": "spark", + "driverStoreVisible": true, + "driverStoreOrder": 23, "singleConnectionPool": false, "metadataConnectionScoped": false, "skipTcpProbe": true, "defaultPort": 10015, + "traits": { + "schemaAware": true + }, "supportLevel": "operate", "capabilities": { "queryExecution": true, diff --git a/crates/dbx-core/build.rs b/crates/dbx-core/build.rs index 3f8e5da0a8..9b0f43456b 100644 --- a/crates/dbx-core/build.rs +++ b/crates/dbx-core/build.rs @@ -1,29 +1,51 @@ +use std::collections::HashSet; use std::env; -use std::path::Path; +use std::path::{Path, PathBuf}; + +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct DatabaseDescriptor { + schema_version: u32, + order: u32, + db_type: String, + rust_variant: String, +} fn main() { let cargo_manifest_dir_str = env::var("CARGO_MANIFEST_DIR").unwrap(); let cargo_manifest_dir = Path::new(&cargo_manifest_dir_str); - let dialects_dir = cargo_manifest_dir.join("..").join("..").join("plugins").join("dialects"); - let dialects_dir = std::fs::canonicalize(&dialects_dir).unwrap_or(dialects_dir); - + let plugins_dir = cargo_manifest_dir.join("..").join("..").join("plugins"); let out_dir_str = env::var("OUT_DIR").unwrap(); - let dest_path = Path::new(&out_dir_str).join("core_dialects.rs"); + let out_dir = Path::new(&out_dir_str); - let mut entries: Vec<_> = std::fs::read_dir(&dialects_dir) - .expect("Cannot read plugins/dialects directory") - .filter_map(|e| e.ok()) - .filter(|e| e.path().extension().is_some_and(|ext| ext == "yaml" || ext == "yml")) + generate_core_dialects(&plugins_dir.join("dialects"), out_dir); + generate_connection_type_registry(&plugins_dir.join("connection-types"), out_dir); +} + +fn yaml_entries(directory: &Path) -> Vec { + let mut entries: Vec<_> = std::fs::read_dir(directory) + .unwrap_or_else(|_| panic!("Cannot read {} directory", directory.display())) + .filter_map(|entry| entry.ok()) + .map(|entry| entry.path()) + .filter(|path| path.extension().is_some_and(|extension| extension == "yaml" || extension == "yml")) .collect(); - entries.sort_by_key(|e| e.file_name()); + entries.sort(); + entries +} + +fn generate_core_dialects(dialects_dir: &Path, out_dir: &Path) { + let dialects_dir = std::fs::canonicalize(dialects_dir).unwrap_or_else(|_| dialects_dir.to_path_buf()); + let dest_path = out_dir.join("core_dialects.rs"); + let entries = yaml_entries(&dialects_dir); // Watch the directory itself so additions/removals of dialect files trigger a rebuild. println!("cargo::rerun-if-changed={}", dialects_dir.to_str().unwrap()); let mut code = String::from("{\n"); - for entry in &entries { - let path = entry.path(); + for path in &entries { let canonical = std::fs::canonicalize(&path).unwrap_or_else(|_| path.clone()); let file_name = path.file_stem().unwrap().to_str().unwrap(); let path_str = canonical.to_str().unwrap(); @@ -49,3 +71,69 @@ fn main() { std::fs::write(&dest_path, code).expect("Failed to write core_dialects.rs"); } + +fn generate_connection_type_registry(connection_types_dir: &Path, out_dir: &Path) { + let connection_types_dir = + std::fs::canonicalize(connection_types_dir).unwrap_or_else(|_| connection_types_dir.to_path_buf()); + println!("cargo::rerun-if-changed={}", connection_types_dir.display()); + + let mut descriptors = Vec::new(); + let mut db_types = HashSet::new(); + let mut rust_variants = HashSet::new(); + let mut orders = HashSet::new(); + + for path in yaml_entries(&connection_types_dir) { + println!("cargo::rerun-if-changed={}", path.display()); + let content = std::fs::read_to_string(&path).unwrap_or_else(|_| panic!("Cannot read {}", path.display())); + let descriptor: DatabaseDescriptor = serde_yaml_ng::from_str(&content) + .unwrap_or_else(|error| panic!("Invalid connection type descriptor {}: {error}", path.display())); + assert_eq!(descriptor.schema_version, 1, "{} must use schemaVersion 1", path.display()); + assert!(db_types.insert(descriptor.db_type.clone()), "Duplicate database type {}", descriptor.db_type); + assert!( + rust_variants.insert(descriptor.rust_variant.clone()), + "Duplicate Rust database variant {}", + descriptor.rust_variant + ); + assert!(orders.insert(descriptor.order), "Duplicate connection type descriptor order {}", descriptor.order); + + let mut public_descriptor: serde_json::Value = serde_yaml_ng::from_str(&content) + .unwrap_or_else(|error| panic!("Invalid connection type descriptor {}: {error}", path.display())); + let public_object = public_descriptor.as_object_mut().expect("Database descriptor must be an object"); + public_object.remove("schemaVersion"); + public_object.remove("order"); + public_object.remove("rustVariant"); + descriptors.push((descriptor, public_descriptor)); + } + + descriptors.sort_by_key(|(descriptor, _)| descriptor.order); + let public_descriptors = descriptors.iter().map(|(_, descriptor)| descriptor.clone()).collect::>(); + let manifest = serde_json::json!({ "schemaVersion": 1, "drivers": public_descriptors }); + std::fs::write( + out_dir.join("database_manifest.json"), + serde_json::to_string(&manifest).expect("Failed to serialize database manifest"), + ) + .expect("Failed to write database_manifest.json"); + + let mut code = String::from( + "#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash)]\n\ + #[cfg_attr(feature = \"openapi\", derive(utoipa::ToSchema))]\n\ + pub enum DatabaseType {\n", + ); + for (descriptor, _) in &descriptors { + code.push_str(&format!( + " #[serde(rename = \"{}\")]\n {},\n", + descriptor.db_type, descriptor.rust_variant + )); + } + code.push_str("}\n\nimpl DatabaseType {\n"); + code.push_str(" pub const ALL: &'static [Self] = &[\n"); + for (descriptor, _) in &descriptors { + code.push_str(&format!(" Self::{},\n", descriptor.rust_variant)); + } + code.push_str(" ];\n\n pub const fn as_str(self) -> &'static str {\n match self {\n"); + for (descriptor, _) in &descriptors { + code.push_str(&format!(" Self::{} => \"{}\",\n", descriptor.rust_variant, descriptor.db_type)); + } + code.push_str(" }\n }\n}\n"); + std::fs::write(out_dir.join("database_type.rs"), code).expect("Failed to write database_type.rs"); +} diff --git a/crates/dbx-core/src/agent_catalog.rs b/crates/dbx-core/src/agent_catalog.rs index 86b2acf108..33849d893b 100644 --- a/crates/dbx-core/src/agent_catalog.rs +++ b/crates/dbx-core/src/agent_catalog.rs @@ -1,425 +1,74 @@ use std::collections::HashSet; +use crate::database_manifest; use crate::models::connection::DatabaseType; -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct AgentCatalogEntry { - pub db_type: DatabaseType, - pub key: &'static str, - pub label: &'static str, - pub store_visible: bool, - pub profiles: &'static [AgentDriverProfile], -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct AgentDriverProfile { - pub profile: &'static str, - pub key: &'static str, - pub label: &'static str, - pub store_visible: bool, -} - -const ORACLE_PROFILES: &[AgentDriverProfile] = &[ - AgentDriverProfile { profile: "oracle-legacy", key: "oracle", label: "Oracle", store_visible: false }, - AgentDriverProfile { profile: "oracle-10g", key: "oracle", label: "Oracle", store_visible: false }, -]; - -const GBASE_PROFILES: &[AgentDriverProfile] = &[ - AgentDriverProfile { profile: "gbase8s", key: "gbase8s", label: "南大通用 GBase 8s", store_visible: true }, - AgentDriverProfile { profile: "gbase8a", key: "gbase8a", label: "南大通用 GBase 8a", store_visible: true }, -]; - -const MONGODB_PROFILES: &[AgentDriverProfile] = &[AgentDriverProfile { - profile: "mongodb-legacy", - key: "mongodb", - label: "MongoDB (Legacy)", - store_visible: false, -}]; - -const H2_PROFILES: &[AgentDriverProfile] = &[ - AgentDriverProfile { profile: "h2-legacy", key: "h2", label: "H2 2.1 Legacy", store_visible: false }, - AgentDriverProfile { profile: "h2-v1", key: "h2", label: "H2 1.x", store_visible: false }, - AgentDriverProfile { profile: "h2-v2", key: "h2", label: "H2 2.0–2.1", store_visible: false }, - AgentDriverProfile { profile: "h2-v3", key: "h2", label: "H2 2.2+", store_visible: false }, - AgentDriverProfile { profile: "h2-custom", key: "h2", label: "H2 Custom JAR", store_visible: false }, -]; - -const EXTRA_AGENT_LABELS: &[(&str, &str)] = &[ - ("duckdb", "DuckDB"), - ("h2-legacy", "H2 2.1 Legacy"), - ("kafka", "Apache Kafka"), - ("rocketmq", "Apache RocketMQ"), - ("rabbitmq", "RabbitMQ"), - ("sqlserver-legacy", "SQL Server legacy compatibility component"), -]; -const EXTRA_DRIVER_STORE_ENTRIES: &[(&str, &str)] = &[ - ("duckdb", "DuckDB"), - ("kafka", "Apache Kafka"), - ("rocketmq", "Apache RocketMQ"), - ("rabbitmq", "RabbitMQ"), - ("sqlserver-legacy", "SQL Server legacy compatibility component"), -]; - -const AGENT_CATALOG: &[AgentCatalogEntry] = &[ - AgentCatalogEntry { - db_type: DatabaseType::Dameng, - key: "dameng", - label: "达梦 DM8", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Kingbase, - key: "kingbase", - label: "金仓KingbaseES", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Highgo, - key: "highgo", - label: "瀚高 HighGo", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Uxdb, - key: "uxdb", - label: "优炫 UXDB", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Vastbase, - key: "vastbase", - label: "海量 Vastbase", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Goldendb, - key: "goldendb", - label: "金篆 GoldenDB", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Databend, - key: "databend", - label: "Databend", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Databricks, - key: "databricks", - label: "Databricks SQL", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::SapHana, - key: "saphana", - label: "SAP HANA", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Teradata, - key: "teradata", - label: "Teradata", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Vertica, - key: "vertica", - label: "Vertica", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Firebird, - key: "firebird", - label: "Firebird", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Exasol, - key: "exasol", - label: "Exasol", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::OceanbaseOracle, - key: "oceanbase-oracle", - label: "OceanBase Oracle Mode", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Gbase, - key: "gbase8a", - label: "南大通用 GBase 8a", - store_visible: true, - profiles: GBASE_PROFILES, - }, - AgentCatalogEntry { - db_type: DatabaseType::Access, - key: "access", - label: "Microsoft Access", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Oracle, - key: "oracle", - label: "Oracle", - store_visible: true, - profiles: ORACLE_PROFILES, - }, - AgentCatalogEntry { db_type: DatabaseType::H2, key: "h2", label: "H2", store_visible: true, profiles: H2_PROFILES }, - AgentCatalogEntry { - db_type: DatabaseType::Snowflake, - key: "snowflake", - label: "Snowflake", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Trino, - key: "trino", - label: "Trino", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Hive, - key: "hive", - label: "Apache Hive", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Kyuubi, - key: "hive", - label: "Apache Kyuubi", - store_visible: false, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Impala, - key: "hive", - label: "Apache Impala", - store_visible: false, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Spark, - key: "spark", - label: "Apache Spark", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { db_type: DatabaseType::Db2, key: "db2", label: "IBM DB2", store_visible: true, profiles: &[] }, - AgentCatalogEntry { - db_type: DatabaseType::Informix, - key: "informix", - label: "IBM Informix", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::InfluxDb, - key: "influxdb", - label: "InfluxDB", - store_visible: false, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Neo4j, - key: "neo4j", - label: "Neo4j", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Cassandra, - key: "cassandra", - label: "Apache Cassandra", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Bigquery, - key: "bigquery", - label: "Google BigQuery", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Spanner, - key: "spanner", - label: "Google Cloud Spanner", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Kylin, - key: "kylin", - label: "Apache Kylin", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Ignite, - key: "ignite", - label: "Apache Ignite", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Ignite3, - key: "ignite3", - label: "Apache Ignite 3", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Sundb, - key: "sundb", - label: "科蓝 SUNDB", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Oscar, - key: "oscar", - label: "神通 OSCAR", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Yashandb, - key: "yashandb", - label: "崖山 YashanDB", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Tdengine, - key: "tdengine", - label: "TDengine", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Xugu, - key: "xugu", - label: "虚谷 XuguDB", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::Iotdb, - key: "iotdb", - label: "Apache IoTDB", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { db_type: DatabaseType::Etcd, key: "etcd", label: "etcd", store_visible: true, profiles: &[] }, - AgentCatalogEntry { - db_type: DatabaseType::ZooKeeper, - key: "zookeeper", - label: "Apache ZooKeeper", - store_visible: true, - profiles: &[], - }, - AgentCatalogEntry { - db_type: DatabaseType::MongoDb, - key: "mongodb", - label: "MongoDB (Legacy)", - store_visible: true, - profiles: MONGODB_PROFILES, - }, - AgentCatalogEntry { - db_type: DatabaseType::Iris, - key: "iris", - label: "InterSystems IRIS", - store_visible: true, - profiles: &[], - }, -]; - -pub fn entries() -> &'static [AgentCatalogEntry] { - AGENT_CATALOG -} - pub fn agent_key(db_type: &DatabaseType, driver_profile: Option<&str>) -> Option<&'static str> { - if *db_type == DatabaseType::MessageQueue { - return match driver_profile { - Some("kafka") => Some("kafka"), - Some("rocketmq") => Some("rocketmq"), - Some("rabbitmq") => Some("rabbitmq"), - _ => None, - }; - } - if *db_type == DatabaseType::SqlServer { - return driver_profile - .is_some_and(|profile| profile.eq_ignore_ascii_case("sqlserver-legacy")) - .then_some("sqlserver-legacy"); - } - let entry = entry_for_db_type(db_type)?; + let entry = database_manifest::entry(db_type)?; if let Some(driver_profile) = driver_profile { - if let Some(profile) = entry.profiles.iter().find(|profile| profile.profile == driver_profile) { - return Some(profile.key); + if let Some(profile) = + entry.driver_profiles.iter().find(|profile| profile.profile.eq_ignore_ascii_case(driver_profile)) + { + return Some(profile.agent_key.as_str()); } } - Some(entry.key) + entry.agent_key.as_deref() } pub fn is_agent_type(db_type: &DatabaseType) -> bool { - entry_for_db_type(db_type).is_some() + database_manifest::is_agent_runtime(db_type) } pub fn driver_store_entries() -> impl Iterator { - let mut seen = HashSet::new(); - entries() + let mut entries = database_manifest::entries() .iter() - .flat_map(move |entry| { - let base = entry.store_visible.then_some((entry.key, entry.label)); - let profiles = entry - .profiles + .flat_map(|entry| { + let base = entry.driver_store_visible.then(|| { + entry + .agent_key + .as_deref() + .map(|key| (entry.driver_store_order.unwrap_or(u32::MAX), key, entry.label.as_str())) + }); + let profiles = entry.driver_profiles.iter().filter(|profile| profile.store_visible).map(|profile| { + ( + profile.store_order.unwrap_or(u32::MAX), + profile.package_key.as_deref().unwrap_or(profile.agent_key.as_str()), + profile.label.as_str(), + ) + }); + let managed = entry + .managed_drivers .iter() - .filter(|profile| profile.store_visible) - .map(|profile| (profile.key, profile.label)); - base.into_iter().chain(profiles) + .filter(|driver| driver.store_visible) + .map(|driver| (driver.store_order.unwrap_or(u32::MAX), driver.key.as_str(), driver.label.as_str())); + base.flatten().into_iter().chain(profiles).chain(managed) }) - .chain(EXTRA_DRIVER_STORE_ENTRIES.iter().copied()) - .filter(move |(key, _)| seen.insert(*key)) + .collect::>(); + entries.sort_by_key(|(order, _, _)| *order); + + let mut seen = HashSet::new(); + entries.into_iter().filter(move |(_, key, _)| seen.insert(*key)).map(|(_, key, label)| (key, label)) } pub fn label_for_key(agent_key: &str) -> Option<&'static str> { - if let Some((_, label)) = EXTRA_AGENT_LABELS.iter().find(|(key, _)| *key == agent_key) { - return Some(label); - } - for entry in entries() { - if entry.key == agent_key { - return Some(entry.label); + for entry in database_manifest::entries() { + if entry.agent_key.as_deref() == Some(agent_key) { + return Some(entry.label.as_str()); } - if let Some(profile) = entry.profiles.iter().find(|profile| profile.key == agent_key) { - return Some(profile.label); + if let Some(profile) = entry + .driver_profiles + .iter() + .find(|profile| profile.package_key.as_deref() == Some(agent_key) || profile.agent_key == agent_key) + { + return Some(profile.label.as_str()); + } + if let Some(driver) = entry.managed_drivers.iter().find(|driver| driver.key == agent_key) { + return Some(driver.label.as_str()); } } None } -fn entry_for_db_type(db_type: &DatabaseType) -> Option<&'static AgentCatalogEntry> { - entries().iter().find(|entry| entry.db_type == *db_type) -} - #[cfg(test)] mod tests { use super::*; @@ -455,4 +104,16 @@ mod tests { assert_eq!(agent_key(&DatabaseType::Kyuubi, None), Some("hive")); assert_eq!(driver_store_entries().filter(|(key, _)| *key == "hive").count(), 1); } + + #[test] + fn manifest_agent_keys_match_catalog_defaults() { + for entry in database_manifest::entries().iter().filter(|entry| entry.agent_key.is_some()) { + assert_eq!( + agent_key(&entry.db_type, None), + entry.agent_key.as_deref(), + "agent key drift for {:?}", + entry.db_type + ); + } + } } diff --git a/crates/dbx-core/src/database_capabilities.rs b/crates/dbx-core/src/database_capabilities.rs index 0d66774607..c7f6dd9720 100644 --- a/crates/dbx-core/src/database_capabilities.rs +++ b/crates/dbx-core/src/database_capabilities.rs @@ -1,4 +1,5 @@ use crate::agent_catalog; +use crate::database_manifest; use crate::models::connection::DatabaseType; pub fn agent_key(db_type: &DatabaseType, driver_profile: Option<&str>) -> Option<&'static str> { @@ -6,61 +7,19 @@ pub fn agent_key(db_type: &DatabaseType, driver_profile: Option<&str>) -> Option } pub fn is_agent_type(db_type: &DatabaseType) -> bool { - agent_catalog::is_agent_type(db_type) + database_manifest::is_agent_runtime(db_type) } pub fn is_single_connection_pool(db_type: &DatabaseType) -> bool { - matches!( - db_type, - DatabaseType::Sqlite - | DatabaseType::DuckDb - | DatabaseType::Rqlite - | DatabaseType::Turso - | DatabaseType::CloudflareD1 - | DatabaseType::MongoDb - | DatabaseType::DynamoDb - | DatabaseType::Hbase - | DatabaseType::Oracle - | DatabaseType::Dameng - | DatabaseType::Kingbase - | DatabaseType::Highgo - | DatabaseType::Uxdb - | DatabaseType::Vastbase - | DatabaseType::Goldendb - | DatabaseType::Yashandb - | DatabaseType::Oscar - | DatabaseType::Firebird - | DatabaseType::Iris - | DatabaseType::OceanbaseOracle - | DatabaseType::Access - | DatabaseType::Jdbc - | DatabaseType::VictoriaMetrics - ) + database_manifest::entry(db_type).is_some_and(|entry| entry.single_connection_pool) } pub fn is_metadata_connection_scoped(db_type: &DatabaseType) -> bool { - // MySQL-protocol engines (incl. Doris/StarRocks) must not keep a configured - // default database when the caller asks for an unscoped metadata pool. - // External-catalog databases do not exist in the default catalog, so leaving - // `config.database` in the URL makes handshake/`USE` fail with Unknown database. - matches!( - db_type, - DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch - ) + database_manifest::entry(db_type).is_some_and(|entry| entry.metadata_connection_scoped) } pub fn skips_tcp_probe(db_type: &DatabaseType) -> bool { - matches!( - db_type, - DatabaseType::Sqlite - | DatabaseType::DuckDb - | DatabaseType::Turso - | DatabaseType::CloudflareD1 - | DatabaseType::Jdbc - | DatabaseType::MessageQueue - | DatabaseType::Mqtt - | DatabaseType::VictoriaMetrics - ) || is_agent_type(db_type) + database_manifest::entry(db_type).is_some_and(|entry| entry.skip_tcp_probe) || is_agent_type(db_type) } /// Database types whose connection backs onto a single local file (or may, in the @@ -68,7 +27,7 @@ pub fn skips_tcp_probe(db_type: &DatabaseType) -> bool { /// manager" affordance. Whether the H2 connection is actually in file mode must /// be determined separately by parsing the JDBC URL. pub fn is_local_file_db_type(db_type: &DatabaseType) -> bool { - matches!(db_type, DatabaseType::Sqlite | DatabaseType::DuckDb | DatabaseType::Access | DatabaseType::H2) + database_manifest::entry(db_type).is_some_and(|entry| entry.local_file) } #[cfg(test)] @@ -99,4 +58,27 @@ mod tests { assert!(is_single_connection_pool(&DatabaseType::CloudflareD1)); assert!(skips_tcp_probe(&DatabaseType::CloudflareD1)); } + + #[test] + fn manifest_connection_capabilities_are_used_for_every_registered_driver() { + for entry in database_manifest::entries() { + assert_eq!( + is_single_connection_pool(&entry.db_type), + entry.single_connection_pool, + "single connection pool drift for {:?}", + entry.db_type + ); + assert_eq!( + is_metadata_connection_scoped(&entry.db_type), + entry.metadata_connection_scoped, + "metadata scope drift for {:?}", + entry.db_type + ); + assert!( + skips_tcp_probe(&entry.db_type) || !is_agent_type(&entry.db_type), + "agent driver {:?} must skip the TCP probe", + entry.db_type + ); + } + } } diff --git a/crates/dbx-core/src/database_manifest.rs b/crates/dbx-core/src/database_manifest.rs new file mode 100644 index 0000000000..0b11540045 --- /dev/null +++ b/crates/dbx-core/src/database_manifest.rs @@ -0,0 +1,145 @@ +use std::sync::OnceLock; + +use serde::Deserialize; + +use crate::models::connection::DatabaseType; + +const DATABASE_MANIFEST_JSON: &str = include_str!(concat!(env!("OUT_DIR"), "/database_manifest.json")); + +#[derive(Debug, Deserialize)] +struct DatabaseManifestFile { + drivers: Vec, +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum DatabaseRuntimeMode { + Native, + File, + Agent, + External, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DatabaseDriverProfile { + pub profile: String, + pub agent_key: String, + #[serde(default)] + pub package_key: Option, + pub label: String, + #[serde(default)] + pub store_visible: bool, + #[serde(default)] + pub store_order: Option, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ManagedDriverEntry { + pub key: String, + pub label: String, + #[serde(default)] + pub store_visible: bool, + #[serde(default)] + pub store_order: Option, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DatabaseManifestEntry { + pub db_type: DatabaseType, + pub label: String, + #[serde(default)] + pub dialect: Option, + pub runtime_mode: DatabaseRuntimeMode, + pub mcp_mode: String, + #[serde(default)] + pub agent_key: Option, + #[serde(default)] + pub driver_store_visible: bool, + #[serde(default)] + pub driver_store_order: Option, + #[serde(default)] + pub driver_profiles: Vec, + #[serde(default)] + pub managed_drivers: Vec, + #[serde(default)] + pub single_connection_pool: bool, + #[serde(default)] + pub metadata_connection_scoped: bool, + #[serde(default)] + pub skip_tcp_probe: bool, + #[serde(default)] + pub default_port: Option, + #[serde(default)] + pub local_file: bool, + #[serde(default)] + pub specialized_surface: bool, +} + +static DATABASE_MANIFEST: OnceLock = OnceLock::new(); + +fn manifest() -> &'static DatabaseManifestFile { + DATABASE_MANIFEST.get_or_init(|| { + serde_json::from_str(DATABASE_MANIFEST_JSON).expect("database-drivers.manifest.json must be valid") + }) +} + +pub fn entries() -> &'static [DatabaseManifestEntry] { + &manifest().drivers +} + +pub fn entry(db_type: &DatabaseType) -> Option<&'static DatabaseManifestEntry> { + entries().iter().find(|candidate| candidate.db_type == *db_type) +} + +pub fn default_port(db_type: &DatabaseType) -> Option { + entry(db_type).and_then(|candidate| candidate.default_port.or(candidate.local_file.then_some(0))) +} + +pub fn agent_key(db_type: &DatabaseType) -> Option<&'static str> { + entry(db_type).and_then(|candidate| candidate.agent_key.as_deref()) +} + +pub fn dialect_name(db_type: &DatabaseType) -> Option<&'static str> { + entry(db_type).and_then(|candidate| candidate.dialect.as_deref()) +} + +pub fn is_agent_runtime(db_type: &DatabaseType) -> bool { + entry(db_type).is_some_and(|candidate| candidate.runtime_mode == DatabaseRuntimeMode::Agent) +} + +#[cfg(test)] +mod tests { + use std::collections::HashSet; + + use super::*; + + #[test] + fn manifest_entries_have_unique_database_types() { + let mut seen = HashSet::new(); + assert!(entries().iter().all(|entry| seen.insert(entry.db_type))); + assert_eq!(seen.len(), DatabaseType::ALL.len()); + assert!(DatabaseType::ALL.iter().all(|db_type| entry(db_type).is_some())); + } + + #[test] + fn database_type_strings_match_serde_contract() { + for db_type in DatabaseType::ALL { + let serialized = serde_json::to_string(db_type).expect("database type must serialize"); + assert_eq!(serialized, format!("\"{}\"", db_type.as_str())); + let deserialized = + serde_json::from_str::(&serialized).expect("database type must deserialize"); + assert_eq!(deserialized, *db_type); + } + } + + #[test] + fn manifest_contains_connection_runtime_defaults() { + assert_eq!(entry(&DatabaseType::Mysql).map(|entry| entry.default_port), Some(Some(3306))); + assert_eq!(entry(&DatabaseType::Postgres).map(|entry| entry.default_port), Some(Some(5432))); + assert_eq!(entry(&DatabaseType::Sqlite).map(|entry| entry.skip_tcp_probe), Some(true)); + assert_eq!(entry(&DatabaseType::H2).map(|entry| entry.agent_key.as_deref()), Some(Some("h2"))); + } +} diff --git a/crates/dbx-core/src/lib.rs b/crates/dbx-core/src/lib.rs index 8b98b5ac57..c9ce69fb56 100644 --- a/crates/dbx-core/src/lib.rs +++ b/crates/dbx-core/src/lib.rs @@ -38,6 +38,7 @@ pub mod data_grid_extractors; pub mod data_grid_sql; pub mod database_capabilities; pub mod database_export; +pub mod database_manifest; pub mod database_search_sql; pub mod db; pub mod db_admin_sql; diff --git a/crates/dbx-core/src/models/connection.rs b/crates/dbx-core/src/models/connection.rs index 2594bdb119..a0f366c9b8 100644 --- a/crates/dbx-core/src/models/connection.rs +++ b/crates/dbx-core/src/models/connection.rs @@ -494,126 +494,7 @@ pub enum ProxyType { Http, } -#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))] -#[serde(rename_all = "lowercase")] -pub enum DatabaseType { - Mysql, - Postgres, - Sqlite, - Rqlite, - Redis, - #[serde(rename = "duckdb")] - DuckDb, - #[serde(rename = "clickhouse")] - ClickHouse, - #[serde(rename = "sqlserver")] - SqlServer, - #[serde(rename = "mongodb")] - MongoDb, - #[serde(rename = "dynamodb")] - DynamoDb, - #[serde(rename = "oracle")] - Oracle, - #[serde(rename = "elasticsearch")] - Elasticsearch, - #[serde(rename = "easysearch")] - Easysearch, - #[serde(rename = "meilisearch")] - Meilisearch, - Hbase, - #[serde(rename = "qdrant")] - Qdrant, - #[serde(rename = "milvus")] - Milvus, - #[serde(rename = "weaviate")] - Weaviate, - #[serde(rename = "chromadb")] - ChromaDb, - Doris, - #[serde(rename = "starrocks")] - StarRocks, - #[serde(rename = "manticoresearch")] - ManticoreSearch, - Databend, - Redshift, - Dameng, - Kingbase, - Highgo, - Uxdb, - Vastbase, - Goldendb, - Gaussdb, - Kwdb, - Yashandb, - Databricks, - #[serde(rename = "saphana")] - SapHana, - Teradata, - Vertica, - Firebird, - Exasol, - #[serde(rename = "opengauss")] - OpenGauss, - #[serde(rename = "oceanbase-oracle")] - OceanbaseOracle, - Gbase, - Access, - #[serde(rename = "h2")] - H2, - Snowflake, - Trino, - #[serde(rename = "prestosql")] - PrestoSql, - Hive, - Kyuubi, - Impala, - Spark, - #[serde(rename = "db2")] - Db2, - Informix, - #[serde(rename = "neo4j")] - Neo4j, - Cassandra, - #[serde(rename = "bigquery")] - Bigquery, - #[serde(rename = "spanner")] - Spanner, - Kylin, - Sundb, - Oscar, - Tdengine, - Xugu, - Iotdb, - Etcd, - #[serde(rename = "zookeeper")] - ZooKeeper, - Nacos, - Consul, - #[serde(rename = "iris")] - Iris, - #[serde(rename = "turso")] - Turso, - #[serde(rename = "cloudflare-d1")] - CloudflareD1, - #[serde(rename = "influxdb")] - InfluxDb, - #[serde(rename = "victoriametrics")] - VictoriaMetrics, - #[serde(rename = "questdb")] - Questdb, - Ignite, - Ignite3, - Jdbc, - /// Message queue admin connection (Pulsar / Kafka / RocketMQ). The specific - /// system is determined by `external_config.systemKind`. - #[serde(rename = "mq")] - MessageQueue, - /// MQTT broker connection. The broker address, client ID, and authentication - /// are stored in `external_config`. - #[serde(rename = "mqtt")] - Mqtt, -} +include!(concat!(env!("OUT_DIR"), "/database_type.rs")); #[derive(Deserialize)] struct ConnectionConfigData { diff --git a/crates/dbx-core/src/sql_dialect/descriptor.rs b/crates/dbx-core/src/sql_dialect/descriptor.rs index 075477d676..c3c3407ee2 100644 --- a/crates/dbx-core/src/sql_dialect/descriptor.rs +++ b/crates/dbx-core/src/sql_dialect/descriptor.rs @@ -19,41 +19,7 @@ pub enum DialectKind { impl DialectKind { pub fn from_database_type(db_type: DatabaseType) -> Self { - match db_type { - DatabaseType::Mysql - | DatabaseType::Doris - | DatabaseType::StarRocks - | DatabaseType::Goldendb - | DatabaseType::Sundb - | DatabaseType::Databend - | DatabaseType::Gbase => DialectKind::Mysql, - DatabaseType::Postgres - | DatabaseType::Gaussdb - | DatabaseType::Kwdb - | DatabaseType::OpenGauss - | DatabaseType::Highgo - | DatabaseType::Vastbase - | DatabaseType::Kingbase - | DatabaseType::Firebird - | DatabaseType::Redshift - | DatabaseType::Vertica - | DatabaseType::Exasol => DialectKind::Postgres, - DatabaseType::Sqlite | DatabaseType::Rqlite | DatabaseType::Turso => DialectKind::Sqlite, - DatabaseType::DuckDb => DialectKind::DuckDb, - DatabaseType::SqlServer | DatabaseType::Access => DialectKind::SqlServer, - DatabaseType::Oracle - | DatabaseType::Dameng - | DatabaseType::OceanbaseOracle - | DatabaseType::Iris - | DatabaseType::Yashandb - | DatabaseType::Xugu => DialectKind::Oracle, - DatabaseType::H2 => DialectKind::H2, - DatabaseType::ClickHouse => DialectKind::ClickHouse, - DatabaseType::ManticoreSearch => DialectKind::ManticoreSearch, - DatabaseType::Informix => DialectKind::Informix, - DatabaseType::Questdb => DialectKind::Questdb, - _ => DialectKind::Unsupported, - } + crate::database_manifest::dialect_name(&db_type).and_then(Self::from_label).unwrap_or(DialectKind::Unsupported) } pub fn to_database_type(self) -> Option { diff --git a/crates/dbx-core/src/sql_dialect/dialect_loader.rs b/crates/dbx-core/src/sql_dialect/dialect_loader.rs index 04915cf317..7fd1c5eba3 100644 --- a/crates/dbx-core/src/sql_dialect/dialect_loader.rs +++ b/crates/dbx-core/src/sql_dialect/dialect_loader.rs @@ -77,9 +77,14 @@ impl DialectRegistry { &self, db_type: crate::models::connection::DatabaseType, ) -> Option { + if let Some(dialect_name) = crate::database_manifest::dialect_name(&db_type) { + if let Some(loaded) = self.get(dialect_name) { + return Some(loaded.descriptor); + } + } let kind = DialectKind::from_database_type(db_type); let label = kind.label(); - let db_name = format!("{db_type:?}").to_ascii_lowercase(); + let db_name = db_type.as_str(); self.get(&db_name).or_else(|| self.get(label)).map(|ld| ld.descriptor) } diff --git a/crates/dbx-core/tests/database_capabilities.rs b/crates/dbx-core/tests/database_capabilities.rs index 9d804977b0..35519f5899 100644 --- a/crates/dbx-core/tests/database_capabilities.rs +++ b/crates/dbx-core/tests/database_capabilities.rs @@ -29,6 +29,8 @@ struct DriverManifestEntry { #[serde(default)] skip_tcp_probe: bool, #[serde(default)] + specialized_surface: bool, + #[serde(default)] driver_profiles: Vec, } @@ -235,18 +237,14 @@ fn driver_manifest_matches_core_database_capabilities() { let support_levels = ["connect", "browse", "understand", "operate"]; for driver in &manifest.drivers { - // MQ is a message queue, not a database — skip database capability checks - if driver.db_type == DatabaseType::MessageQueue { - continue; - } assert!( support_levels.contains(&driver.support_level.as_str()), "invalid support level for {:?}", driver.db_type ); assert!( - driver.capabilities.any_enabled(), - "database {:?} should declare at least one product capability", + driver.capabilities.any_enabled() || driver.specialized_surface, + "database {:?} should declare a product capability or a specialized surface", driver.db_type ); assert_eq!( diff --git a/crates/dbx-mcp/src/server.rs b/crates/dbx-mcp/src/server.rs index b91e007825..1b07498ca3 100644 --- a/crates/dbx-mcp/src/server.rs +++ b/crates/dbx-mcp/src/server.rs @@ -14,6 +14,7 @@ use crate::mongo::{self, MongoCommand, MongoSafetyError}; use crate::session::{McpSession, McpSessionStore}; use dbx_core::{ agent_tools::{format_query_result_as_text, QueryCellWindow}, + database_manifest, db::redis_driver::{classify_command, parse_command_argv, RedisCommandResult, RedisCommandSafety}, models::connection::DatabaseType, production_safety::{ @@ -655,7 +656,7 @@ impl DbxMcpServer { Ok(db_type) => db_type, Err(error) => return tool_error("INVALID_CONNECTION_TYPE", error), }; - let port = match request.port.or_else(|| default_port(&request.db_type)) { + let port = match request.port.or_else(|| database_manifest::default_port(&db_type)) { Some(port) => port, None => return text("Port is required for this database type."), }; @@ -1207,24 +1208,6 @@ fn scoped_connection_ids(value: Option<&str>) -> Vec { ids } -fn default_port(db_type: &str) -> Option { - match db_type.trim().to_ascii_lowercase().as_str() { - "mysql" | "doris" | "starrocks" | "manticoresearch" => Some(3306), - "postgres" | "redshift" | "highgo" | "kingbase" | "opengauss" | "gaussdb" => Some(5432), - "uxdb" => Some(52025), - "redis" => Some(6379), - "mongodb" => Some(27017), - "rqlite" => Some(4001), - "kwdb" => Some(26257), - "cloudflare-d1" => Some(443), - "tdengine" => Some(6041), - "iotdb" => Some(6667), - "xugu" => Some(5138), - "sqlite" | "duckdb" | "access" => Some(0), - _ => None, - } -} - fn ambiguous_connections(name: &str, connections: &[dbx_core::models::connection::ConnectionConfig]) -> String { let lines = connections .iter() diff --git a/package.json b/package.json index 3f04ee902e..6880e1afef 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,9 @@ "release:packages": "node scripts/release.mjs packages", "test:release": "node --test scripts/release.test.mjs", "build:knowledge-base": "node scripts/build-knowledge-base.mjs", + "generate:connection-types": "node scripts/sync-connection-types.mjs", + "check:connection-types": "node scripts/sync-connection-types.mjs --check", + "pretypecheck": "pnpm generate:connection-types", "typecheck": "vue-tsc --noEmit --project apps/desktop/tsconfig.json", "build": "vite build --config apps/desktop/vite.config.ts", "build:docs-export": "vite build --config apps/desktop/vite.docs-export.config.ts", @@ -35,6 +38,7 @@ "bench:table-import": "cargo run -p dbx-core --no-default-features --example table_import_bench --release --", "lint": "oxlint --vue-plugin apps/desktop/src", "fmt": "oxfmt \"apps/desktop/src/**/*.{ts,vue}\"", + "pretest": "pnpm generate:connection-types", "test": "vitest run", "preview": "vite preview --config apps/desktop/vite.config.ts", "tauri": "tauri", @@ -128,7 +132,8 @@ "typescript": "~6.0.3", "vite": "^8.2.1", "vitest": "^4.1.8", - "vue-tsc": "^3.3.3" + "vue-tsc": "^3.3.3", + "yaml": "2.8.4" }, "lint-staged": { "apps/desktop/src/**/*.{ts,vue}": "oxfmt" diff --git a/packages/app-tests/databaseCategoryOptions.test.ts b/packages/app-tests/databaseCategoryOptions.test.ts index f079f1e065..da4eb6efa0 100644 --- a/packages/app-tests/databaseCategoryOptions.test.ts +++ b/packages/app-tests/databaseCategoryOptions.test.ts @@ -5,6 +5,7 @@ import { dirname, join } from "node:path"; import { test } from "vitest"; import { assertCompleteDatabaseCategories, databaseSelectionForCategory } from "../../apps/desktop/src/lib/connection/databaseCategoryOptions.ts"; import { JDBC_PRODUCT_PROFILES } from "../../apps/desktop/src/lib/database/jdbcProductProfiles.ts"; +import { CONNECTION_PICKER_OPTIONS } from "../../apps/desktop/src/types/generated/connectionProfiles.ts"; test("database categories cover every option exactly once", () => { assert.doesNotThrow(() => assertCompleteDatabaseCategories(["mysql", "redis", "kafka"], [["mysql"], ["redis", "kafka"]])); @@ -22,19 +23,14 @@ test("database category changes keep only visible selections", () => { test("ConnectionDialog database categories stay exhaustive", () => { const dialogPath = join(dirname(fileURLToPath(import.meta.url)), "../../apps/desktop/src/components/connection/ConnectionDialog.vue"); const source = readFileSync(dialogPath, "utf8"); - const optionsMatch = source.match(/const dbOptions: DbOption\[] = \[([\s\S]*?)\];/); - const categoriesMatch = source.match(/const dbCategoryDefinitions: Array<\{[\s\S]*?\}> = \[([\s\S]*?)\];/); - assert.ok(optionsMatch, "dbOptions not found"); - assert.ok(categoriesMatch, "dbCategoryDefinitions not found"); - - const optionValues = [...optionsMatch[1].matchAll(/value:\s*"([^"]+)"/g)].map((match) => match[1]); - const categoryBlocks = [...categoriesMatch[1].matchAll(/optionValues:\s*\[([^\]]*)\]/g)].map((match) => [...match[1].matchAll(/"([^"]+)"/g)].map((valueMatch) => valueMatch[1])); - optionValues.push(...JDBC_PRODUCT_PROFILES.map((profile) => profile.id)); - categoryBlocks.push(JDBC_PRODUCT_PROFILES.map((profile) => profile.id)); + const optionValues = [...CONNECTION_PICKER_OPTIONS.map((option) => option.value), ...JDBC_PRODUCT_PROFILES.map((profile) => profile.id)]; + const categories = new Set([...CONNECTION_PICKER_OPTIONS.map((option) => option.category), ...JDBC_PRODUCT_PROFILES.map((profile) => profile.category)]); + const categoryBlocks = [...categories].map((category) => [...CONNECTION_PICKER_OPTIONS.filter((option) => option.category === category).map((option) => option.value), ...JDBC_PRODUCT_PROFILES.filter((profile) => profile.category === category).map((profile) => profile.id)]); assert.doesNotThrow(() => assertCompleteDatabaseCategories(optionValues, categoryBlocks)); - assert.match(source, /for \(const category of dbCategoryDefinitions\)/); - assert.match(source, /jdbcProductProfileIdsForCategory\(category\.key\)/); + assert.match(source, /\.\.\.CONNECTION_PICKER_OPTIONS/); + assert.match(source, /\.\.\.CONNECTION_PROFILES/); + assert.match(source, /jdbcProductProfileIdsForCategory\(key\)/); assert.match(source, /\.\.\.jdbcProductIconTypes\(\)/); assert.ok(optionValues.includes("rabbitmq"), "rabbitmq must remain in dbOptions"); assert.ok( diff --git a/plugins/README.md b/plugins/README.md index 401e5813e0..dbb4f29e07 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -1,11 +1,14 @@ # Plugins -DBX extension plugins live here. +DBX declarative extension metadata and runtime plugins live here. Plugins are not Node packages, so they intentionally stay separate from `packages/`. ## Directories +- `connection-types/` - build-time registry for every DBX connection target, including databases, data services, message queues, and service registries. +- `dialects/` - SQL dialect descriptors, type catalogs, DDL templates, and metadata rules. +- `mappings/` - cross-dialect type mapping rules. - `jdbc/` - optional Java/JDBC plugin for connecting through vendor JDBC drivers and custom JDBC URLs. Plugin build artifacts, downloaded driver JARs, and local targets are ignored by Git. diff --git a/plugins/connection-types/README.md b/plugins/connection-types/README.md new file mode 100644 index 0000000000..a64594bf5a --- /dev/null +++ b/plugins/connection-types/README.md @@ -0,0 +1,29 @@ +# Connection type descriptors + +`plugins/connection-types/*.yaml` is the source of truth for DBX connection type registration. It covers SQL databases, document and vector stores, key-value and configuration services, message queues, MQTT brokers, and generic JDBC targets. `profiles/catalog.yaml` contains the frontend connection-picker profiles that bind product names and defaults to those stable connection types. + +Each descriptor defines the stable `dbType` ID, generated Rust variant, display label, runtime and MCP modes, Agent driver mapping, connection defaults, optional SQL dialect binding, connection form kind, and product capabilities. `dbType` and `DatabaseType` retain their historical names for serialized API compatibility even though some targets are not databases. SQL syntax, DDL templates, type catalogs, and metadata-query details remain in `plugins/dialects/*.yaml`. + +Connection types may contain multiple runtime profiles when they share the same DBX connection model and management surface. For example, Kafka, RocketMQ, and RabbitMQ are profiles of `mq.yaml`; MQTT remains a separate connection type because it has a different protocol, configuration model, and UI workflow. + +Set `specializedSurface: true` only when the product uses a dedicated management surface that is not represented by the shared capability matrix. Otherwise at least one product capability must be enabled. + +Driver store entries also declare their stable display order in YAML. Use `driverStoreOrder` for the descriptor's primary Agent and `storeOrder` for visible profiles or managed drivers. Orders must be positive and unique across effective driver keys. + +Normal Vite development/build, frontend typecheck, and frontend tests regenerate derived files automatically. The explicit command remains available for troubleshooting or refreshing generated files without starting another tool: + +```bash +pnpm generate:connection-types +``` + +The generator updates these derived files: + +- `crates/dbx-core/assets/database-drivers.manifest.json` +- `apps/desktop/src/types/generated/databaseTypes.ts` +- `apps/desktop/src/types/generated/connectionProfiles.ts` + +Cargo reads the same YAML descriptors in `crates/dbx-core/build.rs` to generate `DatabaseType` and the embedded Rust manifest. Do not edit the generated JSON or TypeScript type list directly. + +`pnpm generate:connection-types` validates the YAML and rewrites the committed JSON and TypeScript derivatives. Vite also watches the descriptor directory during development and regenerates after YAML changes. `pnpm check:connection-types` performs the same validation without modifying files, and `pnpm check` runs that read-only check automatically in CI so stale committed derivatives still fail verification. + +A compatible product profile usually needs only a catalog entry and icon. A connection type still needs code when its protocol, authentication, connection fields, metadata provider, query executor, or UI workflow differs from an existing implementation. `formKind` selects a finite coded connection form; it is not an arbitrary YAML form engine. Protocol-compatible products should bind to an existing dialect and reuse the nearest connector or Agent before introducing another independent implementation. diff --git a/plugins/connection-types/access.yaml b/plugins/connection-types/access.yaml new file mode 100644 index 0000000000..f9649a2b88 --- /dev/null +++ b/plugins/connection-types/access.yaml @@ -0,0 +1,35 @@ +schemaVersion: 1 +order: 460 +dbType: access +rustVariant: Access +label: Microsoft Access +dialect: Access +runtimeMode: agent +mcpMode: bridge +agentKey: access +driverStoreVisible: true +driverStoreOrder: 17 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +localFile: true +traits: + singleDatabase: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/bigquery.yaml b/plugins/connection-types/bigquery.yaml new file mode 100644 index 0000000000..051d7b4b6e --- /dev/null +++ b/plugins/connection-types/bigquery.yaml @@ -0,0 +1,31 @@ +schemaVersion: 1 +order: 580 +dbType: bigquery +rustVariant: Bigquery +label: Google BigQuery +runtimeMode: agent +mcpMode: bridge +agentKey: bigquery +driverStoreVisible: true +driverStoreOrder: 28 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/cassandra.yaml b/plugins/connection-types/cassandra.yaml new file mode 100644 index 0000000000..55ee9b3d40 --- /dev/null +++ b/plugins/connection-types/cassandra.yaml @@ -0,0 +1,32 @@ +schemaVersion: 1 +order: 570 +dbType: cassandra +rustVariant: Cassandra +label: Apache Cassandra +runtimeMode: agent +mcpMode: bridge +agentKey: cassandra +driverStoreVisible: true +driverStoreOrder: 27 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 9042 +supportLevel: understand +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/chromadb.yaml b/plugins/connection-types/chromadb.yaml new file mode 100644 index 0000000000..fc9ba642c4 --- /dev/null +++ b/plugins/connection-types/chromadb.yaml @@ -0,0 +1,29 @@ +schemaVersion: 1 +order: 190 +dbType: chromadb +rustVariant: ChromaDb +label: ChromaDB +runtimeMode: native +mcpMode: bridge +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 8000 +supportLevel: browse +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/clickhouse.yaml b/plugins/connection-types/clickhouse.yaml new file mode 100644 index 0000000000..a3ea5d3945 --- /dev/null +++ b/plugins/connection-types/clickhouse.yaml @@ -0,0 +1,30 @@ +schemaVersion: 1 +order: 90 +dbType: clickhouse +rustVariant: ClickHouse +label: ClickHouse +dialect: ClickHouse +runtimeMode: native +mcpMode: bridge +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 8123 +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: false + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: true + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/cloudflare-d1.yaml b/plugins/connection-types/cloudflare-d1.yaml new file mode 100644 index 0000000000..df4b5c658f --- /dev/null +++ b/plugins/connection-types/cloudflare-d1.yaml @@ -0,0 +1,32 @@ +schemaVersion: 1 +order: 60 +dbType: cloudflare-d1 +rustVariant: CloudflareD1 +label: Cloudflare D1 +dialect: SQLite +runtimeMode: native +mcpMode: bridge +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 443 +traits: + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: false + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: true + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/consul.yaml b/plugins/connection-types/consul.yaml new file mode 100644 index 0000000000..54047f5933 --- /dev/null +++ b/plugins/connection-types/consul.yaml @@ -0,0 +1,30 @@ +schemaVersion: 1 +order: 700 +dbType: consul +rustVariant: Consul +label: Consul +runtimeMode: native +mcpMode: unsupported +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 8500 +supportLevel: connect +specializedSurface: true +capabilities: + queryExecution: false + metadataBrowse: false + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/dameng.yaml b/plugins/connection-types/dameng.yaml new file mode 100644 index 0000000000..f342de1a4f --- /dev/null +++ b/plugins/connection-types/dameng.yaml @@ -0,0 +1,39 @@ +schemaVersion: 1 +order: 260 +dbType: dameng +rustVariant: Dameng +label: 达梦 DM8 +dialect: Dameng +runtimeMode: agent +mcpMode: bridge +agentKey: dameng +driverStoreVisible: true +driverStoreOrder: 1 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 5236 +traits: + schemaAware: true + singleDatabase: true + clearableQuerySchema: true + fetchFirst: true + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: true + sqlExplain: true + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/databend.yaml b/plugins/connection-types/databend.yaml new file mode 100644 index 0000000000..1f1ec42400 --- /dev/null +++ b/plugins/connection-types/databend.yaml @@ -0,0 +1,35 @@ +schemaVersion: 1 +order: 320 +dbType: databend +rustVariant: Databend +label: Databend +dialect: Databend +runtimeMode: agent +mcpMode: bridge +agentKey: databend +driverStoreVisible: true +driverStoreOrder: 7 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 8000 +traits: + schemaAware: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: true + tableStructureEdit: true + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: true + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/databricks.yaml b/plugins/connection-types/databricks.yaml new file mode 100644 index 0000000000..2b2e571bfe --- /dev/null +++ b/plugins/connection-types/databricks.yaml @@ -0,0 +1,35 @@ +schemaVersion: 1 +order: 360 +dbType: databricks +rustVariant: Databricks +label: Databricks SQL +runtimeMode: agent +mcpMode: bridge +agentKey: databricks +driverStoreVisible: true +driverStoreOrder: 8 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 443 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/db2.yaml b/plugins/connection-types/db2.yaml new file mode 100644 index 0000000000..303d00df86 --- /dev/null +++ b/plugins/connection-types/db2.yaml @@ -0,0 +1,35 @@ +schemaVersion: 1 +order: 540 +dbType: db2 +rustVariant: Db2 +label: IBM DB2 +runtimeMode: agent +mcpMode: bridge +agentKey: db2 +driverStoreVisible: true +driverStoreOrder: 24 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 50000 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/doris.yaml b/plugins/connection-types/doris.yaml new file mode 100644 index 0000000000..81cc98339f --- /dev/null +++ b/plugins/connection-types/doris.yaml @@ -0,0 +1,30 @@ +schemaVersion: 1 +order: 220 +dbType: doris +rustVariant: Doris +label: Doris +dialect: Doris +runtimeMode: native +mcpMode: direct +singleConnectionPool: false +metadataConnectionScoped: true +skipTcpProbe: false +defaultPort: 9030 +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: false + sqlFileExecution: true + databaseCreate: true + fieldLineage: false + sqlExplain: false + userAdmin: true + driverManagement: false diff --git a/plugins/connection-types/duckdb.yaml b/plugins/connection-types/duckdb.yaml new file mode 100644 index 0000000000..8324b35523 --- /dev/null +++ b/plugins/connection-types/duckdb.yaml @@ -0,0 +1,38 @@ +schemaVersion: 1 +order: 80 +dbType: duckdb +rustVariant: DuckDb +label: DuckDB +dialect: DuckDB +runtimeMode: file +mcpMode: bridge +managedDrivers: + - key: duckdb + label: DuckDB + storeVisible: true + storeOrder: 43 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +localFile: true +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/dynamodb.yaml b/plugins/connection-types/dynamodb.yaml new file mode 100644 index 0000000000..b5bfc42392 --- /dev/null +++ b/plugins/connection-types/dynamodb.yaml @@ -0,0 +1,29 @@ +schemaVersion: 1 +order: 120 +dbType: dynamodb +rustVariant: DynamoDb +label: Amazon DynamoDB +runtimeMode: native +mcpMode: bridge +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 8000 +supportLevel: operate +capabilities: + queryExecution: false + metadataBrowse: true + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/easysearch.yaml b/plugins/connection-types/easysearch.yaml new file mode 100644 index 0000000000..25e41cf632 --- /dev/null +++ b/plugins/connection-types/easysearch.yaml @@ -0,0 +1,29 @@ +schemaVersion: 1 +order: 150 +dbType: easysearch +rustVariant: Easysearch +label: Easysearch +runtimeMode: native +mcpMode: bridge +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 9200 +supportLevel: connect +capabilities: + queryExecution: true + metadataBrowse: false + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/elasticsearch.yaml b/plugins/connection-types/elasticsearch.yaml new file mode 100644 index 0000000000..87284aed2f --- /dev/null +++ b/plugins/connection-types/elasticsearch.yaml @@ -0,0 +1,29 @@ +schemaVersion: 1 +order: 140 +dbType: elasticsearch +rustVariant: Elasticsearch +label: Elasticsearch +runtimeMode: native +mcpMode: bridge +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 9200 +supportLevel: connect +capabilities: + queryExecution: true + metadataBrowse: false + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/etcd.yaml b/plugins/connection-types/etcd.yaml new file mode 100644 index 0000000000..96e5e5cc17 --- /dev/null +++ b/plugins/connection-types/etcd.yaml @@ -0,0 +1,32 @@ +schemaVersion: 1 +order: 670 +dbType: etcd +rustVariant: Etcd +label: etcd +runtimeMode: agent +mcpMode: bridge +agentKey: etcd +driverStoreVisible: true +driverStoreOrder: 39 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 2379 +supportLevel: connect +capabilities: + queryExecution: true + metadataBrowse: false + objectBrowser: false + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/exasol.yaml b/plugins/connection-types/exasol.yaml new file mode 100644 index 0000000000..650eca0f49 --- /dev/null +++ b/plugins/connection-types/exasol.yaml @@ -0,0 +1,36 @@ +schemaVersion: 1 +order: 410 +dbType: exasol +rustVariant: Exasol +label: Exasol +dialect: Exasol +runtimeMode: agent +mcpMode: bridge +agentKey: exasol +driverStoreVisible: true +driverStoreOrder: 13 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 8563 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/firebird.yaml b/plugins/connection-types/firebird.yaml new file mode 100644 index 0000000000..57d4cd0294 --- /dev/null +++ b/plugins/connection-types/firebird.yaml @@ -0,0 +1,35 @@ +schemaVersion: 1 +order: 400 +dbType: firebird +rustVariant: Firebird +label: Firebird +dialect: Firebird +runtimeMode: agent +mcpMode: bridge +agentKey: firebird +driverStoreVisible: true +driverStoreOrder: 12 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 3050 +traits: + singleDatabase: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/gaussdb.yaml b/plugins/connection-types/gaussdb.yaml new file mode 100644 index 0000000000..897270ade1 --- /dev/null +++ b/plugins/connection-types/gaussdb.yaml @@ -0,0 +1,37 @@ +schemaVersion: 1 +order: 330 +dbType: gaussdb +rustVariant: Gaussdb +label: GaussDB +dialect: GaussDB +runtimeMode: native +mcpMode: bridge +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 5432 +traits: + schemaAware: true + clearableQuerySchema: true + treeSchema: true + pgVacuum: true + pgLikeStructure: true + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: true + fieldLineage: true + sqlExplain: false + userAdmin: true + driverManagement: false diff --git a/plugins/connection-types/gbase.yaml b/plugins/connection-types/gbase.yaml new file mode 100644 index 0000000000..b006aa814c --- /dev/null +++ b/plugins/connection-types/gbase.yaml @@ -0,0 +1,47 @@ +schemaVersion: 1 +order: 450 +dbType: gbase +rustVariant: Gbase +label: 南大通用 GBase 8a +dialect: GBase +runtimeMode: agent +mcpMode: bridge +agentKey: gbase8a +driverStoreVisible: true +driverStoreOrder: 15 +driverProfiles: + - profile: gbase8s + agentKey: gbase8s + label: 南大通用 GBase 8s + storeVisible: true + storeOrder: 16 + - profile: gbase8a + agentKey: gbase8a + label: 南大通用 GBase 8a + storeVisible: true + storeOrder: 15 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 5258 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/goldendb.yaml b/plugins/connection-types/goldendb.yaml new file mode 100644 index 0000000000..397dff71eb --- /dev/null +++ b/plugins/connection-types/goldendb.yaml @@ -0,0 +1,33 @@ +schemaVersion: 1 +order: 310 +dbType: goldendb +rustVariant: Goldendb +label: 金篆 GoldenDB +dialect: GoldenDB +runtimeMode: agent +mcpMode: bridge +agentKey: goldendb +driverStoreVisible: true +driverStoreOrder: 6 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 3306 +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: true + fieldLineage: false + sqlExplain: false + userAdmin: true + driverManagement: true diff --git a/plugins/connection-types/h2.yaml b/plugins/connection-types/h2.yaml new file mode 100644 index 0000000000..449e1b6cfe --- /dev/null +++ b/plugins/connection-types/h2.yaml @@ -0,0 +1,59 @@ +schemaVersion: 1 +order: 470 +dbType: h2 +rustVariant: H2 +label: H2 +dialect: H2 +runtimeMode: agent +mcpMode: bridge +agentKey: h2 +driverStoreVisible: true +driverStoreOrder: 19 +driverProfiles: + - profile: h2-legacy + agentKey: h2 + packageKey: h2-legacy + label: H2 2.1 Legacy + storeVisible: false + - profile: h2-v1 + agentKey: h2 + label: H2 1.x + storeVisible: false + - profile: h2-v2 + agentKey: h2 + label: H2 2.0–2.1 + storeVisible: false + - profile: h2-v3 + agentKey: h2 + label: H2 2.2+ + storeVisible: false + - profile: h2-custom + agentKey: h2 + label: H2 Custom JAR + storeVisible: false +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +localFile: true +defaultPort: 9092 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/hbase.yaml b/plugins/connection-types/hbase.yaml new file mode 100644 index 0000000000..4bb6383fdf --- /dev/null +++ b/plugins/connection-types/hbase.yaml @@ -0,0 +1,29 @@ +schemaVersion: 1 +order: 170 +dbType: hbase +rustVariant: Hbase +label: Apache HBase +runtimeMode: native +mcpMode: bridge +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 8080 +supportLevel: operate +capabilities: + queryExecution: false + metadataBrowse: true + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/highgo.yaml b/plugins/connection-types/highgo.yaml new file mode 100644 index 0000000000..d359ab5dd4 --- /dev/null +++ b/plugins/connection-types/highgo.yaml @@ -0,0 +1,37 @@ +schemaVersion: 1 +order: 280 +dbType: highgo +rustVariant: Highgo +label: 瀚高 HighGo +dialect: HighGo +runtimeMode: agent +mcpMode: bridge +agentKey: highgo +driverStoreVisible: true +driverStoreOrder: 3 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 5866 +traits: + schemaAware: true + treeSchema: true + pgVacuum: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: false + sqlFileExecution: true + databaseCreate: true + fieldLineage: false + sqlExplain: false + userAdmin: true + driverManagement: true diff --git a/plugins/connection-types/hive.yaml b/plugins/connection-types/hive.yaml new file mode 100644 index 0000000000..4347060fe0 --- /dev/null +++ b/plugins/connection-types/hive.yaml @@ -0,0 +1,34 @@ +schemaVersion: 1 +order: 510 +dbType: hive +rustVariant: Hive +label: Apache Hive +runtimeMode: agent +mcpMode: bridge +agentKey: hive +driverStoreVisible: true +driverStoreOrder: 22 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 10000 +traits: + schemaAware: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/ignite.yaml b/plugins/connection-types/ignite.yaml new file mode 100644 index 0000000000..f794e5effe --- /dev/null +++ b/plugins/connection-types/ignite.yaml @@ -0,0 +1,35 @@ +schemaVersion: 1 +order: 610 +dbType: ignite +rustVariant: Ignite +label: Apache Ignite +runtimeMode: agent +mcpMode: bridge +agentKey: ignite +driverStoreVisible: true +driverStoreOrder: 31 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 10800 +traits: + schemaAware: true + treeSchema: true +supportLevel: understand +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/ignite3.yaml b/plugins/connection-types/ignite3.yaml new file mode 100644 index 0000000000..bf2b75b3b2 --- /dev/null +++ b/plugins/connection-types/ignite3.yaml @@ -0,0 +1,35 @@ +schemaVersion: 1 +order: 620 +dbType: ignite3 +rustVariant: Ignite3 +label: Apache Ignite 3 +runtimeMode: agent +mcpMode: bridge +agentKey: ignite3 +driverStoreVisible: true +driverStoreOrder: 32 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 10800 +traits: + schemaAware: true + treeSchema: true +supportLevel: understand +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/impala.yaml b/plugins/connection-types/impala.yaml new file mode 100644 index 0000000000..753f3a57d8 --- /dev/null +++ b/plugins/connection-types/impala.yaml @@ -0,0 +1,33 @@ +schemaVersion: 1 +order: 530 +dbType: impala +rustVariant: Impala +label: Apache Impala +runtimeMode: agent +mcpMode: bridge +agentKey: hive +driverStoreVisible: false +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 21050 +traits: + schemaAware: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: true + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/influxdb.yaml b/plugins/connection-types/influxdb.yaml new file mode 100644 index 0000000000..9d7913f0f7 --- /dev/null +++ b/plugins/connection-types/influxdb.yaml @@ -0,0 +1,31 @@ +schemaVersion: 1 +order: 750 +dbType: influxdb +rustVariant: InfluxDb +label: InfluxDB +runtimeMode: agent +mcpMode: bridge +agentKey: influxdb +driverStoreVisible: false +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 8086 +supportLevel: connect +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: true + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/informix.yaml b/plugins/connection-types/informix.yaml new file mode 100644 index 0000000000..e3f5d7f7a5 --- /dev/null +++ b/plugins/connection-types/informix.yaml @@ -0,0 +1,36 @@ +schemaVersion: 1 +order: 550 +dbType: informix +rustVariant: Informix +label: IBM Informix +dialect: Informix +runtimeMode: agent +mcpMode: bridge +agentKey: informix +driverStoreVisible: true +driverStoreOrder: 25 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 9088 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: true + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/iotdb.yaml b/plugins/connection-types/iotdb.yaml new file mode 100644 index 0000000000..bd9709cab0 --- /dev/null +++ b/plugins/connection-types/iotdb.yaml @@ -0,0 +1,34 @@ +schemaVersion: 1 +order: 730 +dbType: iotdb +rustVariant: Iotdb +label: Apache IoTDB +runtimeMode: agent +mcpMode: bridge +agentKey: iotdb +driverStoreVisible: true +driverStoreOrder: 38 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 6667 +traits: + schemaAware: true +supportLevel: understand +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/iris.yaml b/plugins/connection-types/iris.yaml new file mode 100644 index 0000000000..9a6702a9b9 --- /dev/null +++ b/plugins/connection-types/iris.yaml @@ -0,0 +1,36 @@ +schemaVersion: 1 +order: 740 +dbType: iris +rustVariant: Iris +label: InterSystems IRIS +dialect: Iris +runtimeMode: agent +mcpMode: bridge +agentKey: iris +driverStoreVisible: true +driverStoreOrder: 42 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 1972 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: false + tableStructureEdit: true + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/jdbc.yaml b/plugins/connection-types/jdbc.yaml new file mode 100644 index 0000000000..9803a26a28 --- /dev/null +++ b/plugins/connection-types/jdbc.yaml @@ -0,0 +1,33 @@ +schemaVersion: 1 +order: 770 +dbType: jdbc +rustVariant: Jdbc +label: JDBC +runtimeMode: external +mcpMode: bridge +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +formKind: jdbc +traits: + schemaAware: true + treeSchema: true + databaseObjectTree: true +supportLevel: browse +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + 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 diff --git a/plugins/connection-types/kingbase.yaml b/plugins/connection-types/kingbase.yaml new file mode 100644 index 0000000000..ff93e676c6 --- /dev/null +++ b/plugins/connection-types/kingbase.yaml @@ -0,0 +1,37 @@ +schemaVersion: 1 +order: 270 +dbType: kingbase +rustVariant: Kingbase +label: 金仓KingbaseES +dialect: Kingbase +runtimeMode: agent +mcpMode: bridge +agentKey: kingbase +driverStoreVisible: true +driverStoreOrder: 2 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 54321 +traits: + schemaAware: true + treeSchema: true + pgVacuum: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: true + fieldLineage: false + sqlExplain: false + userAdmin: true + driverManagement: true diff --git a/plugins/connection-types/kwdb.yaml b/plugins/connection-types/kwdb.yaml new file mode 100644 index 0000000000..4e7dccc82f --- /dev/null +++ b/plugins/connection-types/kwdb.yaml @@ -0,0 +1,36 @@ +schemaVersion: 1 +order: 340 +dbType: kwdb +rustVariant: Kwdb +label: KWDB +dialect: KwDB +runtimeMode: native +mcpMode: direct +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 26257 +traits: + schemaAware: true + treeSchema: true + pgVacuum: true + pgLikeStructure: true + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: true + fieldLineage: true + sqlExplain: false + userAdmin: true + driverManagement: false diff --git a/plugins/connection-types/kylin.yaml b/plugins/connection-types/kylin.yaml new file mode 100644 index 0000000000..2c4cb1e0b8 --- /dev/null +++ b/plugins/connection-types/kylin.yaml @@ -0,0 +1,32 @@ +schemaVersion: 1 +order: 600 +dbType: kylin +rustVariant: Kylin +label: Apache Kylin +runtimeMode: agent +mcpMode: bridge +agentKey: kylin +driverStoreVisible: true +driverStoreOrder: 30 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 7070 +supportLevel: understand +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/kyuubi.yaml b/plugins/connection-types/kyuubi.yaml new file mode 100644 index 0000000000..c13f03c7bc --- /dev/null +++ b/plugins/connection-types/kyuubi.yaml @@ -0,0 +1,33 @@ +schemaVersion: 1 +order: 520 +dbType: kyuubi +rustVariant: Kyuubi +label: Apache Kyuubi +runtimeMode: agent +mcpMode: bridge +agentKey: hive +driverStoreVisible: false +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 10009 +traits: + schemaAware: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: true + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/manticoresearch.yaml b/plugins/connection-types/manticoresearch.yaml new file mode 100644 index 0000000000..e5374cd17a --- /dev/null +++ b/plugins/connection-types/manticoresearch.yaml @@ -0,0 +1,30 @@ +schemaVersion: 1 +order: 240 +dbType: manticoresearch +rustVariant: ManticoreSearch +label: Manticore Search +dialect: ManticoreSearch +runtimeMode: native +mcpMode: direct +singleConnectionPool: false +metadataConnectionScoped: true +skipTcpProbe: false +defaultPort: 9306 +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: true + tableStructureEdit: true + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/meilisearch.yaml b/plugins/connection-types/meilisearch.yaml new file mode 100644 index 0000000000..fea9b68d27 --- /dev/null +++ b/plugins/connection-types/meilisearch.yaml @@ -0,0 +1,29 @@ +schemaVersion: 1 +order: 160 +dbType: meilisearch +rustVariant: Meilisearch +label: Meilisearch +runtimeMode: native +mcpMode: bridge +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 7700 +supportLevel: browse +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/milvus.yaml b/plugins/connection-types/milvus.yaml new file mode 100644 index 0000000000..f4f5252eee --- /dev/null +++ b/plugins/connection-types/milvus.yaml @@ -0,0 +1,29 @@ +schemaVersion: 1 +order: 200 +dbType: milvus +rustVariant: Milvus +label: Milvus +runtimeMode: native +mcpMode: bridge +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 19530 +supportLevel: browse +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/mongodb.yaml b/plugins/connection-types/mongodb.yaml new file mode 100644 index 0000000000..2d04fd335a --- /dev/null +++ b/plugins/connection-types/mongodb.yaml @@ -0,0 +1,37 @@ +schemaVersion: 1 +order: 110 +dbType: mongodb +rustVariant: MongoDb +label: MongoDB (Legacy) +runtimeMode: agent +mcpMode: bridge +agentKey: mongodb +driverStoreVisible: true +driverStoreOrder: 41 +driverProfiles: + - profile: mongodb-legacy + agentKey: mongodb + label: MongoDB (Legacy) + storeVisible: false +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 27017 +supportLevel: connect +capabilities: + queryExecution: true + metadataBrowse: false + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: true + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/mq.yaml b/plugins/connection-types/mq.yaml new file mode 100644 index 0000000000..b864ec2507 --- /dev/null +++ b/plugins/connection-types/mq.yaml @@ -0,0 +1,46 @@ +schemaVersion: 1 +order: 710 +dbType: mq +rustVariant: MessageQueue +label: Message Queue +runtimeMode: native +mcpMode: unsupported +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 8080 +formKind: mq +driverProfiles: + - profile: kafka + label: Apache Kafka + agentKey: kafka + storeVisible: true + storeOrder: 44 + - profile: rocketmq + label: Apache RocketMQ + agentKey: rocketmq + storeVisible: true + storeOrder: 45 + - profile: rabbitmq + label: RabbitMQ + agentKey: rabbitmq + storeVisible: true + storeOrder: 46 +supportLevel: connect +capabilities: + queryExecution: false + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/mqtt.yaml b/plugins/connection-types/mqtt.yaml new file mode 100644 index 0000000000..81fb67452f --- /dev/null +++ b/plugins/connection-types/mqtt.yaml @@ -0,0 +1,31 @@ +schemaVersion: 1 +order: 720 +dbType: mqtt +rustVariant: Mqtt +label: MQTT +runtimeMode: native +mcpMode: unsupported +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 1883 +formKind: mqtt +supportLevel: connect +specializedSurface: true +capabilities: + queryExecution: false + metadataBrowse: false + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/mysql.yaml b/plugins/connection-types/mysql.yaml new file mode 100644 index 0000000000..c1e69f87f4 --- /dev/null +++ b/plugins/connection-types/mysql.yaml @@ -0,0 +1,32 @@ +schemaVersion: 1 +order: 10 +dbType: mysql +rustVariant: Mysql +label: MySQL +dialect: MySQL +runtimeMode: native +mcpMode: direct +singleConnectionPool: false +metadataConnectionScoped: true +skipTcpProbe: false +defaultPort: 3306 +traits: + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: true + fieldLineage: true + sqlExplain: true + userAdmin: true + driverManagement: false diff --git a/plugins/connection-types/nacos.yaml b/plugins/connection-types/nacos.yaml new file mode 100644 index 0000000000..08abed481f --- /dev/null +++ b/plugins/connection-types/nacos.yaml @@ -0,0 +1,31 @@ +schemaVersion: 1 +order: 690 +dbType: nacos +rustVariant: Nacos +label: Nacos +runtimeMode: native +mcpMode: unsupported +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 8848 +formKind: nacos +supportLevel: connect +specializedSurface: true +capabilities: + queryExecution: false + metadataBrowse: false + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/neo4j.yaml b/plugins/connection-types/neo4j.yaml new file mode 100644 index 0000000000..eb6a5de96e --- /dev/null +++ b/plugins/connection-types/neo4j.yaml @@ -0,0 +1,32 @@ +schemaVersion: 1 +order: 560 +dbType: neo4j +rustVariant: Neo4j +label: Neo4j +runtimeMode: agent +mcpMode: bridge +agentKey: neo4j +driverStoreVisible: true +driverStoreOrder: 26 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 7687 +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/oceanbase-oracle.yaml b/plugins/connection-types/oceanbase-oracle.yaml new file mode 100644 index 0000000000..a6b2d480f1 --- /dev/null +++ b/plugins/connection-types/oceanbase-oracle.yaml @@ -0,0 +1,39 @@ +schemaVersion: 1 +order: 440 +dbType: oceanbase-oracle +rustVariant: OceanbaseOracle +label: OceanBase Oracle Mode +dialect: OceanBase +runtimeMode: agent +mcpMode: bridge +agentKey: oceanbase-oracle +driverStoreVisible: true +driverStoreOrder: 14 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 2883 +traits: + schemaAware: true + singleDatabase: true + clearableQuerySchema: true + treeSchema: true + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: true + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/opengauss.yaml b/plugins/connection-types/opengauss.yaml new file mode 100644 index 0000000000..ef4035adc7 --- /dev/null +++ b/plugins/connection-types/opengauss.yaml @@ -0,0 +1,36 @@ +schemaVersion: 1 +order: 420 +dbType: opengauss +rustVariant: OpenGauss +label: openGauss +dialect: openGauss +runtimeMode: native +mcpMode: bridge +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 5432 +traits: + schemaAware: true + treeSchema: true + pgVacuum: true + pgLikeStructure: true + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: false + dataTransfer: true + sqlFileExecution: true + databaseCreate: true + fieldLineage: true + sqlExplain: false + userAdmin: true + driverManagement: false diff --git a/plugins/connection-types/oracle.yaml b/plugins/connection-types/oracle.yaml new file mode 100644 index 0000000000..45d4fc70bf --- /dev/null +++ b/plugins/connection-types/oracle.yaml @@ -0,0 +1,48 @@ +schemaVersion: 1 +order: 130 +dbType: oracle +rustVariant: Oracle +label: Oracle +dialect: Oracle +runtimeMode: agent +mcpMode: bridge +agentKey: oracle +driverStoreVisible: true +driverStoreOrder: 18 +driverProfiles: + - profile: oracle-legacy + agentKey: oracle + label: Oracle + storeVisible: false + - profile: oracle-10g + agentKey: oracle + label: Oracle + storeVisible: false +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 1521 +traits: + schemaAware: true + singleDatabase: true + clearableQuerySchema: true + fetchFirst: true + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: true + sqlExplain: true + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/oscar.yaml b/plugins/connection-types/oscar.yaml new file mode 100644 index 0000000000..8b897e6669 --- /dev/null +++ b/plugins/connection-types/oscar.yaml @@ -0,0 +1,35 @@ +schemaVersion: 1 +order: 640 +dbType: oscar +rustVariant: Oscar +label: 神通 OSCAR +runtimeMode: agent +mcpMode: bridge +agentKey: oscar +driverStoreVisible: true +driverStoreOrder: 34 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 2003 +traits: + schemaAware: true + treeSchema: true +supportLevel: browse +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: true + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/postgres.yaml b/plugins/connection-types/postgres.yaml new file mode 100644 index 0000000000..c48cab34bd --- /dev/null +++ b/plugins/connection-types/postgres.yaml @@ -0,0 +1,36 @@ +schemaVersion: 1 +order: 20 +dbType: postgres +rustVariant: Postgres +label: PostgreSQL +dialect: PostgreSQL +runtimeMode: native +mcpMode: direct +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 5432 +traits: + schemaAware: true + treeSchema: true + pgVacuum: true + pgLikeStructure: true + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: true + fieldLineage: true + sqlExplain: true + userAdmin: true + driverManagement: false diff --git a/plugins/connection-types/prestosql.yaml b/plugins/connection-types/prestosql.yaml new file mode 100644 index 0000000000..be095e26fc --- /dev/null +++ b/plugins/connection-types/prestosql.yaml @@ -0,0 +1,33 @@ +schemaVersion: 1 +order: 500 +dbType: prestosql +rustVariant: PrestoSql +label: PrestoSQL +runtimeMode: external +mcpMode: bridge +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 8080 +traits: + schemaAware: true + databaseSchemaQualified: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/profiles/catalog.yaml b/plugins/connection-types/profiles/catalog.yaml new file mode 100644 index 0000000000..e78a5ddc03 --- /dev/null +++ b/plugins/connection-types/profiles/catalog.yaml @@ -0,0 +1,727 @@ +schemaVersion: 1 +profiles: + - id: mysql + dbType: mysql + label: MySQL + icon: mysql + port: 3306 + user: root + urlParams: "" + category: sql + - id: postgres + dbType: postgres + label: PostgreSQL + icon: postgres + port: 5432 + user: postgres + urlParams: "" + category: sql + - id: cloudberry + dbType: postgres + label: Apache Cloudberry + icon: cloudberry + port: 5432 + user: postgres + urlParams: "" + category: analytics + - id: opentenbase + dbType: postgres + label: OpenTenBase + icon: opentenbase + port: 11000 + user: opentenbase + urlParams: "" + category: domestic + - id: redis + dbType: redis + label: Redis + icon: redis + port: 6379 + user: "" + category: document + - id: sqlite + dbType: sqlite + label: SQLite + icon: sqlite + port: 0 + user: "" + category: lightweight + - id: rqlite + dbType: rqlite + label: RQLite + icon: rqlite + port: 4001 + user: "" + category: lightweight + - id: turso + dbType: turso + label: Turso + icon: turso + port: 443 + user: "" + category: lightweight + - id: cloudflare-d1 + dbType: cloudflare-d1 + label: Cloudflare D1 + icon: cloudflare-d1 + port: 443 + user: "" + category: lightweight + - id: duckdb + dbType: duckdb + label: DuckDB + icon: duckdb + port: 0 + user: "" + category: lightweight + - id: access + dbType: access + label: Microsoft Access + icon: access + port: 0 + user: "" + category: lightweight + - id: mongodb + dbType: mongodb + label: MongoDB + icon: mongodb + port: 27017 + user: "" + category: document + - id: mongodb-legacy + dbType: mongodb + label: MongoDB (Legacy) + icon: mongodb + port: 27017 + user: "" + - id: dynamodb + dbType: dynamodb + label: Amazon DynamoDB + icon: dynamodb + port: 443 + user: "" + host: dynamodb.us-east-1.amazonaws.com + category: document + - id: clickhouse + dbType: clickhouse + label: ClickHouse + icon: clickhouse + port: 8123 + user: default + category: analytics + - id: sqlserver + dbType: sqlserver + label: SQL Server + icon: sqlserver + port: 1433 + user: sa + category: sql + - id: oracle + dbType: oracle + label: Oracle + icon: oracle + port: 1521 + user: system + category: sql + - id: elasticsearch + dbType: elasticsearch + label: Elasticsearch + icon: elasticsearch + port: 9200 + user: "" + category: document + - id: easysearch + dbType: easysearch + label: Easysearch + icon: easysearch + port: 9200 + user: "" + category: document + - id: meilisearch + dbType: meilisearch + label: Meilisearch + icon: meilisearch + port: 7700 + user: "" + category: document + - id: hbase + dbType: hbase + label: Apache HBase + icon: hbase + port: 8080 + user: "" + category: document + - id: qdrant + dbType: qdrant + label: Qdrant + icon: qdrant + port: 6333 + user: "" + category: graph_ai + - id: milvus + dbType: milvus + label: Milvus + icon: milvus + port: 19530 + user: root + category: graph_ai + - id: weaviate + dbType: weaviate + label: Weaviate + icon: weaviate + port: 8080 + user: "" + category: graph_ai + - id: chromadb + dbType: chromadb + label: ChromaDB + icon: chromadb + port: 8000 + user: "" + category: graph_ai + - id: mariadb + dbType: mysql + label: MariaDB + icon: mariadb + port: 3306 + user: root + category: sql + - id: tidb + dbType: mysql + label: TiDB + icon: tidb + port: 4000 + user: root + category: domestic + - id: oceanbase + dbType: mysql + label: OceanBase + icon: oceanbase + port: 2883 + user: root + category: domestic + - id: oceanbase-oracle + dbType: oceanbase-oracle + label: OceanBase Oracle Mode + icon: oceanbase + port: 2883 + user: SYS + - id: goldendb + dbType: goldendb + label: 金篆 GoldenDB + icon: goldendb + port: 3306 + user: root + category: domestic + - id: databend + dbType: databend + label: Databend + icon: databend + port: 8000 + user: databend + category: analytics + - id: tdsql + dbType: mysql + label: TDSQL + icon: tdsql + port: 3306 + user: root + category: domestic + - id: polardb + dbType: mysql + label: PolarDB + icon: polardb + port: 3306 + user: root + category: domestic + - id: greatsql + dbType: mysql + label: GreatSQL + icon: greatsql + port: 3306 + user: root + category: domestic + - id: databricks + dbType: databricks + label: Databricks SQL + icon: databricks + port: 443 + user: token + category: analytics + - id: saphana + dbType: saphana + label: SAP HANA + icon: saphana + port: 30015 + user: SYSTEM + category: analytics + - id: teradata + dbType: teradata + label: Teradata + icon: teradata + port: 1025 + user: "" + category: analytics + - id: vertica + dbType: vertica + label: Vertica + icon: vertica + port: 5433 + user: dbadmin + category: analytics + - id: firebird + dbType: firebird + label: Firebird + icon: firebird + port: 3050 + user: SYSDBA + category: sql + - id: exasol + dbType: exasol + label: Exasol + icon: exasol + port: 8563 + user: sys + category: analytics + - id: gbase + dbType: gbase + label: 南大通用 GBase 8a + icon: gbase + port: 5258 + user: gbasedbt + category: domestic + pickerLabel: 南大通用 GBase + - id: gbase8a + dbType: gbase + label: 南大通用 GBase 8a + icon: gbase + port: 5258 + user: gbasedbt + - id: gbase8s + dbType: gbase + label: 南大通用 GBase 8s + icon: gbase + port: 9088 + user: gbasedbt + - id: opengauss + dbType: opengauss + label: openGauss + icon: opengauss + port: 5432 + user: gaussdb + category: domestic + - id: gaussdb + dbType: gaussdb + label: GaussDB + icon: gaussdb + port: 5432 + user: gaussdb + category: domestic + - id: kwdb + dbType: kwdb + label: KWDB + icon: kwdb + port: 26257 + user: root + category: domestic + - id: questdb + dbType: questdb + label: QuestDB + icon: questdb + port: 8812 + user: questdb + category: timeseries + - id: kingbase + dbType: kingbase + label: 金仓KingbaseES + icon: kingbase + port: 54321 + user: system + category: domestic + - id: highgo + dbType: highgo + label: 瀚高 HighGo + icon: highgo + port: 5866 + user: highgo + category: domestic + - id: uxdb + dbType: uxdb + label: 优炫 UXDB + icon: uxdb + port: 52025 + user: uxdb + category: domestic + - id: yashandb + dbType: yashandb + label: 崖山 YashanDB + icon: yashandb + port: 1688 + user: sys + category: domestic + - id: vastbase + dbType: vastbase + label: 海量 Vastbase + icon: vastbase + port: 5432 + user: vastbase + category: domestic + - id: doris + dbType: mysql + label: Doris + icon: doris + port: 9030 + user: root + urlParams: "" + category: analytics + - id: selectdb + dbType: mysql + label: SelectDB + icon: selectdb + port: 9030 + user: root + urlParams: "" + category: analytics + - id: starrocks + dbType: mysql + label: StarRocks + icon: starrocks + port: 9030 + user: root + urlParams: "" + category: analytics + - id: manticoresearch + dbType: manticoresearch + label: Manticore Search + icon: manticoresearch + port: 9306 + user: root + urlParams: "" + category: document + - id: redshift + dbType: redshift + label: Redshift + icon: redshift + port: 5439 + user: awsuser + category: analytics + - id: cockroachdb + dbType: postgres + label: CockroachDB + icon: cockroachdb + port: 26257 + user: root + category: sql + - id: dm + dbType: dameng + label: 达梦 Dameng + icon: dm + port: 5236 + user: SYSDBA + category: domestic + - id: h2 + dbType: h2 + label: H2 + icon: h2 + port: 9092 + user: sa + category: lightweight + - id: h2-legacy + dbType: h2 + label: H2 2.1 Legacy + icon: h2 + port: 9092 + user: sa + - id: snowflake + dbType: snowflake + label: Snowflake + icon: snowflake + port: 443 + user: "" + category: analytics + - id: trino + dbType: trino + label: Trino + icon: trino + port: 8080 + user: "" + category: analytics + - id: prestosql + dbType: prestosql + label: PrestoSQL + icon: presto + pickerIcon: prestosql + port: 8080 + user: "" + category: analytics + - id: hive + dbType: hive + label: Apache Hive + icon: hive + port: 10000 + user: "" + category: analytics + pickerLabel: Hive + - id: kyuubi + dbType: kyuubi + label: Apache Kyuubi + icon: kyuubi + port: 10009 + user: "" + urlParams: auth=NONE + category: analytics + - id: impala + dbType: impala + label: Apache Impala + icon: impala + port: 21050 + user: "" + urlParams: auth=noSasl + category: analytics + - id: spark + dbType: spark + label: Apache Spark + icon: spark + port: 10015 + user: "" + category: analytics + - id: db2 + dbType: db2 + label: IBM DB2 + icon: db2 + port: 50000 + user: db2inst1 + category: sql + pickerLabel: DB2 + - id: informix + dbType: informix + label: Informix + icon: informix + port: 9088 + user: informix + category: sql + - id: dremio + dbType: jdbc + label: Dremio + icon: dremio + port: 31010 + user: "" + category: analytics + - id: jdbcx + dbType: jdbc + label: JDBCX + icon: jdbcx + port: 0 + user: "" + category: sql + - id: neo4j + dbType: neo4j + label: Neo4j + icon: neo4j + port: 7687 + user: neo4j + category: graph_ai + - id: cassandra + dbType: cassandra + label: Cassandra + icon: cassandra + port: 9042 + user: cassandra + category: document + - id: bigquery + dbType: bigquery + label: BigQuery + icon: bigquery + port: 443 + user: "" + host: https://www.googleapis.com/bigquery/v2 + category: analytics + - id: spanner + dbType: spanner + label: Cloud Spanner + icon: spanner + port: 443 + user: "" + category: sql + - id: kylin + dbType: kylin + label: Apache Kylin + icon: kylin + port: 7070 + user: ADMIN + category: analytics + pickerLabel: Kylin + - id: ignite + dbType: ignite + label: Apache Ignite + icon: ignite + port: 10800 + user: "" + category: analytics + - id: ignite3 + dbType: ignite3 + label: Apache Ignite 3 + icon: ignite + port: 10800 + user: "" + category: analytics + - id: sundb + dbType: sundb + label: 科蓝 SUNDB + icon: sundb + port: 22000 + user: root + category: domestic + - id: oscar + dbType: oscar + label: 神通 OSCAR + icon: oscar + port: 2003 + user: SYSDBA + category: domestic + - id: jdbc + dbType: jdbc + label: JDBC + icon: jdbc + port: 0 + user: "" + - id: tdengine + dbType: tdengine + label: TDengine + icon: tdengine + port: 6041 + user: root + category: timeseries + - id: xugu + dbType: xugu + label: 虚谷 XuguDB + icon: xugu + port: 5138 + user: "" + category: domestic + - id: iotdb + dbType: iotdb + label: Apache IoTDB + icon: iotdb + port: 6667 + user: root + category: timeseries + - id: etcd + dbType: etcd + label: etcd + icon: etcd + port: 2379 + user: "" + category: registry_config + - id: zookeeper + dbType: zookeeper + label: Apache ZooKeeper + icon: zookeeper + port: 2181 + user: "" + category: registry_config + - id: mq + dbType: mq + label: Apache Pulsar + icon: pulsar + pickerIcon: mq + port: 8080 + user: "" + host: 127.0.0.1 + category: mq + - id: kafka + dbType: mq + label: Apache Kafka + icon: kafka + port: 9092 + user: "" + host: 127.0.0.1 + category: mq + - id: rocketmq + dbType: mq + label: Apache RocketMQ + icon: rocketmq + port: 9876 + user: "" + host: 127.0.0.1 + category: mq + - id: rabbitmq + dbType: mq + label: RabbitMQ + icon: rabbitmq + port: 5672 + user: "" + host: 127.0.0.1 + category: mq + - id: nacos + dbType: nacos + label: Nacos + icon: nacos + port: 8848 + user: nacos + host: 127.0.0.1 + category: registry_config + - id: consul + dbType: consul + label: Consul + icon: consul + port: 8500 + user: "" + host: 127.0.0.1 + category: registry_config + - id: mqtt + dbType: mqtt + label: MQTT + icon: mqtt + port: 1883 + user: "" + host: 127.0.0.1 + category: mq + - id: iris + dbType: iris + label: IRIS + icon: iris + port: 1972 + user: _SYSTEM + category: sql + - id: influxdb + dbType: influxdb + label: InfluxDB + icon: InfluxDB + pickerIcon: influxdb + port: 8086 + user: "" + category: timeseries + - id: victoriametrics + dbType: victoriametrics + label: VictoriaMetrics + icon: victoriametrics + port: 8428 + user: "" + category: timeseries + - id: custom_mysql + dbType: mysql + label: Custom + icon: mysql + port: 3306 + user: root + urlParams: "" + category: sql + pickerLabel: Custom (MySQL) + - id: dolt + dbType: mysql + label: Dolt + icon: dolt + port: 3306 + user: root + urlParams: "" + category: sql + - id: custom_postgres + dbType: postgres + label: Custom + icon: postgres + port: 5432 + user: postgres + urlParams: "" + category: sql + pickerLabel: Custom (PostgreSQL) diff --git a/plugins/connection-types/qdrant.yaml b/plugins/connection-types/qdrant.yaml new file mode 100644 index 0000000000..6ac19a77c6 --- /dev/null +++ b/plugins/connection-types/qdrant.yaml @@ -0,0 +1,29 @@ +schemaVersion: 1 +order: 180 +dbType: qdrant +rustVariant: Qdrant +label: Qdrant +runtimeMode: native +mcpMode: bridge +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 6333 +supportLevel: browse +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/questdb.yaml b/plugins/connection-types/questdb.yaml new file mode 100644 index 0000000000..adf52ca36e --- /dev/null +++ b/plugins/connection-types/questdb.yaml @@ -0,0 +1,34 @@ +schemaVersion: 1 +order: 430 +dbType: questdb +rustVariant: Questdb +label: QuestDB +dialect: QuestDB +runtimeMode: native +mcpMode: direct +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 8812 +traits: + singleDatabase: true + pgLikeStructure: true + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: true + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/redis.yaml b/plugins/connection-types/redis.yaml new file mode 100644 index 0000000000..4a58e0b061 --- /dev/null +++ b/plugins/connection-types/redis.yaml @@ -0,0 +1,29 @@ +schemaVersion: 1 +order: 70 +dbType: redis +rustVariant: Redis +label: Redis +runtimeMode: native +mcpMode: bridge +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 6379 +supportLevel: connect +capabilities: + queryExecution: true + metadataBrowse: false + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/redshift.yaml b/plugins/connection-types/redshift.yaml new file mode 100644 index 0000000000..9cdbe930d0 --- /dev/null +++ b/plugins/connection-types/redshift.yaml @@ -0,0 +1,35 @@ +schemaVersion: 1 +order: 250 +dbType: redshift +rustVariant: Redshift +label: Redshift +dialect: Redshift +runtimeMode: native +mcpMode: direct +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 5439 +traits: + schemaAware: true + treeSchema: true + pgLikeStructure: true + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: false + sqlFileExecution: true + databaseCreate: true + fieldLineage: true + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/rqlite.yaml b/plugins/connection-types/rqlite.yaml new file mode 100644 index 0000000000..d7f28dfb2f --- /dev/null +++ b/plugins/connection-types/rqlite.yaml @@ -0,0 +1,32 @@ +schemaVersion: 1 +order: 40 +dbType: rqlite +rustVariant: Rqlite +label: RQLite +dialect: Rqlite +runtimeMode: native +mcpMode: direct +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 4001 +traits: + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: true + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/saphana.yaml b/plugins/connection-types/saphana.yaml new file mode 100644 index 0000000000..045b420f6f --- /dev/null +++ b/plugins/connection-types/saphana.yaml @@ -0,0 +1,35 @@ +schemaVersion: 1 +order: 370 +dbType: saphana +rustVariant: SapHana +label: SAP HANA +runtimeMode: agent +mcpMode: bridge +agentKey: saphana +driverStoreVisible: true +driverStoreOrder: 9 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 30015 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/snowflake.yaml b/plugins/connection-types/snowflake.yaml new file mode 100644 index 0000000000..bb33f97967 --- /dev/null +++ b/plugins/connection-types/snowflake.yaml @@ -0,0 +1,34 @@ +schemaVersion: 1 +order: 480 +dbType: snowflake +rustVariant: Snowflake +label: Snowflake +runtimeMode: agent +mcpMode: bridge +agentKey: snowflake +driverStoreVisible: true +driverStoreOrder: 20 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 443 +traits: + schemaAware: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: true + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/spanner.yaml b/plugins/connection-types/spanner.yaml new file mode 100644 index 0000000000..988f3fd0ba --- /dev/null +++ b/plugins/connection-types/spanner.yaml @@ -0,0 +1,35 @@ +schemaVersion: 1 +order: 590 +dbType: spanner +rustVariant: Spanner +label: Google Cloud Spanner +runtimeMode: agent +mcpMode: bridge +agentKey: spanner +driverStoreVisible: true +driverStoreOrder: 29 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 443 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/spark.yaml b/plugins/connection-types/spark.yaml new file mode 100644 index 0000000000..ee0fc8f582 --- /dev/null +++ b/plugins/connection-types/spark.yaml @@ -0,0 +1,34 @@ +schemaVersion: 1 +order: 780 +dbType: spark +rustVariant: Spark +label: Apache Spark +runtimeMode: agent +mcpMode: bridge +agentKey: spark +driverStoreVisible: true +driverStoreOrder: 23 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 10015 +traits: + schemaAware: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/sqlite.yaml b/plugins/connection-types/sqlite.yaml new file mode 100644 index 0000000000..dd9e70300d --- /dev/null +++ b/plugins/connection-types/sqlite.yaml @@ -0,0 +1,32 @@ +schemaVersion: 1 +order: 30 +dbType: sqlite +rustVariant: Sqlite +label: SQLite +dialect: SQLite +runtimeMode: file +mcpMode: direct +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +localFile: true +traits: + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: true + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/sqlserver.yaml b/plugins/connection-types/sqlserver.yaml new file mode 100644 index 0000000000..cdc3ff0b89 --- /dev/null +++ b/plugins/connection-types/sqlserver.yaml @@ -0,0 +1,41 @@ +schemaVersion: 1 +order: 100 +dbType: sqlserver +rustVariant: SqlServer +label: SQL Server +dialect: SQL Server +runtimeMode: native +mcpMode: bridge +driverProfiles: + - profile: sqlserver-legacy + agentKey: sqlserver-legacy + label: SQL Server legacy compatibility component + storeVisible: true + storeOrder: 47 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 1433 +traits: + schemaAware: true + databaseSchemaQualified: true + treeSchema: true + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: true + fieldLineage: true + sqlExplain: true + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/starrocks.yaml b/plugins/connection-types/starrocks.yaml new file mode 100644 index 0000000000..732f077942 --- /dev/null +++ b/plugins/connection-types/starrocks.yaml @@ -0,0 +1,30 @@ +schemaVersion: 1 +order: 230 +dbType: starrocks +rustVariant: StarRocks +label: StarRocks +dialect: StarRocks +runtimeMode: native +mcpMode: direct +singleConnectionPool: false +metadataConnectionScoped: true +skipTcpProbe: false +defaultPort: 9030 +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: false + sqlFileExecution: true + databaseCreate: true + fieldLineage: false + sqlExplain: false + userAdmin: true + driverManagement: false diff --git a/plugins/connection-types/sundb.yaml b/plugins/connection-types/sundb.yaml new file mode 100644 index 0000000000..8b4968fcd2 --- /dev/null +++ b/plugins/connection-types/sundb.yaml @@ -0,0 +1,33 @@ +schemaVersion: 1 +order: 630 +dbType: sundb +rustVariant: Sundb +label: 科蓝 SUNDB +dialect: SunDB +runtimeMode: agent +mcpMode: bridge +agentKey: sundb +driverStoreVisible: true +driverStoreOrder: 33 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 22581 +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: true + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/tdengine.yaml b/plugins/connection-types/tdengine.yaml new file mode 100644 index 0000000000..b853ddb19c --- /dev/null +++ b/plugins/connection-types/tdengine.yaml @@ -0,0 +1,32 @@ +schemaVersion: 1 +order: 650 +dbType: tdengine +rustVariant: Tdengine +label: TDengine +runtimeMode: agent +mcpMode: bridge +agentKey: tdengine +driverStoreVisible: true +driverStoreOrder: 36 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 6041 +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: true + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/teradata.yaml b/plugins/connection-types/teradata.yaml new file mode 100644 index 0000000000..eb1870a26e --- /dev/null +++ b/plugins/connection-types/teradata.yaml @@ -0,0 +1,35 @@ +schemaVersion: 1 +order: 380 +dbType: teradata +rustVariant: Teradata +label: Teradata +runtimeMode: agent +mcpMode: bridge +agentKey: teradata +driverStoreVisible: true +driverStoreOrder: 10 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 1025 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/trino.yaml b/plugins/connection-types/trino.yaml new file mode 100644 index 0000000000..1dc11b8375 --- /dev/null +++ b/plugins/connection-types/trino.yaml @@ -0,0 +1,36 @@ +schemaVersion: 1 +order: 490 +dbType: trino +rustVariant: Trino +label: Trino +runtimeMode: agent +mcpMode: bridge +agentKey: trino +driverStoreVisible: true +driverStoreOrder: 21 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 8080 +traits: + schemaAware: true + databaseSchemaQualified: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: true + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/turso.yaml b/plugins/connection-types/turso.yaml new file mode 100644 index 0000000000..e371dc0da2 --- /dev/null +++ b/plugins/connection-types/turso.yaml @@ -0,0 +1,32 @@ +schemaVersion: 1 +order: 50 +dbType: turso +rustVariant: Turso +label: Turso +dialect: Turso +runtimeMode: native +mcpMode: direct +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 443 +traits: + diagramSql: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: true + sqlFileExecution: true + databaseCreate: false + fieldLineage: true + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/uxdb.yaml b/plugins/connection-types/uxdb.yaml new file mode 100644 index 0000000000..256e0eeab3 --- /dev/null +++ b/plugins/connection-types/uxdb.yaml @@ -0,0 +1,37 @@ +schemaVersion: 1 +order: 290 +dbType: uxdb +rustVariant: Uxdb +label: 优炫 UXDB +dialect: PostgreSQL +runtimeMode: agent +mcpMode: bridge +agentKey: uxdb +driverStoreVisible: true +driverStoreOrder: 4 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 52025 +traits: + schemaAware: true + treeSchema: true + pgVacuum: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/vastbase.yaml b/plugins/connection-types/vastbase.yaml new file mode 100644 index 0000000000..bc44e937f1 --- /dev/null +++ b/plugins/connection-types/vastbase.yaml @@ -0,0 +1,37 @@ +schemaVersion: 1 +order: 300 +dbType: vastbase +rustVariant: Vastbase +label: 海量 Vastbase +dialect: Vastbase +runtimeMode: agent +mcpMode: bridge +agentKey: vastbase +driverStoreVisible: true +driverStoreOrder: 5 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 5432 +traits: + schemaAware: true + treeSchema: true + pgVacuum: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: false + sqlFileExecution: true + databaseCreate: true + fieldLineage: false + sqlExplain: false + userAdmin: true + driverManagement: true diff --git a/plugins/connection-types/vertica.yaml b/plugins/connection-types/vertica.yaml new file mode 100644 index 0000000000..79ac745cd4 --- /dev/null +++ b/plugins/connection-types/vertica.yaml @@ -0,0 +1,36 @@ +schemaVersion: 1 +order: 390 +dbType: vertica +rustVariant: Vertica +label: Vertica +dialect: Vertica +runtimeMode: agent +mcpMode: bridge +agentKey: vertica +driverStoreVisible: true +driverStoreOrder: 11 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 5433 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/victoriametrics.yaml b/plugins/connection-types/victoriametrics.yaml new file mode 100644 index 0000000000..3c8099e972 --- /dev/null +++ b/plugins/connection-types/victoriametrics.yaml @@ -0,0 +1,31 @@ +schemaVersion: 1 +order: 760 +dbType: victoriametrics +rustVariant: VictoriaMetrics +label: VictoriaMetrics +runtimeMode: native +mcpMode: bridge +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 8428 +traits: + singleDatabase: true +supportLevel: browse +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + 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 diff --git a/plugins/connection-types/weaviate.yaml b/plugins/connection-types/weaviate.yaml new file mode 100644 index 0000000000..6df6392224 --- /dev/null +++ b/plugins/connection-types/weaviate.yaml @@ -0,0 +1,29 @@ +schemaVersion: 1 +order: 210 +dbType: weaviate +rustVariant: Weaviate +label: Weaviate +runtimeMode: native +mcpMode: bridge +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: false +defaultPort: 8080 +supportLevel: browse +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: false + objectSource: false + schemaSearch: false + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: false diff --git a/plugins/connection-types/xugu.yaml b/plugins/connection-types/xugu.yaml new file mode 100644 index 0000000000..15aa9fec1d --- /dev/null +++ b/plugins/connection-types/xugu.yaml @@ -0,0 +1,36 @@ +schemaVersion: 1 +order: 660 +dbType: xugu +rustVariant: Xugu +label: 虚谷 XuguDB +dialect: Xugu +runtimeMode: agent +mcpMode: bridge +agentKey: xugu +driverStoreVisible: true +driverStoreOrder: 37 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 5138 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: false + schemaSearch: true + diagram: true + tableDataEdit: false + tableStructureEdit: true + tableImport: false + dataTransfer: false + sqlFileExecution: true + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/yashandb.yaml b/plugins/connection-types/yashandb.yaml new file mode 100644 index 0000000000..fc016bc1e0 --- /dev/null +++ b/plugins/connection-types/yashandb.yaml @@ -0,0 +1,36 @@ +schemaVersion: 1 +order: 350 +dbType: yashandb +rustVariant: Yashandb +label: 崖山 YashanDB +dialect: YashanDB +runtimeMode: agent +mcpMode: bridge +agentKey: yashandb +driverStoreVisible: true +driverStoreOrder: 35 +singleConnectionPool: true +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 1688 +traits: + schemaAware: true + treeSchema: true +supportLevel: operate +capabilities: + queryExecution: true + metadataBrowse: true + objectBrowser: true + objectSource: true + schemaSearch: true + diagram: true + tableDataEdit: true + tableStructureEdit: true + tableImport: true + dataTransfer: false + sqlFileExecution: true + databaseCreate: true + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/plugins/connection-types/zookeeper.yaml b/plugins/connection-types/zookeeper.yaml new file mode 100644 index 0000000000..af4d347f93 --- /dev/null +++ b/plugins/connection-types/zookeeper.yaml @@ -0,0 +1,32 @@ +schemaVersion: 1 +order: 680 +dbType: zookeeper +rustVariant: ZooKeeper +label: Apache ZooKeeper +runtimeMode: agent +mcpMode: bridge +agentKey: zookeeper +driverStoreVisible: true +driverStoreOrder: 40 +singleConnectionPool: false +metadataConnectionScoped: false +skipTcpProbe: true +defaultPort: 2181 +supportLevel: connect +capabilities: + queryExecution: true + metadataBrowse: false + objectBrowser: false + objectSource: false + schemaSearch: true + diagram: false + tableDataEdit: false + tableStructureEdit: false + tableImport: false + dataTransfer: false + sqlFileExecution: false + databaseCreate: false + fieldLineage: false + sqlExplain: false + userAdmin: false + driverManagement: true diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98591cc4e1..7d16d4e3a5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -264,6 +264,9 @@ importers: vue-tsc: specifier: ^3.3.3 version: 3.3.3(typescript@6.0.3) + yaml: + specifier: 2.8.4 + version: 2.8.4 packages/cli: optionalDependencies: diff --git a/scripts/run-check.mjs b/scripts/run-check.mjs index 888015ee37..d820944539 100644 --- a/scripts/run-check.mjs +++ b/scripts/run-check.mjs @@ -3,6 +3,11 @@ import { performance } from "node:perf_hooks"; import { delimiter, join } from "node:path"; const tasks = [ + { + name: "connection-types", + command: "node", + args: ["scripts/sync-connection-types.mjs", "--check"], + }, { name: "format", command: "oxfmt", diff --git a/scripts/sync-connection-types.mjs b/scripts/sync-connection-types.mjs new file mode 100644 index 0000000000..207c242553 --- /dev/null +++ b/scripts/sync-connection-types.mjs @@ -0,0 +1,289 @@ +import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import process from "node:process"; +import { parse } from "yaml"; + +const root = resolve(import.meta.dirname, ".."); +const connectionTypeDirectory = join(root, "plugins", "connection-types"); +const connectionProfileCatalog = join(connectionTypeDirectory, "profiles", "catalog.yaml"); +const dialectDirectory = join(root, "plugins", "dialects"); +const jsonTarget = join(root, "crates", "dbx-core", "assets", "database-drivers.manifest.json"); +const typeTarget = join(root, "apps", "desktop", "src", "types", "generated", "databaseTypes.ts"); +const profileTarget = join(root, "apps", "desktop", "src", "types", "generated", "connectionProfiles.ts"); +const checkOnly = process.argv.includes("--check"); + +const runtimeModes = new Set(["native", "file", "agent", "external"]); +const mcpModes = new Set(["direct", "bridge", "unsupported"]); +const supportLevels = new Set(["connect", "browse", "understand", "operate"]); +const formKinds = new Set(["standard", "jdbc", "mq", "mqtt", "nacos"]); +const profileCategories = new Set(["sql", "analytics", "domestic", "lightweight", "document", "graph_ai", "timeseries", "mq", "registry_config"]); +const descriptorKeys = new Set([ + "schemaVersion", + "order", + "dbType", + "rustVariant", + "label", + "dialect", + "runtimeMode", + "mcpMode", + "agentKey", + "driverStoreVisible", + "driverStoreOrder", + "driverProfiles", + "managedDrivers", + "singleConnectionPool", + "metadataConnectionScoped", + "skipTcpProbe", + "defaultPort", + "localFile", + "specializedSurface", + "formKind", + "traits", + "supportLevel", + "capabilities", +]); +const profileCatalogKeys = new Set(["schemaVersion", "profiles"]); +const connectionProfileKeys = new Set(["id", "dbType", "label", "pickerLabel", "icon", "pickerIcon", "port", "user", "host", "urlParams", "category"]); +const driverProfileKeys = new Set(["profile", "agentKey", "packageKey", "label", "storeVisible", "storeOrder"]); +const managedDriverKeys = new Set(["key", "label", "storeVisible", "storeOrder"]); +const capabilityKeys = new Set([ + "queryExecution", + "metadataBrowse", + "objectBrowser", + "objectSource", + "schemaSearch", + "diagram", + "tableDataEdit", + "tableStructureEdit", + "tableImport", + "dataTransfer", + "sqlFileExecution", + "databaseCreate", + "fieldLineage", + "sqlExplain", + "userAdmin", + "driverManagement", +]); +const traitKeys = new Set(["schemaAware", "databaseSchemaQualified", "singleDatabase", "clearableQuerySchema", "fetchFirst", "treeSchema", "databaseObjectTree", "pgVacuum", "pgLikeStructure", "diagramSql"]); + +function connectionTypeFiles() { + if (!existsSync(connectionTypeDirectory)) throw new Error(`Missing connection type descriptor directory: ${connectionTypeDirectory}`); + return readdirSync(connectionTypeDirectory) + .filter((file) => file.endsWith(".yaml") || file.endsWith(".yml")) + .sort(); +} + +function dialectNames() { + return new Set( + readdirSync(dialectDirectory) + .filter((file) => file.endsWith(".yaml") || file.endsWith(".yml")) + .map((file) => { + const value = parse(readFileSync(join(dialectDirectory, file), "utf8")); + return value?.dialect?.name; + }) + .filter(Boolean), + ); +} + +function loadDescriptors() { + const knownDialects = dialectNames(); + const descriptors = connectionTypeFiles().map((file) => { + const path = join(connectionTypeDirectory, file); + const descriptor = parse(readFileSync(path, "utf8")); + validateDescriptor(descriptor, file, knownDialects); + return descriptor; + }); + + const duplicateDbTypes = duplicateValues(descriptors.map((descriptor) => descriptor.dbType)); + const duplicateRustVariants = duplicateValues(descriptors.map((descriptor) => descriptor.rustVariant)); + const duplicateOrders = duplicateValues(descriptors.map((descriptor) => descriptor.order)); + if (duplicateDbTypes.length > 0) throw new Error(`Duplicate database types: ${duplicateDbTypes.join(", ")}`); + if (duplicateRustVariants.length > 0) throw new Error(`Duplicate Rust variants: ${duplicateRustVariants.join(", ")}`); + if (duplicateOrders.length > 0) throw new Error(`Duplicate connection type orders: ${duplicateOrders.join(", ")}`); + validateDriverStoreOrders(descriptors); + + return descriptors.sort((left, right) => left.order - right.order); +} + +function validateDescriptor(descriptor, file, knownDialects) { + const location = join("plugins", "connection-types", file); + if (!descriptor || typeof descriptor !== "object") throw new Error(`${location}: descriptor must be a mapping`); + validateKnownKeys(descriptor, descriptorKeys, location); + if (descriptor.schemaVersion !== 1) throw new Error(`${location}: schemaVersion must be 1`); + if (!Number.isInteger(descriptor.order) || descriptor.order <= 0) throw new Error(`${location}: order must be a positive integer`); + if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(descriptor.dbType ?? "")) throw new Error(`${location}: invalid dbType`); + if (!/^[A-Z][A-Za-z0-9]*$/.test(descriptor.rustVariant ?? "")) throw new Error(`${location}: invalid rustVariant`); + if (typeof descriptor.label !== "string" || descriptor.label.trim() === "") throw new Error(`${location}: label is required`); + if (!runtimeModes.has(descriptor.runtimeMode)) throw new Error(`${location}: invalid runtimeMode`); + if (!mcpModes.has(descriptor.mcpMode)) throw new Error(`${location}: invalid mcpMode`); + if (!supportLevels.has(descriptor.supportLevel)) throw new Error(`${location}: invalid supportLevel`); + if (descriptor.dialect && !knownDialects.has(descriptor.dialect)) throw new Error(`${location}: unknown dialect ${descriptor.dialect}`); + if (descriptor.runtimeMode === "agent" && !descriptor.agentKey) throw new Error(`${location}: agent runtime requires agentKey`); + if (descriptor.driverStoreVisible && !descriptor.agentKey) throw new Error(`${location}: driverStoreVisible requires agentKey`); + if (descriptor.driverStoreVisible) validatePositiveInteger(descriptor.driverStoreOrder, `${location}: driverStoreOrder`); + if (descriptor.defaultPort !== undefined && (!Number.isInteger(descriptor.defaultPort) || descriptor.defaultPort < 0 || descriptor.defaultPort > 65535)) { + throw new Error(`${location}: invalid defaultPort`); + } + if (!descriptor.capabilities || typeof descriptor.capabilities !== "object") throw new Error(`${location}: capabilities are required`); + validateBooleanMap(descriptor.capabilities, capabilityKeys, `${location}: capabilities`, true); + if (!Object.values(descriptor.capabilities).some(Boolean) && descriptor.specializedSurface !== true) { + throw new Error(`${location}: enable a product capability or set specializedSurface: true`); + } + if (descriptor.specializedSurface !== undefined && typeof descriptor.specializedSurface !== "boolean") { + throw new Error(`${location}: specializedSurface must be a boolean`); + } + if (descriptor.formKind !== undefined && !formKinds.has(descriptor.formKind)) { + throw new Error(`${location}: invalid formKind`); + } + if (descriptor.traits !== undefined) validateBooleanMap(descriptor.traits, traitKeys, `${location}: traits`); + for (const profile of descriptor.driverProfiles ?? []) { + validateKnownKeys(profile, driverProfileKeys, `${location}: driver profile`); + if (!profile.profile || !profile.agentKey || !profile.label) throw new Error(`${location}: driverProfiles entries require profile, agentKey, and label`); + if (profile.storeVisible !== undefined && typeof profile.storeVisible !== "boolean") throw new Error(`${location}: driver profile ${profile.profile} storeVisible must be a boolean`); + if (profile.storeVisible) validatePositiveInteger(profile.storeOrder, `${location}: driver profile ${profile.profile} storeOrder`); + } + for (const driver of descriptor.managedDrivers ?? []) { + validateKnownKeys(driver, managedDriverKeys, `${location}: managed driver`); + if (!driver.key || !driver.label) throw new Error(`${location}: managedDrivers entries require key and label`); + if (driver.storeVisible !== undefined && typeof driver.storeVisible !== "boolean") throw new Error(`${location}: managed driver ${driver.key} storeVisible must be a boolean`); + if (driver.storeVisible) validatePositiveInteger(driver.storeOrder, `${location}: managed driver ${driver.key} storeOrder`); + } +} + +function loadConnectionProfiles(descriptors) { + if (!existsSync(connectionProfileCatalog)) throw new Error(`Missing connection profile catalog: ${connectionProfileCatalog}`); + const location = join("plugins", "connection-types", "profiles", "catalog.yaml"); + const catalog = parse(readFileSync(connectionProfileCatalog, "utf8")); + if (!catalog || typeof catalog !== "object") throw new Error(`${location}: catalog must be a mapping`); + validateKnownKeys(catalog, profileCatalogKeys, location); + if (catalog.schemaVersion !== 1) throw new Error(`${location}: schemaVersion must be 1`); + if (!Array.isArray(catalog.profiles) || catalog.profiles.length === 0) throw new Error(`${location}: profiles must be a non-empty list`); + + const knownTypes = new Set(descriptors.map((descriptor) => descriptor.dbType)); + const profileIds = new Set(); + const profiles = catalog.profiles.map((profile, index) => { + const profileLocation = `${location}: profiles[${index}]`; + if (!profile || typeof profile !== "object") throw new Error(`${profileLocation} must be a mapping`); + validateKnownKeys(profile, connectionProfileKeys, profileLocation); + if (!/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/.test(profile.id ?? "")) throw new Error(`${profileLocation}: invalid id`); + if (profileIds.has(profile.id)) throw new Error(`${profileLocation}: duplicate id ${profile.id}`); + profileIds.add(profile.id); + if (!knownTypes.has(profile.dbType)) throw new Error(`${profileLocation}: unknown dbType ${profile.dbType}`); + for (const key of ["label", "icon", "user"]) { + if (typeof profile[key] !== "string") throw new Error(`${profileLocation}: ${key} must be a string`); + } + for (const key of ["pickerLabel", "pickerIcon", "host", "urlParams"]) { + if (profile[key] !== undefined && typeof profile[key] !== "string") throw new Error(`${profileLocation}: ${key} must be a string`); + } + if (!Number.isInteger(profile.port) || profile.port < 0 || profile.port > 65535) throw new Error(`${profileLocation}: invalid port`); + if (profile.category !== undefined && !profileCategories.has(profile.category)) throw new Error(`${profileLocation}: invalid category`); + return profile; + }); + + return profiles; +} + +function validateDriverStoreOrders(descriptors) { + const entries = descriptors.flatMap((descriptor) => [ + ...(descriptor.driverStoreVisible ? [{ key: descriptor.agentKey, order: descriptor.driverStoreOrder }] : []), + ...(descriptor.driverProfiles ?? []).filter((profile) => profile.storeVisible).map((profile) => ({ key: profile.packageKey ?? profile.agentKey, order: profile.storeOrder })), + ...(descriptor.managedDrivers ?? []).filter((driver) => driver.storeVisible).map((driver) => ({ key: driver.key, order: driver.storeOrder })), + ]); + const orderByKey = new Map(); + for (const entry of entries) { + const existingOrder = orderByKey.get(entry.key); + if (existingOrder !== undefined && existingOrder !== entry.order) { + throw new Error(`Driver store key ${entry.key} uses conflicting orders: ${existingOrder}, ${entry.order}`); + } + orderByKey.set(entry.key, entry.order); + } + const duplicateStoreOrders = duplicateValues([...orderByKey.values()]); + if (duplicateStoreOrders.length > 0) throw new Error(`Duplicate driver store orders: ${duplicateStoreOrders.join(", ")}`); +} + +function validatePositiveInteger(value, location) { + if (!Number.isInteger(value) || value <= 0) throw new Error(`${location} must be a positive integer`); +} + +function validateKnownKeys(value, allowedKeys, location) { + const unknownKeys = Object.keys(value).filter((key) => !allowedKeys.has(key)); + if (unknownKeys.length > 0) throw new Error(`${location} contains unknown keys: ${unknownKeys.join(", ")}`); +} + +function validateBooleanMap(value, allowedKeys, location, requireAll = false) { + if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${location} must be a mapping`); + validateKnownKeys(value, allowedKeys, location); + if (requireAll) { + const missingKeys = [...allowedKeys].filter((key) => !(key in value)); + if (missingKeys.length > 0) throw new Error(`${location} is missing keys: ${missingKeys.join(", ")}`); + } + const nonBooleanKeys = Object.entries(value) + .filter(([, entry]) => typeof entry !== "boolean") + .map(([key]) => key); + if (nonBooleanKeys.length > 0) throw new Error(`${location} must use boolean values: ${nonBooleanKeys.join(", ")}`); +} + +function duplicateValues(values) { + return [...new Set(values.filter((value, index) => values.indexOf(value) !== index))]; +} + +function publicDescriptor(descriptor) { + const { schemaVersion: _schemaVersion, order: _order, rustVariant: _rustVariant, ...publicFields } = descriptor; + return publicFields; +} + +function jsonOutput(descriptors) { + return `${JSON.stringify({ schemaVersion: 1, drivers: descriptors.map(publicDescriptor) }, null, 2)}\n`; +} + +function typeOutput(descriptors) { + const values = descriptors.map((descriptor) => ` "${descriptor.dbType}",`).join("\n"); + return `// Generated by scripts/sync-connection-types.mjs. Do not edit manually.\nexport const DATABASE_TYPES = [\n${values}\n] as const;\n\nexport type DatabaseType = (typeof DATABASE_TYPES)[number];\n`; +} + +function typescriptPropertyName(value) { + return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value) ? value : JSON.stringify(value); +} + +function profileTypeOutput(profiles) { + const profileEntries = profiles + .map((profile) => { + const fields = [ + `type: ${JSON.stringify(profile.dbType)}`, + `port: ${profile.port}`, + `user: ${JSON.stringify(profile.user)}`, + `label: ${JSON.stringify(profile.label)}`, + `icon: ${JSON.stringify(profile.icon)}`, + ...(profile.host === undefined ? [] : [`host: ${JSON.stringify(profile.host)}`]), + ...(profile.urlParams === undefined ? [] : [`urlParams: ${JSON.stringify(profile.urlParams)}`]), + ]; + return ` ${typescriptPropertyName(profile.id)}: { ${fields.join(", ")} },`; + }) + .join("\n"); + const pickerOptions = profiles + .filter((profile) => profile.category) + .map((profile) => ` { value: ${JSON.stringify(profile.id)}, label: ${JSON.stringify(profile.pickerLabel ?? profile.label)}, category: ${JSON.stringify(profile.category)} },`) + .join("\n"); + const profileIcons = profiles.map((profile) => ` ${typescriptPropertyName(profile.id)}: ${JSON.stringify(profile.pickerIcon ?? profile.icon)},`).join("\n"); + return `// Generated by scripts/sync-connection-types.mjs. Do not edit manually.\nimport type { DatabaseType } from "./databaseTypes";\n\nexport type ConnectionProfileCategory = "sql" | "analytics" | "domestic" | "lightweight" | "document" | "graph_ai" | "timeseries" | "mq" | "registry_config";\n\nexport interface ConnectionProfileDefinition {\n type: DatabaseType;\n port: number;\n user: string;\n label: string;\n icon: string;\n host?: string;\n urlParams?: string;\n}\n\nexport interface ConnectionPickerOption {\n value: string;\n label: string;\n category: ConnectionProfileCategory;\n}\n\nexport const CONNECTION_PROFILES = {\n${profileEntries}\n} as const satisfies Record;\n\nexport const CONNECTION_PROFILE_ICONS = {\n${profileIcons}\n} as const satisfies Record;\n\nexport const CONNECTION_PICKER_OPTIONS = [\n${pickerOptions}\n] as const satisfies readonly ConnectionPickerOption[];\n`; +} + +function syncTarget(path, expected) { + const current = existsSync(path) ? readFileSync(path, "utf8") : ""; + if (current === expected) return; + if (checkOnly) throw new Error(`${path.slice(root.length + 1)} is out of date; run pnpm generate:connection-types`); + mkdirSync(dirname(path), { recursive: true }); + writeFileSync(path, expected); +} + +try { + const descriptors = loadDescriptors(); + const profiles = loadConnectionProfiles(descriptors); + syncTarget(jsonTarget, jsonOutput(descriptors)); + syncTarget(typeTarget, typeOutput(descriptors)); + syncTarget(profileTarget, profileTypeOutput(profiles)); + console.log(`${checkOnly ? "Validated" : "Generated"} ${descriptors.length} connection type descriptors and ${profiles.length} connection profiles.`); +} catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); +}