本文档记录新增一个数据库驱动类型时需要修改的全部文件,包含精确路径、行号和改法。
适用范围:本手册主体适用于 SQL/表模型数据库。Redis、Elasticsearch、MongoDB 等非 SQL 数据源不要实现
DatabaseDriver,应走src-tauri/src/datasources/下的数据源能力模型,并新增独立 command/UI。
{driver}— 小写 driver ID,与前端DRIVER_IDS保持一致(例:oracle){DriverName}— PascalCase(例:Oracle)network型 — 通过 host:port 连接(postgres、mysql、mssql、clickhouse 等)file型 — 通过本地文件路径连接(sqlite、duckdb)datasource型 — 非 SQL 数据源(redis、elasticsearch、mongodb),按 key/document/search 能力接入
- 后端不要把非 SQL 数据源伪装成
DatabaseDriver,避免实现伪list_tables/get_table_data/execute_query。 - 在
src-tauri/src/datasources/{driver}.rs中定义该数据源的原生模型,例如 Redis 的 database/key/value,MongoDB 的 database/collection/document,Elasticsearch 的 index/document/search。 - 在
src-tauri/src/commands/{driver}.rs中暴露专用 Tauri commands,并在src-tauri/src/lib.rs注册。 - 前端在
src/lib/driver-registry.tsx中设置kind,例如kv、document、search,Sidebar 和主视图按kind分流。 - SQL 的
SqlEditor、TableView、import/export 和sql_execution_logs默认不复用于非 SQL 数据源,除非该数据源明确提供 SQL 兼容接口。
Redis 参考实现:
- 后端:
src-tauri/src/datasources/redis.rs、src-tauri/src/commands/redis.rs - 前端:
src/components/business/Redis/RedisKeyView.tsx - API:
src/services/api.ts的api.redis.*
文件: src-tauri/src/db/drivers/{driver}.rs(新建)
参考模板选择:
- PostgreSQL-like(独立 schema、SSl CA、sqlx)→ 复制
postgres.rs - MySQL-like(共享驱动、MySQL 协议)→ 复制
mysql.rs - HTTP API 型(ClickHouse-like)→ 复制
clickhouse.rs - 嵌入式/文件型(无网络连接)→ 复制
duckdb.rs
必须实现 DatabaseDriver trait 的全部方法(定义见 src-tauri/src/db/drivers/mod.rs:64-121):
test_connection, get_databases, get_table_names, get_table_structure,
get_table_info, get_table_data, execute_query, cancel_query,
get_schema_names, get_table_ddl, get_schema_overview, close
文件: src-tauri/src/db/drivers/mod.rs
在现有的 use self::... 行中加入:
use self::{driver}::{DriverName}Driver;在现有的 pub mod ... 行中加入:
pub mod {driver};在 _ => 分支前加入:
"{driver}" => {
let driver = {DriverName}Driver::connect(form).await?;
Ok(Box::new(driver) as Box<dyn DatabaseDriver>)
}注意(MySQL family): 如果是 MySQL 协议兼容的变体(如 PolarDB),可以复用 MysqlDriver,直接在第 139 行的现有 arm 里加 | "{driver}":
"mysql" | "tidb" | "mariadb" | "{driver}" => {文件: src-tauri/src/ssh.rs,第 48-54 行
在 _ => 5432 之前加入一行:
"{driver}" => {PORT},示例(当前内容):
let default_port: i64 = match config.driver.to_ascii_lowercase().as_str() {
"mysql" => 3306,
"mssql" => 1433,
"clickhouse" => 9000,
"sqlite" => 0,
// ← 在这里加新 driver
_ => 5432, // postgres and unknown drivers
};注意:
- file 型 driver 不走 SSH 隧道的端口逻辑,但若要防止 fallback 到 5432,可加
"sqlite" => 0,同款的占位。 - 端口 0 不会通过第 56-58 行的校验(
1..=65535),file 型 driver 传port=None即可,无需额外处理。 - 忘记加这一行不会 crash,但 SSH 连接会用 5432 作为默认端口,导致隧道目标端口错误。
文件: src-tauri/src/connection_input/mod.rs
第 69-71 行的 else if form.host.is_none() 已覆盖所有 network 型 driver。
在现有的 matches! 中加入新 driver:
if matches!(driver.as_str(), "sqlite" | "duckdb" | "{driver}") {如果新 driver 允许 host:port 写法(如 localhost:3307),在现有 matches! 中加入:
if matches!(driver.as_str(), "mysql" | "mariadb" | "tidb" | "{driver}") {文件: src-tauri/src/commands/transfer.rs,第 615-628 行(import_transaction_sql 函数)
根据 driver 支持的事务语法加入 match arm:
// BEGIN / COMMIT / ROLLBACK(与 postgres 相同)
"postgres" | "sqlite" | "duckdb" | "{driver}" => Ok(("BEGIN", "COMMIT", "ROLLBACK")),
// 或 START TRANSACTION(MySQL 系)
"mysql" | "mariadb" | "tidb" | "{driver}" => Ok(("START TRANSACTION", "COMMIT", "ROLLBACK")),
// 不支持 import
"{driver}" => Err("[UNSUPPORTED] Driver {driver} is read-only in this import flow".to_string()),文件: src-tauri/src/commands/connection.rs
两处需要改(create_database_by_id 约第 262 行,create_database_by_id_direct 约第 343 行):
6a. 从"不支持"排除列表移除(file 型专用黑名单,network 型无需改):
// 第 262、343 行:
if matches!(driver.as_str(), "sqlite" | "duckdb") { // 不要在此加 network 型 driver6b. 在 match 中加入建库 SQL(第 269-319、350-400 行):
"{driver}" => {
let sql = format!("CREATE DATABASE {}", quote_ident(&db_name));
super::execute_with_retry(&state, id, None, |driver| {
let sql_clone = sql.clone();
async move { driver.execute_query(sql_clone).await.map(|_| ()) }
})
.await
}文件: src/lib/driver-registry.tsx
在 as const 数组中加入新 driver ID:
const DRIVER_IDS = [
"postgres",
"mysql",
// ...
"{driver}", // ← 加在这里
] as const;在数组末尾(]; 之前)加入一条记录:
{
id: "{driver}",
label: "DisplayName",
defaultPort: 1234, // file 型填 null
isFileBased: false, // file 型填 true
isMysqlFamily: false, // MySQL 协议兼容时填 true
supportsSSLCA: false, // 支持 SSL CA 证书验证时填 true(需后端也支持)
supportsSchemaBrowsing: false, // 支持 schema 列表时填 true
supportsCreateDatabase: true, // 支持 CREATE DATABASE 时填 true
importCapability: "supported", // "supported" | "read_only_not_supported" | "unsupported"
icon: () => renderSimpleIcon(si{DriverName}), // 或 <Database className="w-4 h-4" />
},图标规则:
- 优先从
simple-icons导入:import { si{DriverName} } from "simple-icons"; - 无 simple-icons 时用
<Server className="w-4 h-4" />(通用服务器图标)或<Database className="w-4 h-4" />
这一个文件改完,以下前端逻辑自动生效(无需再改):
src/services/api.ts—Driver类型src/lib/connection-form/rules.ts— MySQL family / file-based 数组src/components/business/Sidebar/connection-list/helpers.tsx— 图标映射src/components/business/Sidebar/ConnectionList.tsx— SelectItem、默认 port、SSL/file 条件渲染
文件: src/lib/i18n/locales/en.ts、zh.ts
file 型 driver 需要在两个 locale 文件里加"文件路径"标签和占位符。
在 en.ts 中搜索 duckdbFilePath(约第 221 行)附近加入:
{driver}FilePath: "{DriverName} File Path",
{driver}Path: "/path/to/db.{driver}",zh.ts 同理加入对应翻译。
文件: src-tauri/Cargo.toml
按驱动依赖类型选择:
| 类型 | 做法 |
|---|---|
| 使用 sqlx(postgres/mysql 系) | 在 sqlx features 列表加 driver 名(第 34 行) |
| 独立 crate(如 DuckDB) | 加一行 {driver} = { version = "x.y", features = [...] } |
| HTTP 协议(如 ClickHouse) | 加 HTTP client 依赖(参考 clickhouse.rs 的 import) |
| 微软协议(MSSQL) | 使用 tiberius(已有,无需重复加) |
新建 3 个文件(参考同类 driver 复制修改):
src-tauri/tests/common/{driver}_context.rs ← testcontainers 容器配置
src-tauri/tests/{driver}_integration.rs ← DatabaseDriver trait 方法直接测试
src-tauri/tests/{driver}_command_integration.rs ← Tauri command 层测试
在 src-tauri/tests/common/mod.rs 中加入模块声明:
pub mod {driver}_context;更新 scripts/test-integration.sh 加入新 driver(搜索其他 driver 名的赋值行)。
可选: 如果 driver 支持多语句事务,创建:
src-tauri/tests/{driver}_stateful_command_integration.rs
参考 postgres_stateful_command_integration.rs。
每次新增 driver 后执行:
# 必须全部通过
bun run typecheck
bun run lint
cargo check --manifest-path src-tauri/Cargo.toml
# 有条件时执行
bun run test:unit
IT_DB={driver} bun run test:integration # 需要 Docker快速一键验证:
bun run test:smoke # typecheck + lint + unit tests| 陷阱 | 后果 | 解法 |
|---|---|---|
忘记改 ssh.rs 默认端口 |
SSH 隧道目标端口错误(fallback 到 5432) | Step 3 |
file 型 driver 未加入 connection_input 的 matches! |
校验报"host cannot be empty"而不是"file path" | Step 4b |
前端 DRIVER_IDS 加了但 DRIVER_REGISTRY 没加 |
TypeScript 编译报错,图标/port 逻辑异常 | Step 7 |
| 图标使用了不存在的 simple-icons 导出名 | 前端运行时崩溃 | 验证 si{DriverName} 是否存在于 simple-icons 包 |
忘记改 import_transaction_sql |
import 功能对新 driver 返回"不支持"或使用错误事务语法 | Step 5 |
MySQL family 新 driver 未加入 connection_input 的 mysql arm |
host:port 嵌入写法不被解析 |
Step 4c |
| i18n 只改了 en.ts | 中文/日文界面显示 key 字符串而非翻译文本 | Step 8 三个文件都要改 |
| 文件 | 类型 | 条件 |
|---|---|---|
src-tauri/src/db/drivers/{driver}.rs |
新建 | 必须 |
src-tauri/src/db/drivers/mod.rs |
改 | 必须(3处) |
src-tauri/src/ssh.rs |
改 | network 型 |
src-tauri/src/connection_input/mod.rs |
改 | file 型或 MySQL family |
src-tauri/src/commands/transfer.rs |
改 | 支持 import 时 |
src-tauri/src/commands/connection.rs |
改 | 支持 create database 时 |
src-tauri/Cargo.toml |
改 | 必须 |
src/lib/driver-registry.tsx |
改 | 必须(前端唯一入口) |
src/lib/i18n/locales/en.ts |
改 | file 型 |
src/lib/i18n/locales/zh.ts |
改 | file 型 |
src-tauri/tests/common/{driver}_context.rs |
新建 | 集成测试 |
src-tauri/tests/{driver}_integration.rs |
新建 | 集成测试 |
src-tauri/tests/{driver}_command_integration.rs |
新建 | 集成测试 |
src-tauri/tests/common/mod.rs |
改 | 集成测试 |
scripts/test-integration.sh |
改 | 集成测试 |