feat: add dbtool tui live query workspace
Some checks failed
release-smoke / macos-13 / x86_64-apple-darwin (push) Has been cancelled
release-smoke / ubuntu-latest / x86_64-unknown-linux-gnu (push) Has been cancelled
release-smoke / windows-latest / x86_64-pc-windows-msvc (push) Has been cancelled

- add shared db-app layer for connect/inspect/query/export events
- add dbtool-tui workspace with sqlite-local live flow and QA docs
- include host-validated acceptance updates for CMP-36

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Paperclip CTO
2026-03-27 17:17:20 +00:00
parent 7424491944
commit 19aeb7784b
12 changed files with 5006 additions and 4 deletions

240
TUI_BACKEND_CONTRACT.md Normal file
View File

@@ -0,0 +1,240 @@
# TUI Backend Contract
日期2026-03-27
作者Senior Backend Engineer
## 1. 当前后端边界
- `crates/db-core`:数据库无关的领域对象与基础校验。
- `crates/db-config`:连接 profile、密码环境变量注入与脱敏摘要。
- `crates/db-drivers`PostgreSQL / MySQL / SQLite 驱动实现与差异收敛。
- `crates/db-app``connect` / `inspect` / `query` / `export` 共享应用编排、结构化结果、统一错误对象,以及 TUI worker 可复用的执行状态。
- `apps/cli`参数解析、stdout/stderr 渲染、退出码。
## 2. 持久化边界
- 当前产品仍是单次命令执行模型,没有连接配置持久化、历史记录持久化或后台状态存储。
- 当前写路径只有:
- `export` 明确指定的输出文件
- SQLite 目标数据库本身(由用户选择)
- TUI 第二阶段 live integration 仍不引入新的数据库、本地缓存库或后台 daemon 存储契约。
## 3. 共享请求对象
TUI worker 应直接构造共享 Rust 对象,不要拼接 CLI flags更不要解析 CLI 文本。
### Connect
- 输入:`db_config::ConnectionProfile`
- 说明:
- `name` 用于当前会话内的目标标识
- `target` 复用 `db_core::ConnectionTarget`
- `password_env_var` 只作为脱敏标签保留secret 仍通过环境变量注入,不进入持久化
### Inspect
- 输入:`db_core::InspectRequest`
- 字段:
- `schema: Option<String>`
- `table: Option<String>`
- 约束:
- `table.is_some()` 时必须同时提供 `schema`
### Query
- 输入:`db_core::QueryRequest`
- 字段:
- `sql`
- `source`
- `parameters`
- `source` 语义:
- `QuerySource::Inline`
- `QuerySource::File`
### Export
- 输入:
- `db_core::QueryRequest`
- `db_core::ExportRequest`
- `ExportRequest` 字段:
- `format`
- `output_path`
- `overwrite`
- 约束:
- 只允许导出返回结果集的查询
- 不静默覆盖已有文件
- 不为 TUI 增加新的导出元数据存储
## 4. 共享结构化结果
TUI 应优先直接调用 `crates/db-app`,不要解析 CLI 的人类可读文本。
### Connect
- 返回 `ConnectResponse`
- 字段:
- `target.profile_name`
- `target.driver`
- `target.endpoint`
- `target.password_env_var`
- `status`
- 当前 `status` 固定为 `connected`
### Inspect
- 返回 `InspectResponse`
- 字段:
- `target`
- `scope.schema`
- `scope.table`
- `payload`
- `payload.kind` 为:
- `schemas`
- `tables`
- `columns`
- `payload.items` 允许为空;空数组不是错误
### Query
- 返回 `QueryResponse`
- 字段:
- `target`
- `source.kind``inline` / `file`
- `source.label`
- `source.path`
- `result.columns`
- `result.rows`
- `result.rows_affected`
- `result.row_count`
- `rows_affected != null` 表示 command-style 执行成功但没有结果集
### Export
- 返回 `ExportResponse`
- 字段:
- `target`
- `source`
- `export.format`
- `export.output_path`
- `export.overwrite`
- `row_count`
## 5. 错误模型
`db-app::AppError.kind` 当前分为:
- `validation`
- `connection`
- `authentication`
- `inspect`
- `query`
- `export`
这组分类是 TUI banner、QA 断言和未来 GUI 状态映射的当前稳定基础。
`AppError.target` 为可选字段:
- 有目标上下文时返回脱敏后的 `ConnectionSummary`
- 参数校验在目标尚未构成时可为 `null`
## 6. Worker / Channel 状态契约
`crates/db-app` 现提供:
- `AppOperation``connect | inspect | query | export`
- `OperationState``running | success | empty | error`
- `AppEvent<T>`worker / channel 推荐 envelope
推荐发送顺序:
1. 先发 `AppEvent::running(operation)`
2. 成功后发送 `response.into_event()`
3. 失败时发送 `error.into_event()`
状态语义固定如下:
- `connect`
- `running`:正在测试连接
- `success`:连接成功
- `error`:连接失败
- `inspect`
- `success`:返回非空 schema / table / column 集合
- `empty`:返回空集合,但请求本身成功
- `error`inspect 失败
- `query`
- `success`:返回至少一行,或 `rows_affected` 非空
- `empty`:返回零行且 `rows_affected == null`
- `error`:执行失败
- `export`
- `success`:文件写入成功;`row_count == 0` 仍算成功
- `error`:导出校验、查询或文件写入失败
示例:
```rust
use db_app::{AppEvent, AppOperation};
sender.send(AppEvent::<()>::running(AppOperation::Query))?;
match db_app::query(&profile, &request) {
Ok(response) => sender.send(response.into_event())?,
Err(error) => sender.send(error.into_event())?,
}
```
## 7. CLI 结构化输出
CLI 继续保留默认文本输出,同时新增:
- `--result-format text`
- `--result-format json`
JSON 返回 envelope
```json
{
"status": "success",
"operation": "query",
"data": {}
}
```
错误返回 envelope
```json
{
"status": "error",
"operation": "query",
"error": {
"operation": "query",
"kind": "query",
"message": "..."
}
}
```
CLI JSON envelope 继续作为跨入口回归样本,但 TUI live path 不应以调用 CLI 二进制作为主集成方式。
## 8. Frontend 接入约束
- TUI 直接依赖 `crates/db-app``db-core`,不解析 CLI stdout/stderr
- UI 状态映射应优先使用 `OperationState`,不要自行发明另一套 success/empty/error 语义
- `ConnectionSummary.endpoint``password_env_var` 仅用于展示脱敏上下文,不应用作 secret 来源
- `AppError.kind` 必须原样进入状态区 / inspector避免把 `validation``connection``query` 混成统一“失败”
- 若未来引入异步 worker 池,仍以共享 response/error 对象作为唯一 UI 数据源
## 9. 当前回归边界
- `crates/db-app` 回归需覆盖:
- response -> `OperationState` 映射
- `AppEvent<T>` / `AppError` 序列化
- 空 inspect / 空 query / command query 语义
- `apps/cli` 回归继续覆盖:
- `--result-format json` envelope
- text/json 输出在相同 `db-app` 结果上的一致性
## 10. 演进规则
- CLI 文本文案可小幅演进,但 `db-app` 结构化对象字段应保持兼容。
- 新增数据库驱动时,优先扩展 `db-drivers``db-app`,不要在 TUI/CLI 内复制数据库语义。
- 若未来引入本地持久化(例如连接历史),应先新增独立文档定义存储边界,再进入实现。