Files
dbtool-cli-v1/TUI_BACKEND_CONTRACT.md
Paperclip CTO a28dab4cd9
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
feat(usable): package gui-host validation snapshot
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-03-31 10:21:36 +00:00

6.5 KiB
Raw Permalink Blame History

TUI Backend Contract

日期2026-03-27
作者Senior Backend Engineer

1. 当前后端边界

  • crates/db-core:数据库无关的领域对象与基础校验。
  • crates/db-config:连接 profile、密码环境变量注入与脱敏摘要。
  • crates/db-driversPostgreSQL / MySQL / SQLite 驱动实现与差异收敛。
  • crates/db-appconnect / 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.kindinline / 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 现提供:

  • AppOperationconnect | inspect | query | export
  • OperationStaterunning | 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:返回空集合,但请求本身成功
    • errorinspect 失败
  • query
    • success:返回至少一行,或 rows_affected 非空
    • empty:返回零行且 rows_affected == null
    • error:执行失败
  • export
    • success:文件写入成功;row_count == 0 仍算成功
    • error:导出校验、查询或文件写入失败

示例:

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

{
  "status": "success",
  "operation": "query",
  "state": "success",
  "data": {}
}
  • status 继续只区分 envelope 级成功/失败
  • state 对齐共享应用层状态:
    • connectsuccess
    • inspectsuccess | empty
    • querysuccess | empty
    • exportsuccess

错误返回 envelope

{
  "status": "error",
  "operation": "query",
  "state": "error",
  "error": {
    "operation": "query",
    "kind": "query",
    "message": "..."
  }
}

CLI JSON envelope 继续作为跨入口回归样本,但 TUI live path 不应以调用 CLI 二进制作为主集成方式。

8. Frontend 接入约束

  • TUI 直接依赖 crates/db-appdb-core,不解析 CLI stdout/stderr
  • UI 状态映射应优先使用 OperationState,不要自行发明另一套 success/empty/error 语义
  • ConnectionSummary.endpointpassword_env_var 仅用于展示脱敏上下文,不应用作 secret 来源
  • AppError.kind 必须原样进入状态区 / inspector避免把 validationconnectionquery 混成统一“失败”
  • 若未来引入异步 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-driversdb-app,不要在 TUI/CLI 内复制数据库语义。
  • 若未来引入本地持久化(例如连接历史),应先新增独立文档定义存储边界,再进入实现。